Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terraform Data Source to retrieve SQL instance CA certs #5306

Merged
merged 1 commit into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions google/data_source_google_sql_ca_certs.go
Original file line number Diff line number Diff line change
@@ -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
}
92 changes: 92 additions & 0 deletions google/data_source_google_sql_ca_certs_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
1 change: 1 addition & 0 deletions google/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
28 changes: 15 additions & 13 deletions google/resource_sql_database_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}

Expand Down Expand Up @@ -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 {
Expand Down
58 changes: 58 additions & 0 deletions website/docs/d/datasource_google_sql_ca_certs.html.markdown
Original file line number Diff line number Diff line change
@@ -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.