Skip to content

Commit

Permalink
feat(redis): add certificate (#1402)
Browse files Browse the repository at this point in the history
  • Loading branch information
Codelax committed Aug 1, 2022
1 parent f6b5e81 commit 31a8477
Show file tree
Hide file tree
Showing 11 changed files with 4,230 additions and 2,185 deletions.
1 change: 1 addition & 0 deletions docs/resources/redis_cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ In addition to all arguments above, the following attributes are exported:
- `id` - The ID of the Database Instance.
- `created_at` - The date and time of creation of the Redis Cluster.
- `updated_at` - The date and time of the last update of the Redis Cluster.
- `certificate` - The PEM of the certificate used by redis, only when `tls_enabled` is true


## Import
Expand Down
26 changes: 26 additions & 0 deletions scaleway/resource_redis_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package scaleway

import (
"context"
"fmt"
"io/ioutil"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
Expand Down Expand Up @@ -166,6 +168,11 @@ func resourceScalewayRedisCluster() *schema.Resource {
},
},
},
"certificate": {
Type: schema.TypeString,
Computed: true,
Description: "public TLS certificate used by redis cluster, empty if tls is disabled",
},
"created_at": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -291,6 +298,25 @@ func resourceScalewayRedisClusterRead(ctx context.Context, d *schema.ResourceDat
}
_ = d.Set("public_network", flattenRedisPublicNetwork(cluster.Endpoints))

if cluster.TLSEnabled {
certificate, err := redisAPI.GetClusterCertificate(&redis.GetClusterCertificateRequest{
Zone: zone,
ClusterID: cluster.ID,
})
if err != nil {
return diag.FromErr(fmt.Errorf("failed to fetch cluster certificate: %w", err))
}

certificateContent, err := ioutil.ReadAll(certificate.Content)
if err != nil {
return diag.FromErr(fmt.Errorf("failed to read cluster certificate: %w", err))
}

_ = d.Set("certificate", string(certificateContent))
} else {
_ = d.Set("certificate", "")
}

return nil
}

Expand Down
101 changes: 101 additions & 0 deletions scaleway/resource_redis_cluster_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package scaleway

import (
"crypto/x509"
"encoding/pem"
"fmt"
"testing"

Expand Down Expand Up @@ -552,6 +554,86 @@ func TestAccScalewayRedisCluster_Endpoints_ClusterMode(t *testing.T) {
})
}

func TestAccScalewayRedisCluster_Certificate(t *testing.T) {
tt := NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: tt.ProviderFactories,
CheckDestroy: testAccCheckScalewayRedisClusterDestroy(tt),
Steps: []resource.TestStep{
{
Config: `
resource "scaleway_redis_cluster" "main" {
name = "test_redis_certificate"
version = "6.2.6"
node_type = "RED1-XS"
user_name = "my_initial_user"
password = "thiZ_is_v&ry_s3cret"
tags = [ "test1" ]
cluster_size = 1
tls_enabled = "true"
zone = "fr-par-2"
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayRedisExists(tt, "scaleway_redis_cluster.main"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "name", "test_redis_certificate"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "version", "6.2.6"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "node_type", "RED1-XS"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "user_name", "my_initial_user"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "password", "thiZ_is_v&ry_s3cret"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "tags.0", "test1"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "cluster_size", "1"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "tls_enabled", "true"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "zone", "fr-par-2"),
testAccCheckScalewayRedisCertificateIsValid("scaleway_redis_cluster.main"),
),
},
},
})
}

func TestAccScalewayRedisCluster_NoCertificate(t *testing.T) {
tt := NewTestTools(t)
defer tt.Cleanup()
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: tt.ProviderFactories,
CheckDestroy: testAccCheckScalewayRedisClusterDestroy(tt),
Steps: []resource.TestStep{
{
Config: `
resource "scaleway_redis_cluster" "main" {
name = "test_redis_no_certificate"
version = "6.2.6"
node_type = "RED1-XS"
user_name = "my_initial_user"
password = "thiZ_is_v&ry_s3cret"
tags = [ "test1" ]
cluster_size = 1
tls_enabled = "false"
zone = "fr-par-2"
}
`,
Check: resource.ComposeTestCheckFunc(
testAccCheckScalewayRedisExists(tt, "scaleway_redis_cluster.main"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "name", "test_redis_no_certificate"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "version", "6.2.6"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "node_type", "RED1-XS"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "user_name", "my_initial_user"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "password", "thiZ_is_v&ry_s3cret"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "tags.0", "test1"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "cluster_size", "1"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "tls_enabled", "false"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "zone", "fr-par-2"),
resource.TestCheckResourceAttr("scaleway_redis_cluster.main", "certificate", ""),
),
},
},
})
}

func testAccCheckScalewayRedisClusterDestroy(tt *TestTools) resource.TestCheckFunc {
return func(state *terraform.State) error {
for _, rs := range state.RootModule().Resources {
Expand Down Expand Up @@ -664,3 +746,22 @@ func testAccCheckScalewayRedisPrivateNetworksIdsAreEither(name string, possibili
return nil
}
}

func testAccCheckScalewayRedisCertificateIsValid(name string) resource.TestCheckFunc {
return func(state *terraform.State) error {
rs, ok := state.RootModule().Resources[name]
if !ok {
return fmt.Errorf("resource not found: %s", name)
}
pemCert, hasCert := rs.Primary.Attributes["certificate"]
if !hasCert {
return fmt.Errorf("could not find certificate in schema")
}
cert, _ := pem.Decode([]byte(pemCert))
_, err := x509.ParseCertificate(cert.Bytes)
if err != nil {
return fmt.Errorf("failed to parse certificate: %w", err)
}
return nil
}
}

0 comments on commit 31a8477

Please sign in to comment.