Move SKE Enable/Disable to the Service Enablement API (#467)

This commit is contained in:
Diogo Ferrão 2024-07-16 13:42:01 +01:00 committed by GitHub
parent e3da2ebbb4
commit 02c4ad72b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 72 additions and 42 deletions

1
go.mod
View file

@ -28,6 +28,7 @@ require (
github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.9.0 github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.9.0
github.com/stackitcloud/stackit-sdk-go/services/secretsmanager v0.8.0 github.com/stackitcloud/stackit-sdk-go/services/secretsmanager v0.8.0
github.com/stackitcloud/stackit-sdk-go/services/serverbackup v0.1.0 github.com/stackitcloud/stackit-sdk-go/services/serverbackup v0.1.0
github.com/stackitcloud/stackit-sdk-go/services/serviceenablement v0.2.0
github.com/stackitcloud/stackit-sdk-go/services/ske v0.17.0 github.com/stackitcloud/stackit-sdk-go/services/ske v0.17.0
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v0.2.0 github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v0.2.0
github.com/teambition/rrule-go v1.8.2 github.com/teambition/rrule-go v1.8.2

2
go.sum
View file

@ -178,6 +178,8 @@ github.com/stackitcloud/stackit-sdk-go/services/secretsmanager v0.8.0 h1:pJBG455
github.com/stackitcloud/stackit-sdk-go/services/secretsmanager v0.8.0/go.mod h1:LX0Mcyr7/QP77zf7e05fHCJO38RMuTxr7nEDUDZ3oPQ= github.com/stackitcloud/stackit-sdk-go/services/secretsmanager v0.8.0/go.mod h1:LX0Mcyr7/QP77zf7e05fHCJO38RMuTxr7nEDUDZ3oPQ=
github.com/stackitcloud/stackit-sdk-go/services/serverbackup v0.1.0 h1:fYCBNvh4tqE+DXYDfbJEjC3n/I78zTZajdcPTPB/yig= github.com/stackitcloud/stackit-sdk-go/services/serverbackup v0.1.0 h1:fYCBNvh4tqE+DXYDfbJEjC3n/I78zTZajdcPTPB/yig=
github.com/stackitcloud/stackit-sdk-go/services/serverbackup v0.1.0/go.mod h1:ZYI3wj/NnhhWi25ugbdcniwnY/7mF6zN582c5HPe00o= github.com/stackitcloud/stackit-sdk-go/services/serverbackup v0.1.0/go.mod h1:ZYI3wj/NnhhWi25ugbdcniwnY/7mF6zN582c5HPe00o=
github.com/stackitcloud/stackit-sdk-go/services/serviceenablement v0.2.0 h1:HAEFciLgeCY+kIcGcb+/zFUF3zt3z326v6JCen6fSjs=
github.com/stackitcloud/stackit-sdk-go/services/serviceenablement v0.2.0/go.mod h1:z6XdA+ndaWzcPW/P0QrUIcTXJzKlajxgGZ5+EwXNS+c=
github.com/stackitcloud/stackit-sdk-go/services/ske v0.17.0 h1:4S3MwNmpMfjzBz9JtKbXvkos7j+7hGeFMf7XsjMLL/g= github.com/stackitcloud/stackit-sdk-go/services/ske v0.17.0 h1:4S3MwNmpMfjzBz9JtKbXvkos7j+7hGeFMf7XsjMLL/g=
github.com/stackitcloud/stackit-sdk-go/services/ske v0.17.0/go.mod h1:0fFs4R7kg+gU7FNAIzzFvlCZJz6gyZ8CFhbK3eSrAwQ= github.com/stackitcloud/stackit-sdk-go/services/ske v0.17.0/go.mod h1:0fFs4R7kg+gU7FNAIzzFvlCZJz6gyZ8CFhbK3eSrAwQ=
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v0.2.0 h1:aIXxXx6u4+6C02MPb+hdItigeKeen7m+hEEG+Ej9sNs= github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v0.2.0 h1:aIXxXx6u4+6C02MPb+hdItigeKeen7m+hEEG+Ej9sNs=

View file

@ -14,28 +14,29 @@ import (
const Separator = "," const Separator = ","
type ProviderData struct { type ProviderData struct {
RoundTripper http.RoundTripper RoundTripper http.RoundTripper
ServiceAccountEmail string ServiceAccountEmail string
Region string Region string
ArgusCustomEndpoint string ArgusCustomEndpoint string
DnsCustomEndpoint string DnsCustomEndpoint string
IaaSCustomEndpoint string IaaSCustomEndpoint string
LoadBalancerCustomEndpoint string LoadBalancerCustomEndpoint string
LogMeCustomEndpoint string LogMeCustomEndpoint string
MariaDBCustomEndpoint string MariaDBCustomEndpoint string
MongoDBFlexCustomEndpoint string MongoDBFlexCustomEndpoint string
ObjectStorageCustomEndpoint string ObjectStorageCustomEndpoint string
OpenSearchCustomEndpoint string OpenSearchCustomEndpoint string
PostgresFlexCustomEndpoint string PostgresFlexCustomEndpoint string
PostgreSQLCustomEndpoint string PostgreSQLCustomEndpoint string
RabbitMQCustomEndpoint string RabbitMQCustomEndpoint string
RedisCustomEndpoint string RedisCustomEndpoint string
ResourceManagerCustomEndpoint string ResourceManagerCustomEndpoint string
SecretsManagerCustomEndpoint string SecretsManagerCustomEndpoint string
SQLServerFlexCustomEndpoint string SQLServerFlexCustomEndpoint string
ServerBackupCustomEndpoint string ServerBackupCustomEndpoint string
SKECustomEndpoint string SKECustomEndpoint string
EnableBetaResources bool ServiceEnablementCustomEndpoint string
EnableBetaResources bool
} }
// DiagsToError Converts TF diagnostics' errors into an error with a human-readable description. // DiagsToError Converts TF diagnostics' errors into an error with a human-readable description.

View file

@ -29,11 +29,13 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/core/utils" sdkUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/serviceenablement"
"github.com/stackitcloud/stackit-sdk-go/services/ske" "github.com/stackitcloud/stackit-sdk-go/services/ske"
"github.com/stackitcloud/stackit-sdk-go/services/ske/wait" "github.com/stackitcloud/stackit-sdk-go/services/ske/wait"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
) )
@ -214,7 +216,8 @@ func NewClusterResource() resource.Resource {
// clusterResource is the resource implementation. // clusterResource is the resource implementation.
type clusterResource struct { type clusterResource struct {
client *ske.APIClient skeClient *ske.APIClient
enablementClient *serviceenablement.APIClient
} }
// Metadata returns the resource type name. // Metadata returns the resource type name.
@ -235,27 +238,46 @@ func (r *clusterResource) Configure(ctx context.Context, req resource.ConfigureR
return return
} }
var apiClient *ske.APIClient var skeClient *ske.APIClient
var enablementClient *serviceenablement.APIClient
var err error var err error
if providerData.SKECustomEndpoint != "" { if providerData.SKECustomEndpoint != "" {
apiClient, err = ske.NewAPIClient( skeClient, err = ske.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper), config.WithCustomAuth(providerData.RoundTripper),
config.WithEndpoint(providerData.SKECustomEndpoint), config.WithEndpoint(providerData.SKECustomEndpoint),
) )
} else { } else {
apiClient, err = ske.NewAPIClient( skeClient, err = ske.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper), config.WithCustomAuth(providerData.RoundTripper),
config.WithRegion(providerData.Region), config.WithRegion(providerData.Region),
) )
} }
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring SKE API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err))
return return
} }
r.client = apiClient if providerData.ServiceEnablementCustomEndpoint != "" {
tflog.Info(ctx, "SKE cluster client configured") enablementClient, err = serviceenablement.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithEndpoint(providerData.ServiceEnablementCustomEndpoint),
)
} else {
enablementClient, err = serviceenablement.NewAPIClient(
config.WithCustomAuth(providerData.RoundTripper),
config.WithRegion(providerData.Region),
)
}
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring Service Enablement API client", fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err))
return
}
r.skeClient = skeClient
r.enablementClient = enablementClient
tflog.Info(ctx, "SKE cluster clients configured")
} }
// Schema defines the schema for the resource. // Schema defines the schema for the resource.
@ -641,13 +663,13 @@ func (r *clusterResource) Create(ctx context.Context, req resource.CreateRequest
ctx = tflog.SetField(ctx, "name", clusterName) ctx = tflog.SetField(ctx, "name", clusterName)
// If SKE functionality is not enabled, enable it // If SKE functionality is not enabled, enable it
_, err := r.client.EnableService(ctx, projectId).Execute() err := r.enablementClient.EnableService(ctx, projectId, utils.SKEServiceId).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Calling API to enable SKE: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Calling API to enable SKE: %v", err))
return return
} }
_, err = wait.EnableServiceWaitHandler(ctx, r.client, projectId).WaitWithContext(ctx) _, err = wait.EnableServiceWaitHandler(ctx, r.skeClient, projectId).WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Wait for SKE enablement: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Wait for SKE enablement: %v", err))
return return
@ -674,7 +696,7 @@ func (r *clusterResource) Create(ctx context.Context, req resource.CreateRequest
} }
func (r *clusterResource) loadAvailableVersions(ctx context.Context) ([]ske.KubernetesVersion, []ske.MachineImage, error) { func (r *clusterResource) loadAvailableVersions(ctx context.Context) ([]ske.KubernetesVersion, []ske.MachineImage, error) {
c := r.client c := r.skeClient
res, err := c.ListProviderOptions(ctx).Execute() res, err := c.ListProviderOptions(ctx).Execute()
if err != nil { if err != nil {
return nil, nil, fmt.Errorf("calling API: %w", err) return nil, nil, fmt.Errorf("calling API: %w", err)
@ -768,13 +790,13 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag
Network: network, Network: network,
Nodepools: &nodePools, Nodepools: &nodePools,
} }
_, err = r.client.CreateOrUpdateCluster(ctx, projectId, name).CreateOrUpdateClusterPayload(payload).Execute() _, err = r.skeClient.CreateOrUpdateCluster(ctx, projectId, name).CreateOrUpdateClusterPayload(payload).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Calling API: %v", err)) core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Calling API: %v", err))
return return
} }
waitResp, err := wait.CreateOrUpdateClusterWaitHandler(ctx, r.client, projectId, name).WaitWithContext(ctx) waitResp, err := wait.CreateOrUpdateClusterWaitHandler(ctx, r.skeClient, projectId, name).WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Cluster creation waiting: %v", err)) core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Cluster creation waiting: %v", err))
return return
@ -798,7 +820,7 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag
} }
func (r *clusterResource) getCredential(ctx context.Context, diags *diag.Diagnostics, model *Model) error { func (r *clusterResource) getCredential(ctx context.Context, diags *diag.Diagnostics, model *Model) error {
c := r.client c := r.skeClient
// for kubernetes with version >= 1.27, the deprecated endpoint will not work, so we set kubeconfig to nil // for kubernetes with version >= 1.27, the deprecated endpoint will not work, so we set kubeconfig to nil
if semver.Compare(fmt.Sprintf("v%s", model.KubernetesVersion.ValueString()), "v1.27") >= 0 { if semver.Compare(fmt.Sprintf("v%s", model.KubernetesVersion.ValueString()), "v1.27") >= 0 {
core.LogAndAddWarning(ctx, diags, "The kubelogin field is set to null", "Kubernetes version is 1.27 or higher, you must use the stackit_ske_kubeconfig resource instead.") core.LogAndAddWarning(ctx, diags, "The kubelogin field is set to null", "Kubernetes version is 1.27 or higher, you must use the stackit_ske_kubeconfig resource instead.")
@ -1172,7 +1194,7 @@ func toMaintenancePayload(ctx context.Context, m *Model) (*ske.Maintenance, erro
var timeWindowStart *string var timeWindowStart *string
if !(maintenance.Start.IsNull() || maintenance.Start.IsUnknown()) { if !(maintenance.Start.IsNull() || maintenance.Start.IsUnknown()) {
// API expects RFC3339 datetime // API expects RFC3339 datetime
timeWindowStart = utils.Ptr( timeWindowStart = sdkUtils.Ptr(
fmt.Sprintf("0000-01-01T%s", maintenance.Start.ValueString()), fmt.Sprintf("0000-01-01T%s", maintenance.Start.ValueString()),
) )
} }
@ -1180,7 +1202,7 @@ func toMaintenancePayload(ctx context.Context, m *Model) (*ske.Maintenance, erro
var timeWindowEnd *string var timeWindowEnd *string
if !(maintenance.End.IsNull() || maintenance.End.IsUnknown()) { if !(maintenance.End.IsNull() || maintenance.End.IsUnknown()) {
// API expects RFC3339 datetime // API expects RFC3339 datetime
timeWindowEnd = utils.Ptr( timeWindowEnd = sdkUtils.Ptr(
fmt.Sprintf("0000-01-01T%s", maintenance.End.ValueString()), fmt.Sprintf("0000-01-01T%s", maintenance.End.ValueString()),
) )
} }
@ -1833,7 +1855,7 @@ func (r *clusterResource) Read(ctx context.Context, req resource.ReadRequest, re
ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "name", name) ctx = tflog.SetField(ctx, "name", name)
clResp, err := r.client.GetCluster(ctx, projectId, name).Execute() clResp, err := r.skeClient.GetCluster(ctx, projectId, name).Execute()
if err != nil { if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound { if ok && oapiErr.StatusCode == http.StatusNotFound {
@ -1896,7 +1918,7 @@ func (r *clusterResource) Update(ctx context.Context, req resource.UpdateRequest
return return
} }
currentKubernetesVersion, currentMachineImages := getCurrentVersions(ctx, r.client, &model) currentKubernetesVersion, currentMachineImages := getCurrentVersions(ctx, r.skeClient, &model)
r.createOrUpdateCluster(ctx, &resp.Diagnostics, &model, availableKubernetesVersions, availableMachines, currentKubernetesVersion, currentMachineImages) r.createOrUpdateCluster(ctx, &resp.Diagnostics, &model, availableKubernetesVersions, availableMachines, currentKubernetesVersion, currentMachineImages)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -1922,13 +1944,13 @@ func (r *clusterResource) Delete(ctx context.Context, req resource.DeleteRequest
ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "name", name) ctx = tflog.SetField(ctx, "name", name)
c := r.client c := r.skeClient
_, err := c.DeleteCluster(ctx, projectId, name).Execute() _, err := c.DeleteCluster(ctx, projectId, name).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting cluster", fmt.Sprintf("Calling API: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting cluster", fmt.Sprintf("Calling API: %v", err))
return return
} }
_, err = wait.DeleteClusterWaitHandler(ctx, r.client, projectId, name).WaitWithContext(ctx) _, err = wait.DeleteClusterWaitHandler(ctx, r.skeClient, projectId, name).WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting cluster", fmt.Sprintf("Cluster deletion waiting: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting cluster", fmt.Sprintf("Cluster deletion waiting: %v", err))
return return

View file

@ -10,6 +10,10 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
) )
const (
SKEServiceId = "cloud.stackit.ske"
)
// ReconcileStringSlices reconciles two string lists by removing elements from the // ReconcileStringSlices reconciles two string lists by removing elements from the
// first list that are not in the second list and appending elements from the // first list that are not in the second list and appending elements from the
// second list that are not in the first list. // second list that are not in the first list.