From c9dd89a64c358d92f1d8926fa820c87e3993a689 Mon Sep 17 00:00:00 2001 From: Robert Savu Date: Thu, 9 Jul 2026 14:34:12 +0200 Subject: [PATCH 1/6] feat(dremio): stop returning client secret on get dremio Treviously the get dremio and list dremio endpoints were returning the full IDP config, including the client secret. The client secert should be known by the IDP and the instance itself and not be returned by "routine" get/list requests. --- go.mod | 2 +- go.sum | 4 ++-- .../internal/services/dremio/instance/resource.go | 8 ++++---- .../services/dremio/instance/resource_test.go | 14 ++++++-------- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 942312854..a07c66633 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/stackitcloud/stackit-sdk-go/services/cdn v1.18.0 github.com/stackitcloud/stackit-sdk-go/services/certificates v1.8.0 github.com/stackitcloud/stackit-sdk-go/services/dns v0.21.0 - github.com/stackitcloud/stackit-sdk-go/services/dremio v0.3.0 + github.com/stackitcloud/stackit-sdk-go/services/dremio v0.4.0 github.com/stackitcloud/stackit-sdk-go/services/edge v0.12.0 github.com/stackitcloud/stackit-sdk-go/services/git v0.14.0 github.com/stackitcloud/stackit-sdk-go/services/iaas v1.12.0 diff --git a/go.sum b/go.sum index bca7caf55..269a85eab 100644 --- a/go.sum +++ b/go.sum @@ -680,8 +680,8 @@ github.com/stackitcloud/stackit-sdk-go/services/certificates v1.8.0 h1:bINitVHAy github.com/stackitcloud/stackit-sdk-go/services/certificates v1.8.0/go.mod h1:eJpB3/pukz+KzVPVHQ4g3DVtQkxGga18VbFBhq9ugdY= github.com/stackitcloud/stackit-sdk-go/services/dns v0.21.0 h1:ZVkptfVCAqpaPWkE+WIopM9XdzqgbVcwmX5L1jZqqx8= github.com/stackitcloud/stackit-sdk-go/services/dns v0.21.0/go.mod h1:FiYSv3D9rzgEVzi8Mpq5oYZBosrasa5uUYqVdEIbM1U= -github.com/stackitcloud/stackit-sdk-go/services/dremio v0.3.0 h1:LKreLAR425+EMYbKrPIAzeoTEQlDF8EpIMTVBpOhjmA= -github.com/stackitcloud/stackit-sdk-go/services/dremio v0.3.0/go.mod h1:iMoiM8fM1mXC1Nz8FBiiQ08Yh+0C3yN0GPCdAbOlRXo= +github.com/stackitcloud/stackit-sdk-go/services/dremio v0.4.0 h1:kAWRUptc9g6lA9XCgB4Fw8oQYOhDuV0mp+eZhpiyJ+Y= +github.com/stackitcloud/stackit-sdk-go/services/dremio v0.4.0/go.mod h1:iMoiM8fM1mXC1Nz8FBiiQ08Yh+0C3yN0GPCdAbOlRXo= github.com/stackitcloud/stackit-sdk-go/services/edge v0.12.0 h1:qPhNo5m0K9ZKMnUx7e23fmvBmhOCxIFRzobwFhSHWUY= github.com/stackitcloud/stackit-sdk-go/services/edge v0.12.0/go.mod h1:Ylse6gqGJtsd5TVmvha+hoLd1QQHLKvhY5dO15+q5kg= github.com/stackitcloud/stackit-sdk-go/services/git v0.14.0 h1:VZBneGprCmHqckcSMPs3puBlK8rBpLMtYKmBktwdoVE= diff --git a/stackit/internal/services/dremio/instance/resource.go b/stackit/internal/services/dremio/instance/resource.go index aa51dc4a7..85f09b0c2 100644 --- a/stackit/internal/services/dremio/instance/resource.go +++ b/stackit/internal/services/dremio/instance/resource.go @@ -717,7 +717,7 @@ func mapAuthentication(instanceResp *dremioSdk.DremioResponse, model *Model) err authModel.AzureAD = &AzureADModel{ AuthorityUrl: types.StringValue(azureADResp.AuthorityUrl), ClientId: types.StringValue(azureADResp.ClientId), - ClientSecret: types.StringValue(azureADResp.ClientSecret), + ClientSecret: types.StringNull(), RedirectUrl: types.StringPointerValue(azureADResp.RedirectUrl), } } @@ -727,7 +727,7 @@ func mapAuthentication(instanceResp *dremioSdk.DremioResponse, model *Model) err oauthModel := &OAuthModel{ AuthorityUrl: types.StringValue(oauthResp.AuthorityUrl), ClientId: types.StringValue(oauthResp.ClientId), - ClientSecret: types.StringValue(oauthResp.ClientSecret), + ClientSecret: types.StringNull(), Scope: types.StringPointerValue(oauthResp.Scope), RedirectUrl: types.StringPointerValue(oauthResp.RedirectUrl), JwtClaims: &JwtClaimsModel{ @@ -827,7 +827,7 @@ func parseAuthentication(model *Model) (*dremioSdk.Authentication, error) { oAuthPayload := &dremioSdk.Oauth{ AuthorityUrl: model.Authentication.OAuth.AuthorityUrl.ValueString(), ClientId: model.Authentication.OAuth.ClientId.ValueString(), - ClientSecret: model.Authentication.OAuth.ClientSecret.ValueString(), + ClientSecret: model.Authentication.OAuth.ClientSecret.ValueStringPointer(), JwtClaims: dremioSdk.OauthJwtClaims{ UserName: model.Authentication.OAuth.JwtClaims.UserName.ValueString(), }, @@ -852,7 +852,7 @@ func parseAuthentication(model *Model) (*dremioSdk.Authentication, error) { azureAdPayload := &dremioSdk.Azuread{ AuthorityUrl: model.Authentication.AzureAD.AuthorityUrl.ValueString(), ClientId: model.Authentication.AzureAD.ClientId.ValueString(), - ClientSecret: model.Authentication.AzureAD.ClientSecret.ValueString(), + ClientSecret: model.Authentication.AzureAD.ClientSecret.ValueStringPointer(), RedirectUrl: model.Authentication.AzureAD.RedirectUrl.ValueStringPointer(), } return &dremioSdk.Authentication{ diff --git a/stackit/internal/services/dremio/instance/resource_test.go b/stackit/internal/services/dremio/instance/resource_test.go index a295afcc8..7b03b80dd 100644 --- a/stackit/internal/services/dremio/instance/resource_test.go +++ b/stackit/internal/services/dremio/instance/resource_test.go @@ -36,13 +36,11 @@ func TestMapFields(t *testing.T) { Azuread: &dremioSdk.Azuread{ AuthorityUrl: "azure-authority", ClientId: "azure-client", - ClientSecret: "azure-secret", RedirectUrl: utils.Ptr("azure-redirect"), }, Oauth: &dremioSdk.Oauth{ AuthorityUrl: "oauth-authority", ClientId: "oauth-client", - ClientSecret: "oauth-secret", JwtClaims: dremioSdk.OauthJwtClaims{ UserName: "oauth-username", }, @@ -77,13 +75,13 @@ func TestMapFields(t *testing.T) { AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), ClientId: types.StringValue("azure-client"), - ClientSecret: types.StringValue("azure-secret"), + ClientSecret: types.StringNull(), RedirectUrl: types.StringValue("azure-redirect"), }, OAuth: &OAuthModel{ AuthorityUrl: types.StringValue("oauth-authority"), ClientId: types.StringValue("oauth-client"), - ClientSecret: types.StringValue("oauth-secret"), + ClientSecret: types.StringNull(), JwtClaims: &JwtClaimsModel{ UserName: types.StringValue("oauth-username"), }, @@ -207,7 +205,7 @@ func TestToCreatePayload(t *testing.T) { Oauth: &dremioSdk.Oauth{ AuthorityUrl: "oauth-authority", ClientId: "oauth-client", - ClientSecret: "oauth-secret", + ClientSecret: utils.Ptr("oauth-secret"), JwtClaims: dremioSdk.OauthJwtClaims{ UserName: "oauth-username", }, @@ -247,7 +245,7 @@ func TestToCreatePayload(t *testing.T) { Azuread: &dremioSdk.Azuread{ AuthorityUrl: "azure-authority", ClientId: "azure-client", - ClientSecret: "azure-secret", + ClientSecret: utils.Ptr("azure-secret"), RedirectUrl: utils.Ptr("azure-redirect"), }, Type: dremioSdk.AUTHENTICATIONTYPE_AZUREAD, @@ -424,7 +422,7 @@ func TestToUpdatePayload(t *testing.T) { Oauth: &dremioSdk.Oauth{ AuthorityUrl: "oauth-authority", ClientId: "oauth-client", - ClientSecret: "oauth-secret", + ClientSecret: utils.Ptr("oauth-secret"), JwtClaims: dremioSdk.OauthJwtClaims{ UserName: "oauth-username", }, @@ -464,7 +462,7 @@ func TestToUpdatePayload(t *testing.T) { Azuread: &dremioSdk.Azuread{ AuthorityUrl: "azure-authority", ClientId: "azure-client", - ClientSecret: "azure-secret", + ClientSecret: utils.Ptr("azure-secret"), RedirectUrl: utils.Ptr("azure-redirect"), }, Type: dremioSdk.AUTHENTICATIONTYPE_AZUREAD, From 3d7238a1de0561e08b9b0b0c4e292c13cfb742c7 Mon Sep 17 00:00:00 2001 From: Robert Savu Date: Fri, 10 Jul 2026 17:58:25 +0200 Subject: [PATCH 2/6] fix(dremio): resolve runtime validation failure for oauth/azuread client_secret - Fixes the runtime validation failure where apply fails with inconsistent values for sensitive attribute under the authentication block. --- .../services/dremio/dremio_acc_test.go | 14 +++--- .../services/dremio/instance/resource.go | 45 ++++++++++--------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/stackit/internal/services/dremio/dremio_acc_test.go b/stackit/internal/services/dremio/dremio_acc_test.go index 339a51fb9..c2660ea7b 100644 --- a/stackit/internal/services/dremio/dremio_acc_test.go +++ b/stackit/internal/services/dremio/dremio_acc_test.go @@ -26,11 +26,15 @@ var resourceDremioInstanceMin string //go:embed testdata/resource-max.tf var resourceDremioInstanceMax string -const dremioInstanceResource = "stackit_dremio_instance.example" -const dremioInstanceDataResource = "data.stackit_dremio_instance.example" +const ( + dremioInstanceResource = "stackit_dremio_instance.example" + dremioInstanceDataResource = "data.stackit_dremio_instance.example" +) -const dremioUserResource = "stackit_dremio_user.example" -const dremioUserDataResource = "data.stackit_dremio_user.example" +const ( + dremioUserResource = "stackit_dremio_user.example" + dremioUserDataResource = "data.stackit_dremio_user.example" +) var testDremioConfigVarsMin = config.Variables{ "project_id": config.StringVariable(testutil.ProjectId), @@ -285,7 +289,6 @@ func TestAccDremioInstanceMax(t *testing.T) { resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.authority_url", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_authority_url"])), resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.client_id", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_client_id"])), - resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.client_secret", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_client_secret"])), resource.TestCheckResourceAttrSet(dremioInstanceResource, "authentication.oauth.redirect_url"), resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.jwt_claims.user_name", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_client_jwt_claims_user_name"])), resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.scope", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_scope"])), @@ -432,6 +435,7 @@ func TestAccDremioInstanceMax(t *testing.T) { return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, testutil.Region, instanceId), nil }, + ImportStateVerifyIgnore: []string{"authentication.oauth.client_secret"}, }, { ConfigVariables: testDremioConfigVarsMax, diff --git a/stackit/internal/services/dremio/instance/resource.go b/stackit/internal/services/dremio/instance/resource.go index 85f09b0c2..c6f484c6c 100644 --- a/stackit/internal/services/dremio/instance/resource.go +++ b/stackit/internal/services/dremio/instance/resource.go @@ -708,33 +708,39 @@ func mapAuthentication(instanceResp *dremioSdk.DremioResponse, model *Model) err return fmt.Errorf("model input is nil") } - authModel := AuthenticationModel{ - Type: types.StringValue(string(instanceResp.Authentication.Type)), + if model.Authentication == nil { + model.Authentication = new(AuthenticationModel) } + model.Authentication.Type = types.StringValue(string(instanceResp.Authentication.Type)) + if instanceResp.Authentication.Azuread != nil { - azureADResp := instanceResp.Authentication.Azuread - authModel.AzureAD = &AzureADModel{ - AuthorityUrl: types.StringValue(azureADResp.AuthorityUrl), - ClientId: types.StringValue(azureADResp.ClientId), - ClientSecret: types.StringNull(), - RedirectUrl: types.StringPointerValue(azureADResp.RedirectUrl), + if model.Authentication.AzureAD == nil { + model.Authentication.AzureAD = new(AzureADModel) } + + azureADResp := instanceResp.Authentication.Azuread + azureADModel := model.Authentication.AzureAD + + azureADModel.AuthorityUrl = types.StringValue(azureADResp.AuthorityUrl) + azureADModel.ClientId = types.StringValue(azureADResp.ClientId) + azureADModel.RedirectUrl = types.StringValue(*azureADResp.RedirectUrl) } if instanceResp.Authentication.Oauth != nil { - oauthResp := instanceResp.Authentication.Oauth - oauthModel := &OAuthModel{ - AuthorityUrl: types.StringValue(oauthResp.AuthorityUrl), - ClientId: types.StringValue(oauthResp.ClientId), - ClientSecret: types.StringNull(), - Scope: types.StringPointerValue(oauthResp.Scope), - RedirectUrl: types.StringPointerValue(oauthResp.RedirectUrl), - JwtClaims: &JwtClaimsModel{ - UserName: types.StringValue(oauthResp.JwtClaims.UserName), - }, + if model.Authentication.OAuth == nil { + model.Authentication.OAuth = new(OAuthModel) } + oauthResp := instanceResp.Authentication.Oauth + oauthModel := model.Authentication.OAuth + + oauthModel.AuthorityUrl = types.StringValue(oauthResp.AuthorityUrl) + oauthModel.ClientId = types.StringValue(oauthResp.ClientId) + oauthModel.Scope = types.StringPointerValue(oauthResp.Scope) + oauthModel.RedirectUrl = types.StringPointerValue(oauthResp.RedirectUrl) + oauthModel.JwtClaims = &JwtClaimsModel{UserName: types.StringValue(oauthResp.JwtClaims.UserName)} + if len(oauthResp.Parameters) > 0 { var params []AuthParameterModel for _, p := range oauthResp.Parameters { @@ -746,11 +752,8 @@ func mapAuthentication(instanceResp *dremioSdk.DremioResponse, model *Model) err oauthModel.Parameters = params } - authModel.OAuth = oauthModel } - model.Authentication = &authModel - return nil } From 170411214db2d5bc0ff89e32cca8821fdf79f2f3 Mon Sep 17 00:00:00 2001 From: Robert Savu Date: Mon, 13 Jul 2026 14:39:58 +0200 Subject: [PATCH 3/6] feat(dremio): remove client_secret from dremio data source auth config blocks --- .../services/dremio/instance/datasource.go | 115 +++++++++- .../services/dremio/instance/resource.go | 60 +++-- .../services/dremio/instance/resource_test.go | 206 +++++++++++------- 3 files changed, 253 insertions(+), 128 deletions(-) diff --git a/stackit/internal/services/dremio/instance/datasource.go b/stackit/internal/services/dremio/instance/datasource.go index cd0d2c18c..22cf185f6 100644 --- a/stackit/internal/services/dremio/instance/datasource.go +++ b/stackit/internal/services/dremio/instance/datasource.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" @@ -26,6 +27,40 @@ var ( type InstanceDataSourceModel struct { Model + + Authentication *AuthenticationDatasourceModel `tfsdk:"authentication"` +} + +// AuthenticationModel maps the nested authentication block. +type AuthenticationDatasourceModel struct { + // Required Fields + Type types.String `tfsdk:"type"` + + // Optional Fields + AzureAD *AzureADDatasourceModel `tfsdk:"azuread"` + OAuth *OAuthDatasourceModel `tfsdk:"oauth"` +} + +type AzureADDatasourceModel struct { + // Required Fields + AuthorityUrl types.String `tfsdk:"authority_url"` + ClientId types.String `tfsdk:"client_id"` + + RedirectUrl types.String `tfsdk:"redirect_url"` +} + +type OAuthDatasourceModel struct { + // Required Fields + AuthorityUrl types.String `tfsdk:"authority_url"` + ClientId types.String `tfsdk:"client_id"` + JwtClaims *JwtClaimsModel `tfsdk:"jwt_claims"` + + // Optional Fields + Scope types.String `tfsdk:"scope"` + Parameters []AuthParameterModel `tfsdk:"parameters"` + + // Read-only Fields + RedirectUrl types.String `tfsdk:"redirect_url"` } type instanceDataSource struct { @@ -64,6 +99,74 @@ func (d *instanceDataSource) Configure(ctx context.Context, req datasource.Confi tflog.Info(ctx, "Dremio instance client configured for data source") } +func mapDatasourceFields(instanceResp *dremioSdk.DremioResponse, model *InstanceDataSourceModel, region string) error { + if instanceResp == nil { + return fmt.Errorf("response input is nil") + } + if model == nil { + return fmt.Errorf("model input is nil") + } + + err := mapModelFields(instanceResp, &model.Model, region) + if err != nil { + return fmt.Errorf("failed to map Model fields") + } + + if model.Authentication == nil { + model.Authentication = new(AuthenticationDatasourceModel) + } + err = mapDatasourceAuthentication(instanceResp, model.Authentication) + if err != nil { + return fmt.Errorf("failed to map Authentication fields") + } + + return nil +} + +func mapDatasourceAuthentication(instanceResp *dremioSdk.DremioResponse, auth *AuthenticationDatasourceModel) error { + auth.Type = types.StringValue(string(instanceResp.Authentication.Type)) + + if instanceResp.Authentication.Azuread != nil { + if auth.AzureAD == nil { + auth.AzureAD = new(AzureADDatasourceModel) + } + + azureADResp := instanceResp.Authentication.Azuread + azureADModel := auth.AzureAD + + azureADModel.AuthorityUrl = types.StringValue(azureADResp.AuthorityUrl) + azureADModel.ClientId = types.StringValue(azureADResp.ClientId) + azureADModel.RedirectUrl = types.StringPointerValue(azureADResp.RedirectUrl) + } + + if instanceResp.Authentication.Oauth != nil { + if auth.OAuth == nil { + auth.OAuth = new(OAuthDatasourceModel) + } + oauthResp := instanceResp.Authentication.Oauth + oauthModel := auth.OAuth + + oauthModel.AuthorityUrl = types.StringValue(oauthResp.AuthorityUrl) + oauthModel.ClientId = types.StringValue(oauthResp.ClientId) + oauthModel.Scope = types.StringPointerValue(oauthResp.Scope) + oauthModel.RedirectUrl = types.StringPointerValue(oauthResp.RedirectUrl) + oauthModel.JwtClaims = &JwtClaimsModel{UserName: types.StringValue(oauthResp.JwtClaims.UserName)} + + if len(oauthResp.Parameters) > 0 { + var params []AuthParameterModel + for _, p := range oauthResp.Parameters { + params = append(params, AuthParameterModel{ + Name: types.StringValue(p.Name), + Value: types.StringValue(p.Value), + }) + } + oauthModel.Parameters = params + } + } + + return nil +} + // Schema should return the schema for this data source. func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ @@ -133,11 +236,6 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques Description: descriptions["azuread_client_id"], Computed: true, }, - "client_secret": schema.StringAttribute{ - Description: descriptions["azuread_client_secret"], - Computed: true, - Sensitive: true, - }, "redirect_url": schema.StringAttribute{ Description: descriptions["azuread_redirect_url"], Computed: true, @@ -157,11 +255,6 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques Description: descriptions["oauth_client_id"], Computed: true, }, - "client_secret": schema.StringAttribute{ - Description: descriptions["oauth_client_secret"], - Computed: true, - Sensitive: true, - }, "scope": schema.StringAttribute{ Description: descriptions["oauth_scope"], Optional: true, @@ -244,7 +337,7 @@ func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques ctx = core.LogResponse(ctx) - err = mapFields(instanceResp, &model.Model, region) + err = mapDatasourceFields(instanceResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading Dremio instance", fmt.Sprintf("Processing API payload: %v", err)) return diff --git a/stackit/internal/services/dremio/instance/resource.go b/stackit/internal/services/dremio/instance/resource.go index c6f484c6c..ace8e61d5 100644 --- a/stackit/internal/services/dremio/instance/resource.go +++ b/stackit/internal/services/dremio/instance/resource.go @@ -47,8 +47,7 @@ type Model struct { InstanceId types.String `tfsdk:"instance_id"` // Required Fields - DisplayName types.String `tfsdk:"display_name"` - Authentication *AuthenticationModel `tfsdk:"authentication"` + DisplayName types.String `tfsdk:"display_name"` // Optional Fields Description types.String `tfsdk:"description"` @@ -61,7 +60,8 @@ type Model struct { type InstanceModel struct { Model - Timeouts timeouts.Value `tfsdk:"timeouts"` + Authentication *AuthenticationModel `tfsdk:"authentication"` + Timeouts timeouts.Value `tfsdk:"timeouts"` } // AuthenticationModel maps the nested authentication block. @@ -413,7 +413,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques ctx = tflog.SetField(ctx, "region", region) // prepare the payload struct for the create instance request - payload, err := toCreatePayload(&model.Model) + payload, err := toCreatePayload(&model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Creating API payload: %v", err)) return @@ -447,7 +447,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - err = mapFields(instanceResp, &model.Model, region) + err = mapFields(instanceResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating Dremio instance", fmt.Sprintf("Processing API payload: %v", err)) return @@ -500,7 +500,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r ctx = core.LogResponse(ctx) - err = mapFields(instanceResp, &model.Model, region) + err = mapFields(instanceResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading dremio instance", fmt.Sprintf("Processing API payload: %v", err)) return @@ -537,7 +537,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "region", region) - payload, err := toUpdatePayload(&model.Model) + payload, err := toUpdatePayload(&model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return @@ -571,7 +571,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - err = mapFields(instanceResp, &model.Model, region) + err = mapFields(instanceResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating Dremio instance", fmt.Sprintf("Processing API payload: %v", err)) return @@ -649,7 +649,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS tflog.Info(ctx, "Dremio instance state imported") } -func mapFields(instanceResp *dremioSdk.DremioResponse, model *Model, region string) error { +func mapFields(instanceResp *dremioSdk.DremioResponse, model *InstanceModel, region string) error { if instanceResp == nil { return fmt.Errorf("response input is nil") } @@ -657,11 +657,15 @@ func mapFields(instanceResp *dremioSdk.DremioResponse, model *Model, region stri return fmt.Errorf("model input is nil") } - err := mapModelFields(instanceResp, model, region) + err := mapModelFields(instanceResp, &model.Model, region) if err != nil { return fmt.Errorf("failed to map Model fields") } - err = mapAuthentication(instanceResp, model) + + if model.Authentication == nil { + model.Authentication = new(AuthenticationModel) + } + err = mapAuthentication(instanceResp, model.Authentication) if err != nil { return fmt.Errorf("failed to map Authentication fields") } @@ -703,37 +707,28 @@ func mapModelFields(instanceResp *dremioSdk.DremioResponse, model *Model, region return nil } -func mapAuthentication(instanceResp *dremioSdk.DremioResponse, model *Model) error { - if model == nil { - return fmt.Errorf("model input is nil") - } - - if model.Authentication == nil { - model.Authentication = new(AuthenticationModel) - } - - model.Authentication.Type = types.StringValue(string(instanceResp.Authentication.Type)) +func mapAuthentication(instanceResp *dremioSdk.DremioResponse, auth *AuthenticationModel) error { + auth.Type = types.StringValue(string(instanceResp.Authentication.Type)) if instanceResp.Authentication.Azuread != nil { - if model.Authentication.AzureAD == nil { - model.Authentication.AzureAD = new(AzureADModel) + if auth.AzureAD == nil { + auth.AzureAD = new(AzureADModel) } azureADResp := instanceResp.Authentication.Azuread - azureADModel := model.Authentication.AzureAD + azureADModel := auth.AzureAD azureADModel.AuthorityUrl = types.StringValue(azureADResp.AuthorityUrl) azureADModel.ClientId = types.StringValue(azureADResp.ClientId) - azureADModel.RedirectUrl = types.StringValue(*azureADResp.RedirectUrl) + azureADModel.RedirectUrl = types.StringPointerValue(azureADResp.RedirectUrl) } if instanceResp.Authentication.Oauth != nil { - if model.Authentication.OAuth == nil { - model.Authentication.OAuth = new(OAuthModel) + if auth.OAuth == nil { + auth.OAuth = new(OAuthModel) } - oauthResp := instanceResp.Authentication.Oauth - oauthModel := model.Authentication.OAuth + oauthModel := auth.OAuth oauthModel.AuthorityUrl = types.StringValue(oauthResp.AuthorityUrl) oauthModel.ClientId = types.StringValue(oauthResp.ClientId) @@ -751,14 +746,13 @@ func mapAuthentication(instanceResp *dremioSdk.DremioResponse, model *Model) err } oauthModel.Parameters = params } - } return nil } // Build UpdateDremioInstancePayload from provider's model -func toUpdatePayload(model *Model) (*dremioSdk.UpdateDremioInstancePayload, error) { +func toUpdatePayload(model *InstanceModel) (*dremioSdk.UpdateDremioInstancePayload, error) { if model == nil { return nil, fmt.Errorf("nil model") } @@ -776,7 +770,7 @@ func toUpdatePayload(model *Model) (*dremioSdk.UpdateDremioInstancePayload, erro } // Build CreateDremioInstancePayload from provider's model -func toCreatePayload(model *Model) (*dremioSdk.CreateDremioInstancePayload, error) { +func toCreatePayload(model *InstanceModel) (*dremioSdk.CreateDremioInstancePayload, error) { if model == nil { return nil, fmt.Errorf("nil model") } @@ -793,7 +787,7 @@ func toCreatePayload(model *Model) (*dremioSdk.CreateDremioInstancePayload, erro }, nil } -func parseAuthentication(model *Model) (*dremioSdk.Authentication, error) { +func parseAuthentication(model *InstanceModel) (*dremioSdk.Authentication, error) { // API only saves the block of the stated type. The other one is omitted. // Keeping the block in TF leads to inconsistent state. Therefore we have // make sure the type matches the existing block. diff --git a/stackit/internal/services/dremio/instance/resource_test.go b/stackit/internal/services/dremio/instance/resource_test.go index 7b03b80dd..1d23bf13a 100644 --- a/stackit/internal/services/dremio/instance/resource_test.go +++ b/stackit/internal/services/dremio/instance/resource_test.go @@ -16,16 +16,18 @@ func TestMapFields(t *testing.T) { instanceId := uuid.New().String() tests := []struct { description string - state *Model + state *InstanceModel input *dremioSdk.DremioResponse - expected *Model + expected *InstanceModel wantErr bool }{ { "all_fields_filled", - &Model{ - Region: types.StringValue("rid"), - ProjectId: types.StringValue("pid"), + &InstanceModel{ + Model: Model{ + Region: types.StringValue("rid"), + ProjectId: types.StringValue("pid"), + }, }, &dremioSdk.DremioResponse{ Id: instanceId, @@ -61,15 +63,30 @@ func TestMapFields(t *testing.T) { Ui: "ui", }, }, - &Model{ - Id: types.StringValue("pid,rid," + instanceId), + &InstanceModel{ + Model: Model{ + Id: types.StringValue("pid,rid," + instanceId), - ProjectId: types.StringValue("pid"), - Region: types.StringValue("rid"), - InstanceId: types.StringValue(instanceId), + ProjectId: types.StringValue("pid"), + Region: types.StringValue("rid"), + InstanceId: types.StringValue(instanceId), - DisplayName: types.StringValue("greatName"), - Description: types.StringValue("minimal-required-values"), + DisplayName: types.StringValue("greatName"), + Description: types.StringValue("minimal-required-values"), + + Endpoints: types.ObjectValueMust( + map[string]attr.Type{ + "arrow_flight": types.StringType, + "catalog": types.StringType, + "ui": types.StringType, + }, + map[string]attr.Value{ + "arrow_flight": types.StringValue("flight"), + "catalog": types.StringValue("catalog"), + "ui": types.StringValue("ui"), + }, + ), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ @@ -96,33 +113,24 @@ func TestMapFields(t *testing.T) { }, Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_LOCAL_ONLY)), }, - - Endpoints: types.ObjectValueMust( - map[string]attr.Type{ - "arrow_flight": types.StringType, - "catalog": types.StringType, - "ui": types.StringType, - }, - map[string]attr.Value{ - "arrow_flight": types.StringValue("flight"), - "catalog": types.StringValue("catalog"), - "ui": types.StringValue("ui"), - }, - ), }, false, }, { "nil response", - &Model{ - Region: types.StringValue("rid"), - ProjectId: types.StringValue("pid"), + &InstanceModel{ + Model: Model{ + Region: types.StringValue("rid"), + ProjectId: types.StringValue("pid"), + }, }, nil, - &Model{ - Id: types.StringValue("pid,rid,"), - ProjectId: types.StringValue("pid"), - Region: types.StringValue("rid"), + &InstanceModel{ + Model: Model{ + Id: types.StringValue("pid,rid,"), + ProjectId: types.StringValue("pid"), + Region: types.StringValue("rid"), + }, }, true, }, @@ -153,15 +161,17 @@ func TestMapFields(t *testing.T) { func TestToCreatePayload(t *testing.T) { tests := []struct { description string - state *Model + state *InstanceModel expected *dremioSdk.CreateDremioInstancePayload wantErr bool }{ { "success-local", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_LOCAL_ONLY)), }, @@ -177,9 +187,11 @@ func TestToCreatePayload(t *testing.T) { }, { "success-oauth", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ OAuth: &OAuthModel{ AuthorityUrl: types.StringValue("oauth-authority"), @@ -227,9 +239,11 @@ func TestToCreatePayload(t *testing.T) { }, { "success-azuread", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), @@ -257,9 +271,11 @@ func TestToCreatePayload(t *testing.T) { }, { "idp-config-mismatch-local", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), @@ -275,9 +291,11 @@ func TestToCreatePayload(t *testing.T) { }, { "idp-config-mismatch-oauth", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), @@ -293,9 +311,11 @@ func TestToCreatePayload(t *testing.T) { }, { "idp-config-mismatch-azuread", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_AZUREAD)), OAuth: &OAuthModel{ @@ -321,9 +341,11 @@ func TestToCreatePayload(t *testing.T) { }, { "missing-idp-config-oauth", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_OAUTH)), }, @@ -333,9 +355,11 @@ func TestToCreatePayload(t *testing.T) { }, { "missing-idp-config-azuread", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_AZUREAD)), }, @@ -370,15 +394,17 @@ func TestToCreatePayload(t *testing.T) { func TestToUpdatePayload(t *testing.T) { tests := []struct { description string - state *Model + state *InstanceModel expected *dremioSdk.UpdateDremioInstancePayload wantErr bool }{ { "success", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_LOCAL_ONLY)), }, @@ -394,9 +420,11 @@ func TestToUpdatePayload(t *testing.T) { }, { "success-oauth", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ OAuth: &OAuthModel{ AuthorityUrl: types.StringValue("oauth-authority"), @@ -444,9 +472,11 @@ func TestToUpdatePayload(t *testing.T) { }, { "success-azuread", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), @@ -474,9 +504,11 @@ func TestToUpdatePayload(t *testing.T) { }, { "idp-config-mismatch-local", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), @@ -492,9 +524,11 @@ func TestToUpdatePayload(t *testing.T) { }, { "idp-config-mismatch-oauth", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ AzureAD: &AzureADModel{ AuthorityUrl: types.StringValue("azure-authority"), @@ -510,9 +544,11 @@ func TestToUpdatePayload(t *testing.T) { }, { "idp-config-mismatch-azuread", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_AZUREAD)), OAuth: &OAuthModel{ @@ -538,9 +574,11 @@ func TestToUpdatePayload(t *testing.T) { }, { "missing-idp-config-oauth", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), + }, Authentication: &AuthenticationModel{ Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_OAUTH)), }, @@ -550,12 +588,12 @@ func TestToUpdatePayload(t *testing.T) { }, { "missing-idp-config-azuread", - &Model{ - Description: types.StringValue("test description"), - DisplayName: types.StringValue("displayName"), - Authentication: &AuthenticationModel{ - Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_AZUREAD)), + &InstanceModel{ + Model: Model{ + Description: types.StringValue("test description"), + DisplayName: types.StringValue("displayName"), }, + Authentication: &AuthenticationModel{Type: types.StringValue(string(dremioSdk.AUTHENTICATIONTYPE_AZUREAD))}, }, nil, true, From 81f933c31afd5e11b98705907dbe0f49bacc46e1 Mon Sep 17 00:00:00 2001 From: Robert Savu Date: Mon, 13 Jul 2026 15:11:47 +0200 Subject: [PATCH 4/6] feat(dremio): re-enable client_secret verification in acceptance test --- stackit/internal/services/dremio/dremio_acc_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/stackit/internal/services/dremio/dremio_acc_test.go b/stackit/internal/services/dremio/dremio_acc_test.go index c2660ea7b..7bd640bb0 100644 --- a/stackit/internal/services/dremio/dremio_acc_test.go +++ b/stackit/internal/services/dremio/dremio_acc_test.go @@ -289,6 +289,7 @@ func TestAccDremioInstanceMax(t *testing.T) { resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.authority_url", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_authority_url"])), resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.client_id", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_client_id"])), + resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.client_secret", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_client_secret"])), resource.TestCheckResourceAttrSet(dremioInstanceResource, "authentication.oauth.redirect_url"), resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.jwt_claims.user_name", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_client_jwt_claims_user_name"])), resource.TestCheckResourceAttr(dremioInstanceResource, "authentication.oauth.scope", testutil.ConvertConfigVariable(testDremioConfigVarsMax["authentication_oauth_scope"])), From 9665c54a14a302960bc187d83a1dd0a3b82f05ea Mon Sep 17 00:00:00 2001 From: Robert Savu Date: Tue, 14 Jul 2026 09:45:38 +0200 Subject: [PATCH 5/6] feat(dremio): add nil check for mapAuthentication and mapDatasourceAuthentication inputs --- stackit/internal/services/dremio/instance/datasource.go | 7 +++++++ stackit/internal/services/dremio/instance/resource.go | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/stackit/internal/services/dremio/instance/datasource.go b/stackit/internal/services/dremio/instance/datasource.go index 22cf185f6..5d30aa75b 100644 --- a/stackit/internal/services/dremio/instance/datasource.go +++ b/stackit/internal/services/dremio/instance/datasource.go @@ -124,6 +124,13 @@ func mapDatasourceFields(instanceResp *dremioSdk.DremioResponse, model *Instance } func mapDatasourceAuthentication(instanceResp *dremioSdk.DremioResponse, auth *AuthenticationDatasourceModel) error { + if instanceResp == nil { + return fmt.Errorf("response input is nil") + } + if auth == nil { + return fmt.Errorf("auth input is nil") + } + auth.Type = types.StringValue(string(instanceResp.Authentication.Type)) if instanceResp.Authentication.Azuread != nil { diff --git a/stackit/internal/services/dremio/instance/resource.go b/stackit/internal/services/dremio/instance/resource.go index ace8e61d5..ceb11cd1f 100644 --- a/stackit/internal/services/dremio/instance/resource.go +++ b/stackit/internal/services/dremio/instance/resource.go @@ -708,6 +708,13 @@ func mapModelFields(instanceResp *dremioSdk.DremioResponse, model *Model, region } func mapAuthentication(instanceResp *dremioSdk.DremioResponse, auth *AuthenticationModel) error { + if instanceResp == nil { + return fmt.Errorf("response input is nil") + } + if auth == nil { + return fmt.Errorf("auth input is nil") + } + auth.Type = types.StringValue(string(instanceResp.Authentication.Type)) if instanceResp.Authentication.Azuread != nil { From 86599c0ae0ed48317a286137bcd7829974d6f4c5 Mon Sep 17 00:00:00 2001 From: Robert Savu Date: Tue, 14 Jul 2026 09:47:28 +0200 Subject: [PATCH 6/6] feat(dremio): generate docs --- docs/data-sources/dremio_instance.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/data-sources/dremio_instance.md b/docs/data-sources/dremio_instance.md index afa80edf6..c6f3270da 100644 --- a/docs/data-sources/dremio_instance.md +++ b/docs/data-sources/dremio_instance.md @@ -62,7 +62,6 @@ Read-Only: - `authority_url` (String) The Azure AD authority URL. - `client_id` (String) The Azure AD client ID. -- `client_secret` (String, Sensitive) The Azure AD client secret. - `redirect_url` (String) The Azure AD redirect URL. @@ -78,7 +77,6 @@ Read-Only: - `authority_url` (String) The Issuer location URI, where the OIDC provider configuration can be found. - `client_id` (String) The client ID assigned by the Identity Provider. -- `client_secret` (String, Sensitive) The client secret generated by the Identity Provider. - `jwt_claims` (Attributes) Maps fields from the JWT token to fields Dremio requires. (see [below for nested schema](#nestedatt--authentication--oauth--jwt_claims)) - `redirect_url` (String) The URL where the Dremio instance is hosted. The URL must match the redirect URL set in the Identity Provider.