Skip to content
Draft
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
19 changes: 19 additions & 0 deletions docs/actions/redis_cluster_renew_certificate_action.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
subcategory: "Redis"
page_title: "Scaleway: scaleway_redis_cluster_renew_certificate_action"
---

# scaleway_redis_cluster_renew_certificate_action (Action)

<!-- action schema generated by tfplugindocs -->
## Schema

### Required

- `cluster_id` (String) Redis cluster ID to renew certificate for. Can be a plain UUID or a zonal ID.

### Optional

- `wait` (Boolean) Wait for the certificate renewal to complete before returning.
- `zone` (String) Zone of the Redis cluster. If not set, the zone is derived from the cluster_id when possible or from the provider configuration.

166 changes: 166 additions & 0 deletions internal/services/redis/action_cluster_renew_certificate_action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package redis

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-framework/action"
"github.com/hashicorp/terraform-plugin-framework/action/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/scaleway/scaleway-sdk-go/api/redis/v1"
"github.com/scaleway/scaleway-sdk-go/scw"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
)

var (
_ action.Action = (*ClusterRenewCertificateAction)(nil)
_ action.ActionWithConfigure = (*ClusterRenewCertificateAction)(nil)
)

type ClusterRenewCertificateAction struct {
redisAPI *redis.API
}

func (a *ClusterRenewCertificateAction) Configure(ctx context.Context, req action.ConfigureRequest, resp *action.ConfigureResponse) {
if req.ProviderData == nil {
return
}

m, ok := req.ProviderData.(*meta.Meta)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Action Configure Type",
fmt.Sprintf("Expected *meta.Meta, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)

return
}

client := m.ScwClient()
a.redisAPI = redis.NewAPI(client)
}

func (a *ClusterRenewCertificateAction) Metadata(ctx context.Context, req action.MetadataRequest, resp *action.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_redis_cluster_renew_certificate_action"
}

type ClusterRenewCertificateActionModel struct {
ClusterID types.String `tfsdk:"cluster_id"`
Zone types.String `tfsdk:"zone"`
Wait types.Bool `tfsdk:"wait"`
}

func NewClusterRenewCertificateAction() action.Action {
return &ClusterRenewCertificateAction{}
}

func (a *ClusterRenewCertificateAction) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"cluster_id": schema.StringAttribute{
Required: true,
Description: "Redis cluster ID to renew certificate for. Can be a plain UUID or a zonal ID.",
},
"zone": schema.StringAttribute{
Optional: true,
Description: "Zone of the Redis cluster. If not set, the zone is derived from the cluster_id when possible or from the provider configuration.",
},
"wait": schema.BoolAttribute{
Optional: true,
Description: "Wait for the certificate renewal to complete before returning.",
},
},
}
}

func (a *ClusterRenewCertificateAction) Invoke(ctx context.Context, req action.InvokeRequest, resp *action.InvokeResponse) {
var data ClusterRenewCertificateActionModel

resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

if resp.Diagnostics.HasError() {
return
}

if a.redisAPI == nil {
resp.Diagnostics.AddError(
"Unconfigured redisAPI",
"The action was not properly configured. The Scaleway client is missing. "+
"This is usually a bug in the provider. Please report it to the maintainers.",
)

return
}

if data.ClusterID.IsNull() || data.ClusterID.ValueString() == "" {
resp.Diagnostics.AddError(
"Missing cluster_id",
"The cluster_id attribute is required to renew the Redis cluster certificate.",
)

return
}

clusterID := locality.ExpandID(data.ClusterID.ValueString())

var (
zone scw.Zone
err error
)

if !data.Zone.IsNull() && data.Zone.ValueString() != "" {
zone = scw.Zone(data.Zone.ValueString())
} else {
// Try to derive zone from the cluster_id if it is a zonal ID.
if derivedZone, id, parseErr := zonal.ParseID(data.ClusterID.ValueString()); parseErr == nil {
zone = derivedZone
clusterID = id
}
}

renewReq := &redis.RenewClusterCertificateRequest{
ClusterID: clusterID,
}

if zone != "" {
renewReq.Zone = zone
}

cluster, err := a.redisAPI.RenewClusterCertificate(renewReq, scw.WithContext(ctx))
if err != nil {
resp.Diagnostics.AddError(
"Error executing Redis RenewClusterCertificate action",
fmt.Sprintf("Failed to renew certificate for cluster %s: %s", clusterID, err),
)

return
}

if data.Wait.ValueBool() {
waitZone := cluster.Zone
if waitZone == "" && zone != "" {
waitZone = zone
}

if waitZone == "" {
resp.Diagnostics.AddError(
"Missing zone for wait operation",
"Could not determine zone to wait for Redis cluster certificate renewal completion.",
)

return
}

_, err = waitForCluster(ctx, a.redisAPI, waitZone, clusterID, defaultRedisClusterTimeout)
if err != nil {
resp.Diagnostics.AddError(
"Error waiting for Redis cluster certificate renewal completion",
fmt.Sprintf("Certificate renewal for cluster %s did not complete: %s", clusterID, err),
)

return
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package redis_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
)

func TestAccActionRedisClusterRenewCertificate_Basic(t *testing.T) {
if acctest.IsRunningOpenTofu() {
t.Skip("Skipping TestAccActionRedisClusterRenewCertificate_Basic because actions are not yet supported on OpenTofu")
}

// Note: This test will fail with 501 Not Implemented until Scaleway implements
// the RenewClusterCertificate API endpoint. The SDK method exists but the API
// endpoint is not yet available on the server side.
tt := acctest.NewTestTools(t)
defer tt.Cleanup()

latestRedisVersion := getLatestVersion(tt)
resource.ParallelTest(t, resource.TestCase{
ProtoV6ProviderFactories: tt.ProviderFactories,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "scaleway_redis_cluster" "main" {
name = "test-redis-action-renew-certificate"
version = "%s"
node_type = "RED1-XS"
user_name = "my_initial_user"
password = "thiZ_is_v&ry_s3cret"
cluster_size = 1
tls_enabled = "true"
zone = "fr-par-2"

lifecycle {
action_trigger {
events = [after_create]
actions = [action.scaleway_redis_cluster_renew_certificate_action.main]
}
}
}

action "scaleway_redis_cluster_renew_certificate_action" "main" {
config {
cluster_id = scaleway_redis_cluster.main.id
wait = true
}
}
`, latestRedisVersion),
},
},
})
}
2 changes: 2 additions & 0 deletions provider/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/instance"
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/redis"
)

var (
Expand Down Expand Up @@ -138,6 +139,7 @@ func (p *ScalewayProvider) Actions(_ context.Context) []func() action.Action {
var res []func() action.Action

res = append(res, instance.NewServerAction)
res = append(res, redis.NewClusterRenewCertificateAction)

return res
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{{- /*gotype: github.com/hashicorp/terraform-plugin-docs/internal/provider.ActionTemplateType */ -}}
---
subcategory: "Redis"
page_title: "Scaleway: scaleway_redis_cluster_renew_certificate_action"
---

# scaleway_redis_cluster_renew_certificate_action (Action)

{{ .SchemaMarkdown }}

Loading