diff --git a/docs/data-sources/opensearch_instance.md b/docs/data-sources/opensearch_instance.md index 8d3782ead..187fce15b 100644 --- a/docs/data-sources/opensearch_instance.md +++ b/docs/data-sources/opensearch_instance.md @@ -59,4 +59,4 @@ Read-Only: - `sgw_acl` (String) Comma separated list of IP networks in CIDR notation which are allowed to access this instance. - `syslog` (List of String) List of syslog servers to send logs to. - `tls_ciphers` (List of String) List of TLS ciphers to use. -- `tls_protocols` (String) The TLS protocol to use. +- `tls_protocols` (List of String) List of TLS protocols to use. diff --git a/golang-ci.yaml b/golang-ci.yaml index e42dacdb7..13c02685f 100644 --- a/golang-ci.yaml +++ b/golang-ci.yaml @@ -40,6 +40,7 @@ linters: - typeDefFirst - ifElseChain - dupImport # https://github.com/go-critic/go-critic/issues/845 + - rangeValCopy enabled-tags: - performance - style diff --git a/stackit/internal/conversion/conversion.go b/stackit/internal/conversion/conversion.go index 11bdd5994..2617a74f1 100644 --- a/stackit/internal/conversion/conversion.go +++ b/stackit/internal/conversion/conversion.go @@ -131,11 +131,21 @@ func BoolValueToPointer(s basetypes.BoolValue) *bool { // StringListToPointer converts basetypes.ListValue to a pointer to a list of strings. // It returns nil if the value is null or unknown. func StringListToPointer(list basetypes.ListValue) (*[]string, error) { + result, err := StringListToSlice(list) + if result == nil { + return nil, err + } + return &result, err +} + +// StringListToSlice converts basetypes.ListValue to a list of strings. +// It returns nil if the value is null or unknown. +func StringListToSlice(list basetypes.ListValue) ([]string, error) { if list.IsNull() || list.IsUnknown() { return nil, nil } - listStr := []string{} + var listStr []string for i, el := range list.Elements() { elStr, ok := el.(types.String) if !ok { @@ -144,7 +154,7 @@ func StringListToPointer(list basetypes.ListValue) (*[]string, error) { listStr = append(listStr, elStr.ValueString()) } - return &listStr, nil + return listStr, nil } // StringSetToPointer converts basetypes.SetValue to a pointer to a list of strings. diff --git a/stackit/internal/conversion/conversion_test.go b/stackit/internal/conversion/conversion_test.go index c1dfe8763..dbdb1986e 100644 --- a/stackit/internal/conversion/conversion_test.go +++ b/stackit/internal/conversion/conversion_test.go @@ -449,3 +449,59 @@ func TestStringSetToSlice(t *testing.T) { }) } } + +func TestStringListToSlice(t *testing.T) { + t.Parallel() + tests := []struct { + name string + in basetypes.ListValue + want []string + wantErr bool + }{ + { + name: "unknown", + in: basetypes.NewListUnknown(types.StringType), + want: nil, + }, + { + name: "null", + in: basetypes.NewListNull(types.StringType), + want: nil, + }, + { + name: "invalid type", + in: basetypes.NewListValueMust(types.Int64Type, []attr.Value{types.Int64Value(123)}), + wantErr: true, + }, + { + name: "some values", + in: basetypes.NewListValueMust( + types.StringType, + []attr.Value{ + types.StringValue("abc"), + types.StringValue("xyz"), + }, + ), + want: []string{ + "abc", + "xyz", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := StringListToSlice(tt.in) + if tt.wantErr && err == nil { + t.Fatal("expected error") + } + if !tt.wantErr && err != nil { + t.Fatalf("expected no error, got: %v", err) + } + if d := cmp.Diff(got, tt.want); d != "" { + t.Fatalf("no match, diff: %s", d) + } + }) + } +} diff --git a/stackit/internal/services/opensearch/credential/datasource.go b/stackit/internal/services/opensearch/credential/datasource.go index 86350f600..62c156743 100644 --- a/stackit/internal/services/opensearch/credential/datasource.go +++ b/stackit/internal/services/opensearch/credential/datasource.go @@ -17,7 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" ) // Ensure the implementation satisfies the expected interfaces. @@ -107,7 +107,7 @@ func (r *credentialDataSource) Schema(_ context.Context, _ datasource.SchemaRequ Computed: true, Sensitive: true, }, - "port": schema.Int64Attribute{ + "port": schema.Int32Attribute{ Computed: true, }, "scheme": schema.StringAttribute{ @@ -142,7 +142,7 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "credential_id", credentialId) - recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() + recordSetResp, err := r.client.DefaultAPI.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() if err != nil { utils.LogError( ctx, diff --git a/stackit/internal/services/opensearch/credential/resource.go b/stackit/internal/services/opensearch/credential/resource.go index 1510cd89a..575cfd87c 100644 --- a/stackit/internal/services/opensearch/credential/resource.go +++ b/stackit/internal/services/opensearch/credential/resource.go @@ -21,8 +21,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch/wait" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" + "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api/wait" ) // Ensure the implementation satisfies the expected interfaces. @@ -40,7 +40,7 @@ type Model struct { Host types.String `tfsdk:"host"` Hosts types.List `tfsdk:"hosts"` Password types.String `tfsdk:"password"` - Port types.Int64 `tfsdk:"port"` + Port types.Int32 `tfsdk:"port"` Scheme types.String `tfsdk:"scheme"` Uri types.String `tfsdk:"uri"` Username types.String `tfsdk:"username"` @@ -142,7 +142,7 @@ func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, Computed: true, Sensitive: true, }, - "port": schema.Int64Attribute{ + "port": schema.Int32Attribute{ Computed: true, }, "scheme": schema.StringAttribute{ @@ -176,7 +176,7 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ ctx = tflog.SetField(ctx, "instance_id", instanceId) // Create new recordset - credentialsResp, err := r.client.CreateCredentials(ctx, projectId, instanceId).Execute() + credentialsResp, err := r.client.DefaultAPI.CreateCredentials(ctx, projectId, instanceId).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Calling API: %v", err)) return @@ -184,18 +184,14 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ ctx = core.LogResponse(ctx) - if credentialsResp.Id == nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", "Got empty credential id") - return - } - credentialId := *credentialsResp.Id + credentialId := credentialsResp.Id ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{ "project_id": projectId, "instance_id": instanceId, "credential_id": credentialId, }) - waitResp, err := wait.CreateCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialId).WaitWithContext(ctx) + waitResp, err := wait.CreateCredentialsWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, credentialId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Instance creation waiting: %v", err)) return @@ -233,7 +229,7 @@ func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest, ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "credential_id", credentialId) - recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() + recordSetResp, err := r.client.DefaultAPI.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() 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 if ok && oapiErr.StatusCode == http.StatusNotFound { @@ -287,14 +283,14 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ ctx = tflog.SetField(ctx, "credential_id", credentialId) // Delete existing record set - err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialId).Execute() + err := r.client.DefaultAPI.DeleteCredentials(ctx, projectId, instanceId, credentialId).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Calling API: %v", err)) } ctx = core.LogResponse(ctx) - _, err = wait.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialId).WaitWithContext(ctx) + _, err = wait.DeleteCredentialsWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, credentialId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Instance deletion waiting: %v", err)) return @@ -337,10 +333,8 @@ func mapFields(ctx context.Context, credentialsResp *opensearch.CredentialsRespo var credentialId string if model.CredentialId.ValueString() != "" { credentialId = model.CredentialId.ValueString() - } else if credentialsResp.Id != nil { - credentialId = *credentialsResp.Id } else { - return fmt.Errorf("credentials id not present") + credentialId = credentialsResp.Id } model.Id = utils.BuildInternalTerraformId( @@ -354,24 +348,22 @@ func mapFields(ctx context.Context, credentialsResp *opensearch.CredentialsRespo model.CredentialId = types.StringValue(credentialId) model.Hosts = types.ListNull(types.StringType) - if credentials != nil { - if credentials.Hosts != nil { - respHosts := *credentials.Hosts - reconciledHosts := utils.ReconcileStringSlices(modelHosts, respHosts) + if credentials.Hosts != nil { + respHosts := credentials.Hosts + reconciledHosts := utils.ReconcileStringSlices(modelHosts, respHosts) - hostsTF, diags := types.ListValueFrom(ctx, types.StringType, reconciledHosts) - if diags.HasError() { - return fmt.Errorf("failed to map hosts: %w", core.DiagsToError(diags)) - } - - model.Hosts = hostsTF + hostsTF, diags := types.ListValueFrom(ctx, types.StringType, reconciledHosts) + if diags.HasError() { + return fmt.Errorf("failed to map hosts: %w", core.DiagsToError(diags)) } - model.Host = types.StringPointerValue(credentials.Host) - model.Password = types.StringPointerValue(credentials.Password) - model.Port = types.Int64PointerValue(credentials.Port) - model.Scheme = types.StringPointerValue(credentials.Scheme) - model.Uri = types.StringPointerValue(credentials.Uri) - model.Username = types.StringPointerValue(credentials.Username) + + model.Hosts = hostsTF } + model.Host = types.StringValue(credentials.Host) + model.Password = types.StringValue(credentials.Password) + model.Port = types.Int32PointerValue(credentials.Port) + model.Scheme = types.StringPointerValue(credentials.Scheme) + model.Uri = types.StringPointerValue(credentials.Uri) + model.Username = types.StringValue(credentials.Username) return nil } diff --git a/stackit/internal/services/opensearch/credential/resource_test.go b/stackit/internal/services/opensearch/credential/resource_test.go index c07494bda..523f86cbe 100644 --- a/stackit/internal/services/opensearch/credential/resource_test.go +++ b/stackit/internal/services/opensearch/credential/resource_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" ) func TestMapFields(t *testing.T) { @@ -25,7 +25,7 @@ func TestMapFields(t *testing.T) { ProjectId: types.StringValue("pid"), }, &opensearch.CredentialsResponse{ - Id: new("cid"), + Id: "cid", Raw: &opensearch.RawCredentials{}, }, Model{ @@ -33,13 +33,13 @@ func TestMapFields(t *testing.T) { CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), - Host: types.StringNull(), + Host: types.StringValue(""), Hosts: types.ListNull(types.StringType), - Password: types.StringNull(), - Port: types.Int64Null(), + Password: types.StringValue(""), + Port: types.Int32Null(), Scheme: types.StringNull(), Uri: types.StringNull(), - Username: types.StringNull(), + Username: types.StringValue(""), }, true, }, @@ -50,19 +50,19 @@ func TestMapFields(t *testing.T) { ProjectId: types.StringValue("pid"), }, &opensearch.CredentialsResponse{ - Id: new("cid"), + Id: "cid", Raw: &opensearch.RawCredentials{ - Credentials: &opensearch.Credentials{ - Host: new("host"), - Hosts: &[]string{ + Credentials: opensearch.Credentials{ + Host: "host", + Hosts: []string{ "host_1", "", }, - Password: new("password"), - Port: new(int64(1234)), + Password: "password", + Port: new(int32(1234)), Scheme: new("scheme"), Uri: new("uri"), - Username: new("username"), + Username: "username", }, }, }, @@ -77,7 +77,7 @@ func TestMapFields(t *testing.T) { types.StringValue(""), }), Password: types.StringValue("password"), - Port: types.Int64Value(1234), + Port: types.Int32Value(1234), Scheme: types.StringValue("scheme"), Uri: types.StringValue("uri"), Username: types.StringValue("username"), @@ -96,20 +96,20 @@ func TestMapFields(t *testing.T) { }), }, &opensearch.CredentialsResponse{ - Id: new("cid"), + Id: "cid", Raw: &opensearch.RawCredentials{ - Credentials: &opensearch.Credentials{ - Host: new("host"), - Hosts: &[]string{ + Credentials: opensearch.Credentials{ + Host: "host", + Hosts: []string{ "", "host_1", "host_2", }, - Password: new("password"), - Port: new(int64(1234)), + Password: "password", + Port: new(int32(1234)), Scheme: new("scheme"), Uri: new("uri"), - Username: new("username"), + Username: "username", }, }, }, @@ -125,7 +125,7 @@ func TestMapFields(t *testing.T) { types.StringValue("host_1"), }), Password: types.StringValue("password"), - Port: types.Int64Value(1234), + Port: types.Int32Value(1234), Scheme: types.StringValue("scheme"), Uri: types.StringValue("uri"), Username: types.StringValue("username"), @@ -139,16 +139,16 @@ func TestMapFields(t *testing.T) { ProjectId: types.StringValue("pid"), }, &opensearch.CredentialsResponse{ - Id: new("cid"), + Id: "cid", Raw: &opensearch.RawCredentials{ - Credentials: &opensearch.Credentials{ - Host: new(""), - Hosts: &[]string{}, - Password: new(""), - Port: new(int64(2123456789)), + Credentials: opensearch.Credentials{ + Host: "", + Hosts: []string{}, + Password: "", + Port: new(int32(2123456789)), Scheme: nil, Uri: nil, - Username: new(""), + Username: "", }, }, }, @@ -160,7 +160,7 @@ func TestMapFields(t *testing.T) { Host: types.StringValue(""), Hosts: types.ListValueMust(types.StringType, []attr.Value{}), Password: types.StringValue(""), - Port: types.Int64Value(2123456789), + Port: types.Int32Value(2123456789), Scheme: types.StringNull(), Uri: types.StringNull(), Username: types.StringValue(""), @@ -194,7 +194,7 @@ func TestMapFields(t *testing.T) { ProjectId: types.StringValue("pid"), }, &opensearch.CredentialsResponse{ - Id: new("cid"), + Id: "cid", }, Model{}, false, diff --git a/stackit/internal/services/opensearch/instance/datasource.go b/stackit/internal/services/opensearch/instance/datasource.go index 6e5a25950..7fee1825d 100644 --- a/stackit/internal/services/opensearch/instance/datasource.go +++ b/stackit/internal/services/opensearch/instance/datasource.go @@ -17,7 +17,7 @@ import ( "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" ) // Ensure the implementation satisfies the expected interfaces. @@ -82,7 +82,7 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "plugins": "List of plugins to install. Must be a supported plugin name. The plugins `repository-s3` and `repository-azure` are enabled by default and cannot be disabled.", "syslog": "List of syslog servers to send logs to.", "tls_ciphers": "List of TLS ciphers to use.", - "tls_protocols": "The TLS protocol to use.", + "tls_protocols": "List of TLS protocols to use.", } resp.Schema = schema.Schema{ @@ -142,19 +142,19 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques Description: parametersDescriptions["java_garbage_collector"], Computed: true, }, - "java_heapspace": schema.Int64Attribute{ + "java_heapspace": schema.Int32Attribute{ Description: parametersDescriptions["java_heapspace"], Computed: true, }, - "java_maxmetaspace": schema.Int64Attribute{ + "java_maxmetaspace": schema.Int32Attribute{ Description: parametersDescriptions["java_maxmetaspace"], Computed: true, }, - "max_disk_threshold": schema.Int64Attribute{ + "max_disk_threshold": schema.Int32Attribute{ Description: parametersDescriptions["max_disk_threshold"], Computed: true, }, - "metrics_frequency": schema.Int64Attribute{ + "metrics_frequency": schema.Int32Attribute{ Description: parametersDescriptions["metrics_frequency"], Computed: true, }, @@ -181,7 +181,8 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques Description: parametersDescriptions["tls_ciphers"], Computed: true, }, - "tls_protocols": schema.StringAttribute{ + "tls_protocols": schema.ListAttribute{ + ElementType: types.StringType, Description: parametersDescriptions["tls_protocols"], Computed: true, }, @@ -223,7 +224,7 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { utils.LogError( ctx, diff --git a/stackit/internal/services/opensearch/instance/resource.go b/stackit/internal/services/opensearch/instance/resource.go index 372088f3a..3984af639 100644 --- a/stackit/internal/services/opensearch/instance/resource.go +++ b/stackit/internal/services/opensearch/instance/resource.go @@ -26,8 +26,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch/wait" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" + "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api/wait" ) // Ensure the implementation satisfies the expected interfaces. @@ -59,10 +59,10 @@ type parametersModel struct { EnableMonitoring types.Bool `tfsdk:"enable_monitoring"` Graphite types.String `tfsdk:"graphite"` JavaGarbageCollector types.String `tfsdk:"java_garbage_collector"` - JavaHeapspace types.Int64 `tfsdk:"java_heapspace"` - JavaMaxmetaspace types.Int64 `tfsdk:"java_maxmetaspace"` - MaxDiskThreshold types.Int64 `tfsdk:"max_disk_threshold"` - MetricsFrequency types.Int64 `tfsdk:"metrics_frequency"` + JavaHeapspace types.Int32 `tfsdk:"java_heapspace"` + JavaMaxmetaspace types.Int32 `tfsdk:"java_maxmetaspace"` + MaxDiskThreshold types.Int32 `tfsdk:"max_disk_threshold"` + MetricsFrequency types.Int32 `tfsdk:"metrics_frequency"` MetricsPrefix types.String `tfsdk:"metrics_prefix"` MonitoringInstanceId types.String `tfsdk:"monitoring_instance_id"` Plugins types.List `tfsdk:"plugins"` @@ -77,10 +77,10 @@ var parametersTypes = map[string]attr.Type{ "enable_monitoring": basetypes.BoolType{}, "graphite": basetypes.StringType{}, "java_garbage_collector": basetypes.StringType{}, - "java_heapspace": basetypes.Int64Type{}, - "java_maxmetaspace": basetypes.Int64Type{}, - "max_disk_threshold": basetypes.Int64Type{}, - "metrics_frequency": basetypes.Int64Type{}, + "java_heapspace": basetypes.Int32Type{}, + "java_maxmetaspace": basetypes.Int32Type{}, + "max_disk_threshold": basetypes.Int32Type{}, + "metrics_frequency": basetypes.Int32Type{}, "metrics_prefix": basetypes.StringType{}, "monitoring_instance_id": basetypes.StringType{}, "plugins": basetypes.ListType{ElemType: types.StringType}, @@ -229,22 +229,22 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r Optional: true, Computed: true, }, - "java_heapspace": schema.Int64Attribute{ + "java_heapspace": schema.Int32Attribute{ Description: parametersDescriptions["java_heapspace"], Optional: true, Computed: true, }, - "java_maxmetaspace": schema.Int64Attribute{ + "java_maxmetaspace": schema.Int32Attribute{ Description: parametersDescriptions["java_maxmetaspace"], Optional: true, Computed: true, }, - "max_disk_threshold": schema.Int64Attribute{ + "max_disk_threshold": schema.Int32Attribute{ Description: parametersDescriptions["max_disk_threshold"], Optional: true, Computed: true, }, - "metrics_frequency": schema.Int64Attribute{ + "metrics_frequency": schema.Int32Attribute{ Description: parametersDescriptions["metrics_frequency"], Optional: true, Computed: true, @@ -358,24 +358,21 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } // Create new instance - createResp, err := r.client.CreateInstance(ctx, projectId).CreateInstancePayload(*payload).Execute() + createResp, err := r.client.DefaultAPI.CreateInstance(ctx, projectId).CreateInstancePayload(*payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err)) return } ctx = core.LogResponse(ctx) - if createResp.InstanceId == nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", "API response did not include instance ID") - } - instanceId := *createResp.InstanceId + instanceId := createResp.InstanceId ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{ "project_id": projectId, "instance_id": instanceId, }) - waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, instanceId).WaitWithContext(ctx) + waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err)) return @@ -413,7 +410,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, instanceId).Execute() 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 if ok && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { @@ -488,12 +485,12 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } // Update existing instance - err = r.client.PartialUpdateInstance(ctx, projectId, instanceId).PartialUpdateInstancePayload(*payload).Execute() + err = r.client.DefaultAPI.PartialUpdateInstance(ctx, projectId, instanceId).PartialUpdateInstancePayload(*payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } - waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).WaitWithContext(ctx) + waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Instance update waiting: %v", err)) return @@ -534,7 +531,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = tflog.SetField(ctx, "instance_id", instanceId) // Delete existing instance - err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() + err := r.client.DefaultAPI.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return @@ -542,7 +539,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = core.LogResponse(ctx) - _, err = wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).WaitWithContext(ctx) + _, err = wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return @@ -589,18 +586,18 @@ func mapFields(instance *opensearch.Instance, model *Model) error { model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), instanceId) model.InstanceId = types.StringValue(instanceId) - model.PlanId = types.StringPointerValue(instance.PlanId) - model.CfGuid = types.StringPointerValue(instance.CfGuid) - model.CfSpaceGuid = types.StringPointerValue(instance.CfSpaceGuid) - model.DashboardUrl = types.StringPointerValue(instance.DashboardUrl) - model.ImageUrl = types.StringPointerValue(instance.ImageUrl) - model.Name = types.StringPointerValue(instance.Name) - model.CfOrganizationGuid = types.StringPointerValue(instance.CfOrganizationGuid) + model.PlanId = types.StringValue(instance.PlanId) + model.CfGuid = types.StringValue(instance.CfGuid) + model.CfSpaceGuid = types.StringValue(instance.CfSpaceGuid) + model.DashboardUrl = types.StringValue(instance.DashboardUrl) + model.ImageUrl = types.StringValue(instance.ImageUrl) + model.Name = types.StringValue(instance.Name) + model.CfOrganizationGuid = types.StringValue(instance.CfOrganizationGuid) if instance.Parameters == nil { model.Parameters = types.ObjectNull(parametersTypes) } else { - parameters, err := mapParameters(*instance.Parameters) + parameters, err := mapParameters(instance.Parameters) if err != nil { return fmt.Errorf("mapping parameters: %w", err) } @@ -658,26 +655,22 @@ func mapParameters(params map[string]any) (types.Object, error) { } value = types.BoolValue(valueBool) } - case basetypes.Int64Type: + case basetypes.Int32Type: if valueInterface == nil { - value = types.Int64Null() + value = types.Int32Null() } else { - // This may be int64, int32, int or float64 + // This may be int32, int or float64 // We try to assert all 4 - var valueInt64 int64 + var valueInt32 int32 switch temp := valueInterface.(type) { default: return types.ObjectNull(parametersTypes), fmt.Errorf("found attribute '%s' of type %T, failed to assert as int", attribute, valueInterface) - case int64: - valueInt64 = temp case int32: - valueInt64 = int64(temp) - case int: - valueInt64 = int64(temp) + valueInt32 = temp case float64: - valueInt64 = int64(temp) + valueInt32 = int32(temp) } - value = types.Int64Value(valueInt64) + value = types.Int32Value(valueInt32) } case basetypes.ListType: // Assumed to be a list of strings if valueInterface == nil { @@ -728,9 +721,9 @@ func toCreatePayload(model *Model, parameters *parametersModel) (*opensearch.Cre return nil, fmt.Errorf("convert parameters: %w", err) } return &opensearch.CreateInstancePayload{ - InstanceName: conversion.StringValueToPointer(model.Name), + InstanceName: model.Name.ValueString(), Parameters: payloadParams, - PlanId: conversion.StringValueToPointer(model.PlanId), + PlanId: model.PlanId.ValueString(), }, nil } @@ -757,31 +750,31 @@ func toInstanceParams(parameters *parametersModel) (*opensearch.InstanceParamete payloadParams.SgwAcl = conversion.StringValueToPointer(parameters.SgwAcl) payloadParams.EnableMonitoring = conversion.BoolValueToPointer(parameters.EnableMonitoring) payloadParams.Graphite = conversion.StringValueToPointer(parameters.Graphite) - payloadParams.JavaGarbageCollector = opensearch.InstanceParametersGetJavaGarbageCollectorAttributeType(conversion.StringValueToPointer(parameters.JavaGarbageCollector)) - payloadParams.JavaHeapspace = conversion.Int64ValueToPointer(parameters.JavaHeapspace) - payloadParams.JavaMaxmetaspace = conversion.Int64ValueToPointer(parameters.JavaMaxmetaspace) - payloadParams.MaxDiskThreshold = conversion.Int64ValueToPointer(parameters.MaxDiskThreshold) - payloadParams.MetricsFrequency = conversion.Int64ValueToPointer(parameters.MetricsFrequency) + payloadParams.JavaGarbageCollector = conversion.StringValueToPointer(parameters.JavaGarbageCollector) + payloadParams.JavaHeapspace = conversion.Int32ValueToPointer(parameters.JavaHeapspace) + payloadParams.JavaMaxmetaspace = conversion.Int32ValueToPointer(parameters.JavaMaxmetaspace) + payloadParams.MaxDiskThreshold = conversion.Int32ValueToPointer(parameters.MaxDiskThreshold) + payloadParams.MetricsFrequency = conversion.Int32ValueToPointer(parameters.MetricsFrequency) payloadParams.MetricsPrefix = conversion.StringValueToPointer(parameters.MetricsPrefix) payloadParams.MonitoringInstanceId = conversion.StringValueToPointer(parameters.MonitoringInstanceId) var err error - payloadParams.Plugins, err = conversion.StringListToPointer(parameters.Plugins) + payloadParams.Plugins, err = conversion.StringListToSlice(parameters.Plugins) if err != nil { return nil, fmt.Errorf("convert plugins: %w", err) } - payloadParams.Syslog, err = conversion.StringListToPointer(parameters.Syslog) + payloadParams.Syslog, err = conversion.StringListToSlice(parameters.Syslog) if err != nil { return nil, fmt.Errorf("convert syslog: %w", err) } - payloadParams.TlsCiphers, err = conversion.StringListToPointer(parameters.TlsCiphers) + payloadParams.TlsCiphers, err = conversion.StringListToSlice(parameters.TlsCiphers) if err != nil { return nil, fmt.Errorf("convert tls_ciphers: %w", err) } - payloadParams.TlsProtocols, err = conversion.StringListToPointer(parameters.TlsProtocols) + payloadParams.TlsProtocols, err = conversion.StringListToSlice(parameters.TlsProtocols) if err != nil { return nil, fmt.Errorf("convert tls_protocols: %w", err) } @@ -791,7 +784,7 @@ func toInstanceParams(parameters *parametersModel) (*opensearch.InstanceParamete func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() - res, err := r.client.ListOfferings(ctx, projectId).Execute() + res, err := r.client.DefaultAPI.ListOfferings(ctx, projectId).Execute() if err != nil { return fmt.Errorf("getting OpenSearch offerings: %w", err) } @@ -801,22 +794,19 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { availableVersions := "" availablePlanNames := "" isValidVersion := false - for _, offer := range *res.Offerings { - if !strings.EqualFold(*offer.Version, version) { - availableVersions = fmt.Sprintf("%s\n- %s", availableVersions, *offer.Version) + for _, offer := range res.Offerings { + if !strings.EqualFold(offer.Version, version) { + availableVersions = fmt.Sprintf("%s\n- %s", availableVersions, offer.Version) continue } isValidVersion = true - for _, plan := range *offer.Plans { - if plan.Name == nil { - continue - } - if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { - model.PlanId = types.StringPointerValue(plan.Id) + for _, plan := range offer.Plans { + if strings.EqualFold(plan.Name, planName) { + model.PlanId = types.StringValue(plan.Id) return nil } - availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) + availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, plan.Name) } } @@ -829,16 +819,16 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { func loadPlanNameAndVersion(ctx context.Context, client *opensearch.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() - res, err := client.ListOfferings(ctx, projectId).Execute() + res, err := client.DefaultAPI.ListOfferings(ctx, projectId).Execute() if err != nil { return fmt.Errorf("getting OpenSearch offerings: %w", err) } - for _, offer := range *res.Offerings { - for _, plan := range *offer.Plans { - if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { - model.PlanName = types.StringPointerValue(plan.Name) - model.Version = types.StringPointerValue(offer.Version) + for _, offer := range res.Offerings { + for _, plan := range offer.Plans { + if strings.EqualFold(plan.Id, planId) { + model.PlanName = types.StringValue(plan.Name) + model.Version = types.StringValue(offer.Version) return nil } } diff --git a/stackit/internal/services/opensearch/instance/resource_test.go b/stackit/internal/services/opensearch/instance/resource_test.go index 4d2535ee9..eb242adcf 100644 --- a/stackit/internal/services/opensearch/instance/resource_test.go +++ b/stackit/internal/services/opensearch/instance/resource_test.go @@ -8,18 +8,19 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + legacyOpensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" ) var fixtureModelParameters = types.ObjectValueMust(parametersTypes, map[string]attr.Value{ "sgw_acl": types.StringValue("acl"), "enable_monitoring": types.BoolValue(true), "graphite": types.StringValue("graphite"), - "java_garbage_collector": types.StringValue(string(opensearch.INSTANCEPARAMETERSJAVA_GARBAGE_COLLECTOR_USE_G1_GC)), - "java_heapspace": types.Int64Value(10), - "java_maxmetaspace": types.Int64Value(10), - "max_disk_threshold": types.Int64Value(10), - "metrics_frequency": types.Int64Value(10), + "java_garbage_collector": types.StringValue(string(legacyOpensearch.INSTANCEPARAMETERSJAVA_GARBAGE_COLLECTOR_USE_G1_GC)), + "java_heapspace": types.Int32Value(10), + "java_maxmetaspace": types.Int32Value(10), + "max_disk_threshold": types.Int32Value(10), + "metrics_frequency": types.Int32Value(10), "metrics_prefix": types.StringValue("prefix"), "monitoring_instance_id": types.StringValue("mid"), "plugins": types.ListValueMust(types.StringType, []attr.Value{ @@ -45,10 +46,10 @@ var fixtureNullModelParameters = types.ObjectValueMust(parametersTypes, map[stri "enable_monitoring": types.BoolNull(), "graphite": types.StringNull(), "java_garbage_collector": types.StringNull(), - "java_heapspace": types.Int64Null(), - "java_maxmetaspace": types.Int64Null(), - "max_disk_threshold": types.Int64Null(), - "metrics_frequency": types.Int64Null(), + "java_heapspace": types.Int32Null(), + "java_maxmetaspace": types.Int32Null(), + "max_disk_threshold": types.Int32Null(), + "metrics_frequency": types.Int32Null(), "metrics_prefix": types.StringNull(), "monitoring_instance_id": types.StringNull(), "plugins": types.ListNull(types.StringType), @@ -61,17 +62,17 @@ var fixtureInstanceParameters = opensearch.InstanceParameters{ SgwAcl: new("acl"), EnableMonitoring: new(true), Graphite: new("graphite"), - JavaGarbageCollector: opensearch.INSTANCEPARAMETERSJAVA_GARBAGE_COLLECTOR_USE_G1_GC.Ptr(), - JavaHeapspace: new(int64(10)), - JavaMaxmetaspace: new(int64(10)), - MaxDiskThreshold: new(int64(10)), - MetricsFrequency: new(int64(10)), + JavaGarbageCollector: new(string(legacyOpensearch.INSTANCEPARAMETERSJAVA_GARBAGE_COLLECTOR_USE_G1_GC)), + JavaHeapspace: new(int32(10)), + JavaMaxmetaspace: new(int32(10)), + MaxDiskThreshold: new(int32(10)), + MetricsFrequency: new(int32(10)), MetricsPrefix: new("prefix"), MonitoringInstanceId: new("mid"), - Plugins: &[]string{"plugin", "plugin2"}, - Syslog: &[]string{"syslog", "syslog2"}, - TlsCiphers: &[]string{"cipher", "cipher2"}, - TlsProtocols: &[]string{"TLSv1.2", "TLSv1.3"}, + Plugins: []string{"plugin", "plugin2"}, + Syslog: []string{"syslog", "syslog2"}, + TlsCiphers: []string{"cipher", "cipher2"}, + TlsProtocols: []string{"TLSv1.2", "TLSv1.3"}, } func TestMapFields(t *testing.T) { @@ -88,13 +89,13 @@ func TestMapFields(t *testing.T) { Id: types.StringValue("pid,iid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), - PlanId: types.StringNull(), - Name: types.StringNull(), - CfGuid: types.StringNull(), - CfSpaceGuid: types.StringNull(), - DashboardUrl: types.StringNull(), - ImageUrl: types.StringNull(), - CfOrganizationGuid: types.StringNull(), + PlanId: types.StringValue(""), + Name: types.StringValue(""), + CfGuid: types.StringValue(""), + CfSpaceGuid: types.StringValue(""), + DashboardUrl: types.StringValue(""), + ImageUrl: types.StringValue(""), + CfOrganizationGuid: types.StringValue(""), Parameters: types.ObjectNull(parametersTypes), }, true, @@ -102,24 +103,24 @@ func TestMapFields(t *testing.T) { { "simple_values", &opensearch.Instance{ - PlanId: new("plan"), - CfGuid: new("cf"), - CfSpaceGuid: new("space"), - DashboardUrl: new("dashboard"), - ImageUrl: new("image"), + PlanId: "plan", + CfGuid: "cf", + CfSpaceGuid: "space", + DashboardUrl: "dashboard", + ImageUrl: "image", InstanceId: new("iid"), - Name: new("name"), - CfOrganizationGuid: new("org"), - Parameters: &map[string]any{ + Name: "name", + CfOrganizationGuid: "org", + Parameters: map[string]any{ // Using "-" on purpose on some fields because that is the API response "sgw_acl": "acl", "enable_monitoring": true, "graphite": "graphite", - "java_garbage_collector": string(opensearch.INSTANCEPARAMETERSJAVA_GARBAGE_COLLECTOR_USE_G1_GC), - "java_heapspace": int64(10), - "java_maxmetaspace": int64(10), - "max_disk_threshold": int64(10), - "metrics_frequency": int64(10), + "java_garbage_collector": string(legacyOpensearch.INSTANCEPARAMETERSJAVA_GARBAGE_COLLECTOR_USE_G1_GC), + "java_heapspace": int32(10), + "java_maxmetaspace": int32(10), + "max_disk_threshold": int32(10), + "metrics_frequency": int32(10), "metrics_prefix": "prefix", "monitoring_instance_id": "mid", "plugins": []string{"plugin", "plugin2"}, @@ -158,7 +159,7 @@ func TestMapFields(t *testing.T) { { "wrong_param_types_1", &opensearch.Instance{ - Parameters: &map[string]any{ + Parameters: map[string]any{ "sgw_acl": true, }, }, @@ -168,7 +169,7 @@ func TestMapFields(t *testing.T) { { "wrong_param_types_2", &opensearch.Instance{ - Parameters: &map[string]any{ + Parameters: map[string]any{ "sgw_acl": 1, }, }, @@ -220,9 +221,9 @@ func TestToCreatePayload(t *testing.T) { Parameters: fixtureModelParameters, }, &opensearch.CreateInstancePayload{ - InstanceName: new("name"), + InstanceName: "name", Parameters: &fixtureInstanceParameters, - PlanId: new("plan"), + PlanId: "plan", }, true, }, @@ -234,9 +235,9 @@ func TestToCreatePayload(t *testing.T) { Parameters: fixtureNullModelParameters, }, &opensearch.CreateInstancePayload{ - InstanceName: new(""), + InstanceName: "", Parameters: &opensearch.InstanceParameters{}, - PlanId: new(""), + PlanId: "", }, true, }, @@ -253,8 +254,8 @@ func TestToCreatePayload(t *testing.T) { PlanId: types.StringValue("plan"), }, &opensearch.CreateInstancePayload{ - InstanceName: new("name"), - PlanId: new("plan"), + InstanceName: "name", + PlanId: "plan", }, true, }, diff --git a/stackit/internal/services/opensearch/utils/util.go b/stackit/internal/services/opensearch/utils/util.go index e630a860e..f1075ffa5 100644 --- a/stackit/internal/services/opensearch/utils/util.go +++ b/stackit/internal/services/opensearch/utils/util.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/stackitcloud/stackit-sdk-go/core/config" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" ) diff --git a/stackit/internal/services/opensearch/utils/util_test.go b/stackit/internal/services/opensearch/utils/util_test.go index fa46355bf..fa441218f 100644 --- a/stackit/internal/services/opensearch/utils/util_test.go +++ b/stackit/internal/services/opensearch/utils/util_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" sdkClients "github.com/stackitcloud/stackit-sdk-go/core/clients" "github.com/stackitcloud/stackit-sdk-go/core/config" - "github.com/stackitcloud/stackit-sdk-go/services/opensearch" + opensearch "github.com/stackitcloud/stackit-sdk-go/services/opensearch/v1api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" )