diff --git a/google/data_source_google_sql_ca_certs.go b/google/data_source_google_sql_ca_certs.go new file mode 100644 index 00000000000..8bb7d9027a8 --- /dev/null +++ b/google/data_source_google_sql_ca_certs.go @@ -0,0 +1,87 @@ +package google + +import ( + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func dataSourceGoogleSQLCaCerts() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleSQLCaCertsRead, + + Schema: map[string]*schema.Schema{ + "instance": { + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "active_version": { + Type: schema.TypeString, + Computed: true, + }, + "certs": { + Type: schema.TypeList, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cert": { + Type: schema.TypeString, + Computed: true, + }, + "common_name": { + Type: schema.TypeString, + Computed: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "expiration_time": { + Type: schema.TypeString, + Computed: true, + }, + "sha1_fingerprint": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + Computed: true, + }, + }, + } +} + +func dataSourceGoogleSQLCaCertsRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + fv, err := parseProjectFieldValue("instances", d.Get("instance").(string), "project", d, config, false) + if err != nil { + return err + } + project := fv.Project + instance := fv.Name + + log.Printf("[DEBUG] Fetching CA certs from instance %s", instance) + + response, err := config.clientSqlAdmin.Instances.ListServerCas(project, instance).Do() + if err != nil { + return fmt.Errorf("error retrieving CA certs: %s", err) + } + + log.Printf("[DEBUG] Fetched CA certs from instance %s", instance) + + d.Set("project", project) + d.Set("certs", flattenServerCaCerts(response.Certs)) + d.Set("active_version", response.ActiveVersion) + d.SetId(fmt.Sprintf("projects/%s/instance/%s", project, instance)) + + return nil +} diff --git a/google/data_source_google_sql_ca_certs_test.go b/google/data_source_google_sql_ca_certs_test.go new file mode 100644 index 00000000000..f42a685074b --- /dev/null +++ b/google/data_source_google_sql_ca_certs_test.go @@ -0,0 +1,92 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccDataSourceGoogleSQLCaCerts_basic(t *testing.T) { + t.Parallel() + + instanceName := fmt.Sprintf("data-ssl-ca-cert-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleSQLCaCertsConfig(instanceName), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceGoogleSQLCaCertsCheck("data.google_sql_ca_certs.ca_certs", "google_sql_database_instance.foo"), + testAccDataSourceGoogleSQLCaCertsCheck("data.google_sql_ca_certs.ca_certs_self_link", "google_sql_database_instance.foo"), + resource.TestCheckResourceAttr("data.google_sql_ca_certs.ca_certs", "certs.#", "1"), + resource.TestCheckResourceAttr("data.google_sql_ca_certs.ca_certs_self_link", "certs.#", "1"), + ), + }, + }, + }) +} + +func testAccDataSourceGoogleSQLCaCertsCheck(datasourceName string, resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + ds, ok := s.RootModule().Resources[datasourceName] + if !ok { + return fmt.Errorf("root module has no resource called %s", datasourceName) + } + + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("can't find %s in state", resourceName) + } + + datasourceAttributes := ds.Primary.Attributes + resourceAttributes := rs.Primary.Attributes + + instanceToDatasourceAttrsMapping := map[string]string{ + "server_ca_cert.0.cert": "certs.0.cert", + "server_ca_cert.0.common_name": "certs.0.common_name", + "server_ca_cert.0.create_time": "certs.0.create_time", + "server_ca_cert.0.expiration_time": "certs.0.expiration_time", + "server_ca_cert.0.sha1_fingerprint": "certs.0.sha1_fingerprint", + } + + for resourceAttr, datasourceAttr := range instanceToDatasourceAttrsMapping { + if resourceAttributes[resourceAttr] != datasourceAttributes[datasourceAttr] { + return fmt.Errorf( + "%s is %s; want %s", + datasourceAttr, + datasourceAttributes[datasourceAttr], + resourceAttributes[resourceAttr], + ) + } + } + + return nil + } +} + +func testAccDataSourceGoogleSQLCaCertsConfig(instanceName string) string { + return fmt.Sprintf(` +resource "google_sql_database_instance" "foo" { + name = "%s" + region = "us-central1" + settings { + tier = "db-f1-micro" + crash_safe_replication = false + } +} + +data "google_sql_ca_certs" "ca_certs" { + instance = google_sql_database_instance.foo.name +} + +data "google_sql_ca_certs" "ca_certs_self_link" { + instance = google_sql_database_instance.foo.self_link +} +`, instanceName) +} diff --git a/google/provider.go b/google/provider.go index 39452669eab..2a2bb55fd96 100644 --- a/google/provider.go +++ b/google/provider.go @@ -453,6 +453,7 @@ func Provider() terraform.ResourceProvider { "google_service_account": dataSourceGoogleServiceAccount(), "google_service_account_access_token": dataSourceGoogleServiceAccountAccessToken(), "google_service_account_key": dataSourceGoogleServiceAccountKey(), + "google_sql_ca_certs": dataSourceGoogleSQLCaCerts(), "google_storage_bucket_object": dataSourceGoogleStorageBucketObject(), "google_storage_object_signed_url": dataSourceGoogleSignedUrl(), "google_storage_project_service_account": dataSourceGoogleStorageProjectServiceAccount(), diff --git a/google/resource_sql_database_instance.go b/google/resource_sql_database_instance.go index 63f47639511..d152b655528 100644 --- a/google/resource_sql_database_instance.go +++ b/google/resource_sql_database_instance.go @@ -829,7 +829,7 @@ func resourceSqlDatabaseInstanceRead(d *schema.ResourceData, meta interface{}) e d.Set("public_ip_address", publicIpAddress) d.Set("private_ip_address", privateIpAddress) - if err := d.Set("server_ca_cert", flattenServerCaCert(instance.ServerCaCert)); err != nil { + if err := d.Set("server_ca_cert", flattenServerCaCerts([]*sqladmin.SslCert{instance.ServerCaCert})); err != nil { log.Printf("[WARN] Failed to set SQL Database CA Certificate") } @@ -1094,22 +1094,24 @@ func flattenIpAddresses(ipAddresses []*sqladmin.IpMapping) []map[string]interfac return ips } -func flattenServerCaCert(caCert *sqladmin.SslCert) []map[string]interface{} { - var cert []map[string]interface{} +func flattenServerCaCerts(caCerts []*sqladmin.SslCert) []map[string]interface{} { + var certs []map[string]interface{} + + for _, caCert := range caCerts { + if caCert != nil { + data := map[string]interface{}{ + "cert": caCert.Cert, + "common_name": caCert.CommonName, + "create_time": caCert.CreateTime, + "expiration_time": caCert.ExpirationTime, + "sha1_fingerprint": caCert.Sha1Fingerprint, + } - if caCert != nil { - data := map[string]interface{}{ - "cert": caCert.Cert, - "common_name": caCert.CommonName, - "create_time": caCert.CreateTime, - "expiration_time": caCert.ExpirationTime, - "sha1_fingerprint": caCert.Sha1Fingerprint, + certs = append(certs, data) } - - cert = append(cert, data) } - return cert + return certs } func instanceMutexKey(project, instance_name string) string { diff --git a/website/docs/d/datasource_google_sql_ca_certs.html.markdown b/website/docs/d/datasource_google_sql_ca_certs.html.markdown new file mode 100644 index 00000000000..762fdd4a0fb --- /dev/null +++ b/website/docs/d/datasource_google_sql_ca_certs.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "Cloud SQL" +layout: "google" +page_title: "Google: google_sql_ca_certs" +sidebar_current: "docs-google-datasource-sql-ca-certs" +description: |- + Get all of the trusted Certificate Authorities (CAs) for the specified SQL database instance. +--- + +# google\_sql\_ca\_certs + +Get all of the trusted Certificate Authorities (CAs) for the specified SQL database instance. For more information see the +[official documentation](https://cloud.google.com/sql/) +and +[API](https://cloud.google.com/sql/docs/mysql/admin-api/rest/v1beta4/instances/listServerCas). + + +## Example Usage + +```hcl +data "google_sql_ca_certs" "ca_certs" { + instance = "primary-database-server" +} + +locals { + furthest_expiration_time = reverse(sort([for k, v in data.google_sql_ca_certs.ca_certs.certs : v.expiration_time]))[0] + latest_ca_cert = [for v in data.google_sql_ca_certs.ca_certs.certs : v.cert if v.expiration_time == local.furthest_expiration_time] +} + +output "db_latest_ca_cert" { + description = "Latest CA cert used by the primary database server" + value = local.latest_ca_cert + sensitive = true +} +``` + +## Argument Reference + +The following arguments are supported: + +* `instance` - (Required) The name or self link of the instance. + +--- + +* `project` - (Optional) The ID of the project in which the resource belongs. If `project` is not provided, the provider project is used. + +## Attributes Reference + +The following attributes are exported: + +* `active_version` - SHA1 fingerprint of the currently active CA certificate. + +* `certs` - A list of server CA certificates for the instance. Each contains: + * `cert` - The CA certificate used to connect to the SQL instance via SSL. + * `common_name` - The CN valid for the CA cert. + * `create_time` - Creation time of the CA cert. + * `expiration_time` - Expiration time of the CA cert. + * `sha1_fingerprint` - SHA1 fingerprint of the CA cert.