diff --git a/sysdig/common.go b/sysdig/common.go index ea2f54d1..8b309470 100644 --- a/sysdig/common.go +++ b/sysdig/common.go @@ -59,4 +59,5 @@ const ( SchemaCloudProviderType = "provider_type" SchemaFeature = "feature" SchemaManagementAccountId = "management_account_id" + SchemaOrganizationIDKey = "organization_id" ) diff --git a/sysdig/resource_sysdig_secure_cloud_auth_account.go b/sysdig/resource_sysdig_secure_cloud_auth_account.go index 98a345bc..a753e9f8 100644 --- a/sysdig/resource_sysdig_secure_cloud_auth_account.go +++ b/sysdig/resource_sysdig_secure_cloud_auth_account.go @@ -4,6 +4,7 @@ import ( "context" b64 "encoding/base64" "encoding/json" + "errors" "fmt" "reflect" "strings" @@ -153,6 +154,10 @@ func resourceSysdigSecureCloudauthAccount() *schema.Resource { Optional: true, Elem: accountComponents, }, + SchemaOrganizationIDKey: { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -173,6 +178,7 @@ func resourceSysdigSecureCloudauthAccountCreate(ctx context.Context, data *schem } data.SetId(cloudauthAccount.Id) + data.Set(SchemaOrganizationIDKey, cloudauthAccount.OrganizationId) return nil } @@ -206,8 +212,23 @@ func resourceSysdigSecureCloudauthAccountUpdate(ctx context.Context, data *schem return diag.FromErr(err) } - _, errStatus, err := client.UpdateCloudauthAccountSecure(ctx, data.Id(), cloudauthAccountFromResourceData(data)) + existingCloudAccount, errStatus, err := client.GetCloudauthAccountSecure(ctx, data.Id()) + if err != nil { + if strings.Contains(errStatus, "404") { + return nil + } + return diag.FromErr(err) + } + + newCloudAccount := cloudauthAccountFromResourceData(data) + + // validate and reject non-updatable resource schema fields upfront + err = validateCloudauthAccountUpdate(existingCloudAccount, newCloudAccount) + if err != nil { + return diag.FromErr(err) + } + _, errStatus, err = client.UpdateCloudauthAccountSecure(ctx, data.Id(), newCloudAccount) if err != nil { if strings.Contains(errStatus, "404") { return nil @@ -236,6 +257,19 @@ func resourceSysdigSecureCloudauthAccountDelete(ctx context.Context, data *schem return nil } +/* +This function validates and restricts any fields not allowed to be updated during resource updates. +*/ +func validateCloudauthAccountUpdate(existingCloudAccount *v2.CloudauthAccountSecure, newCloudAccount *v2.CloudauthAccountSecure) error { + if existingCloudAccount.Enabled != newCloudAccount.Enabled || existingCloudAccount.Provider != newCloudAccount.Provider || + existingCloudAccount.ProviderId != newCloudAccount.ProviderId || existingCloudAccount.OrganizationId != newCloudAccount.OrganizationId { + errorInvalidResourceUpdate := fmt.Sprintf("Bad Request. Updating restricted fields not allowed: %s", []string{"enabled", "provider_type", "provider_id", "organization_id"}) + return errors.New(errorInvalidResourceUpdate) + } + + return nil +} + /* This function converts a schema set to map for iteration. */ @@ -439,11 +473,12 @@ func cloudauthAccountFromResourceData(data *schema.ResourceData) *v2.CloudauthAc return &v2.CloudauthAccountSecure{ CloudAccount: cloudauth.CloudAccount{ - Enabled: data.Get(SchemaEnabled).(bool), - ProviderId: data.Get(SchemaCloudProviderId).(string), - Provider: cloudauth.Provider(cloudauth.Provider_value[data.Get(SchemaCloudProviderType).(string)]), - Components: accountComponents, - Feature: accountFeatures, + Enabled: data.Get(SchemaEnabled).(bool), + OrganizationId: data.Get(SchemaOrganizationIDKey).(string), + ProviderId: data.Get(SchemaCloudProviderId).(string), + Provider: cloudauth.Provider(cloudauth.Provider_value[data.Get(SchemaCloudProviderType).(string)]), + Components: accountComponents, + Feature: accountFeatures, }, } } @@ -498,6 +533,19 @@ func featureToResourceData(features *cloudauth.AccountFeatures) []interface{} { return nil } +func componentsToResourceData(components []*cloudauth.AccountComponent) []map[string]interface{} { + componentsList := []map[string]interface{}{} + + for _, comp := range components { + componentsList = append(componentsList, map[string]interface{}{ + SchemaType: comp.Type.String(), + SchemaInstance: comp.Instance, + }) + } + + return componentsList +} + func cloudauthAccountToResourceData(data *schema.ResourceData, cloudAccount *v2.CloudauthAccountSecure) error { err := data.Set(SchemaIDKey, cloudAccount.Id) if err != nil { @@ -524,16 +572,12 @@ func cloudauthAccountToResourceData(data *schema.ResourceData, cloudAccount *v2. return err } - components := []map[string]interface{}{} - - for _, comp := range cloudAccount.Components { - components = append(components, map[string]interface{}{ - SchemaType: comp.Type.String(), - SchemaInstance: comp.Instance, - }) + err = data.Set(SchemaComponent, componentsToResourceData(cloudAccount.Components)) + if err != nil { + return err } - err = data.Set(SchemaComponent, components) + err = data.Set(SchemaOrganizationIDKey, cloudAccount.OrganizationId) if err != nil { return err } diff --git a/sysdig/resource_sysdig_secure_cloud_auth_account_test.go b/sysdig/resource_sysdig_secure_cloud_auth_account_test.go index 095cead4..3eb9f968 100644 --- a/sysdig/resource_sysdig_secure_cloud_auth_account_test.go +++ b/sysdig/resource_sysdig_secure_cloud_auth_account_test.go @@ -80,19 +80,6 @@ func TestAccSecureCloudAuthAccountFC(t *testing.T) { } func secureCloudAuthAccountWithFC(accountID string) string { - type sample_service_account_key struct { - ProjectId string `json:"project_id"` - PrivateKeyId string `json:"private_key_id"` - PrivateKey string `json:"private_key"` - } - test_service_account_key := &sample_service_account_key{ - ProjectId: fmt.Sprintf("sample-1-%s", accountID), - PrivateKeyId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", - PrivateKey: "-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----\n", - } - test_service_account_keyJSON, _ := json.Marshal(test_service_account_key) - test_service_account_key_encoded := b64.StdEncoding.EncodeToString([]byte(string(test_service_account_keyJSON))) - return fmt.Sprintf(` resource "sysdig_secure_cloud_auth_account" "sample-1" { provider_id = "sample-1-%s" @@ -121,5 +108,23 @@ resource "sysdig_secure_cloud_auth_account" "sample-1" { ignore_changes = [component] } } -`, accountID, test_service_account_key_encoded) +`, accountID, getEncodedServiceAccountKey("sample-1", accountID)) +} + +func getEncodedServiceAccountKey(resourceName string, accountID string) string { + type sample_service_account_key struct { + Type string `json:"type"` + ProjectId string `json:"project_id"` + PrivateKeyId string `json:"private_key_id"` + PrivateKey string `json:"private_key"` + } + test_service_account_key := &sample_service_account_key{ + Type: "service_account", + ProjectId: fmt.Sprintf("%s-%s", resourceName, accountID), + PrivateKeyId: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + PrivateKey: "-----BEGIN PRIVATE KEY-----\nxxxxxxxxxxxxxxxxxxxxxxxxxxx\n-----END PRIVATE KEY-----\n", + } + test_service_account_keyJSON, _ := json.Marshal(test_service_account_key) + test_service_account_key_encoded := b64.StdEncoding.EncodeToString([]byte(string(test_service_account_keyJSON))) + return test_service_account_key_encoded }