From f0d041e5e46066a762f80a8ce4efb3a2db8c4a30 Mon Sep 17 00:00:00 2001 From: Okumura Takahiro Date: Sat, 29 Jun 2024 19:51:08 +0900 Subject: [PATCH] Implement mysql_databases data source (#160) --- mysql/data_source_databases.go | 70 ++++++++++++++++++++++++ mysql/data_source_databases_test.go | 76 ++++++++++++++++++++++++++ mysql/provider.go | 3 +- website/docs/d/databases.html.markdown | 32 +++++++++++ website/mysql.erb | 4 ++ 5 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 mysql/data_source_databases.go create mode 100644 mysql/data_source_databases_test.go create mode 100644 website/docs/d/databases.html.markdown diff --git a/mysql/data_source_databases.go b/mysql/data_source_databases.go new file mode 100644 index 000000000..887020b9d --- /dev/null +++ b/mysql/data_source_databases.go @@ -0,0 +1,70 @@ +package mysql + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceDatabases() *schema.Resource { + return &schema.Resource{ + ReadContext: ShowDatabases, + Schema: map[string]*schema.Schema{ + "pattern": { + Type: schema.TypeString, + Optional: true, + }, + "databases": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } +} + +func ShowDatabases(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + db, err := getDatabaseFromMeta(ctx, meta) + if err != nil { + return diag.FromErr(err) + } + + pattern := d.Get("pattern").(string) + + sql := fmt.Sprint("SHOW DATABASES") + + if pattern != "" { + sql += fmt.Sprintf(" LIKE '%s'", pattern) + } + + log.Printf("[DEBUG] SQL: %s", sql) + + rows, err := db.QueryContext(ctx, sql) + if err != nil { + return diag.Errorf("failed querying for databases: %v", err) + } + defer rows.Close() + + var databases []string + for rows.Next() { + var database string + + if err := rows.Scan(&database); err != nil { + return diag.Errorf("failed scanning MySQL rows: %v", err) + } + + databases = append(databases, database) + } + + if err := d.Set("databases", databases); err != nil { + return diag.Errorf("failed setting databases field: %v", err) + } + + d.SetId(id.UniqueId()) + + return nil +} diff --git a/mysql/data_source_databases_test.go b/mysql/data_source_databases_test.go new file mode 100644 index 000000000..64c66e24a --- /dev/null +++ b/mysql/data_source_databases_test.go @@ -0,0 +1,76 @@ +package mysql + +import ( + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceDatabases(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDatabasesConfigBasic("%"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.mysql_databases.test", "pattern", "%"), + testAccDatabasesCount("data.mysql_databases.test", "databases.#", func(rn string, databaseCount int) error { + if databaseCount < 1 { + return fmt.Errorf("%s: databases not found", rn) + } + + return nil + }), + ), + }, + { + Config: testAccDatabasesConfigBasic("__database_does_not_exist__"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.mysql_databases.test", "pattern", "__database_does_not_exist__"), + testAccDatabasesCount("data.mysql_databases.test", "databases.#", func(rn string, databaseCount int) error { + if databaseCount > 0 { + return fmt.Errorf("%s: unexpected database found", rn) + } + + return nil + }), + ), + }, + }, + }) +} + +func testAccDatabasesCount(rn string, key string, check func(string, int) error) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[rn] + + if !ok { + return fmt.Errorf("resource not found: %s", rn) + } + + value, ok := rs.Primary.Attributes[key] + + if !ok { + return fmt.Errorf("%s: attribute '%s' not found", rn, key) + } + + databaseCount, err := strconv.Atoi(value) + + if err != nil { + return err + } + + return check(rn, databaseCount) + } +} + +func testAccDatabasesConfigBasic(pattern string) string { + return fmt.Sprintf(` +data "mysql_databases" "test" { + pattern = "%s" +}`, pattern) +} diff --git a/mysql/provider.go b/mysql/provider.go index b7ce4d023..2f845d314 100644 --- a/mysql/provider.go +++ b/mysql/provider.go @@ -241,7 +241,8 @@ func Provider() *schema.Provider { }, DataSourcesMap: map[string]*schema.Resource{ - "mysql_tables": dataSourceTables(), + "mysql_databases": dataSourceDatabases(), + "mysql_tables": dataSourceTables(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/website/docs/d/databases.html.markdown b/website/docs/d/databases.html.markdown new file mode 100644 index 000000000..185eb56a1 --- /dev/null +++ b/website/docs/d/databases.html.markdown @@ -0,0 +1,32 @@ +--- +layout: "mysql" +page_title: "MySQL: mysql_databases" +sidebar_current: "docs-mysql-datasource-databases" +description: |- + Gets databases on a MySQL server. +--- + +# Data Source: mysql\_databases + +The ``mysql_databases`` gets databases on a MySQL +server. + +## Example Usage + +```hcl +data "mysql_databases" "app" { + pattern = "test_%" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `pattern` - (Optional) Patterns for searching databases. + +## Attributes Reference + +The following attributes are exported: + +* `databases` - The list of the database names. diff --git a/website/mysql.erb b/website/mysql.erb index 25d40d81f..6dbbf7f5b 100644 --- a/website/mysql.erb +++ b/website/mysql.erb @@ -40,6 +40,10 @@ Data Sources