diff --git a/docs/resources/external_volume.md b/docs/resources/external_volume.md new file mode 100644 index 0000000000..3e9d24c8e9 --- /dev/null +++ b/docs/resources/external_volume.md @@ -0,0 +1,74 @@ +--- +page_title: "snowflake_external_volume Resource - terraform-provider-snowflake" +subcategory: "" +description: |- + Resource used to manage external volume objects. For more information, check external volume documentation https://docs.snowflake.com/en/sql-reference/commands-data-loading#external-volume. +--- + +# snowflake_external_volume (Resource) + +Resource used to manage external volume objects. For more information, check [external volume documentation](https://docs.snowflake.com/en/sql-reference/commands-data-loading#external-volume). + + + + +## Schema + +### Required + +- `name` (String) Identifier for the external volume; must be unique for your account. Due to technical limitations (read more [here](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/identifiers_rework_design_decisions.md#known-limitations-and-identifier-recommendations)), avoid using the following characters: `|`, `.`, `(`, `)`, `"` +- `storage_location` (Block List, Min: 1) List of named cloud storage locations in different regions and, optionally, cloud platforms. Minimum 1 required. Note that not all parameter combinations are valid as they depend on the given storage_provider. Consult [the docs](https://docs.snowflake.com/en/sql-reference/sql/create-external-volume#cloud-provider-parameters-cloudproviderparams) for more details on this. (see [below for nested schema](#nestedblock--storage_location)) + +### Optional + +- `allow_writes` (String) Specifies whether write operations are allowed for the external volume; must be set to TRUE for Iceberg tables that use Snowflake as the catalog. Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value. +- `comment` (String) Specifies a comment for the external volume. + +### Read-Only + +- `describe_output` (List of Object) Outputs the result of `DESCRIBE EXTERNAL VOLUME` for the given external volume. (see [below for nested schema](#nestedatt--describe_output)) +- `fully_qualified_name` (String) Fully qualified name of the resource. For more information, see [object name resolution](https://docs.snowflake.com/en/sql-reference/name-resolution). +- `id` (String) The ID of this resource. +- `show_output` (List of Object) Outputs the result of `SHOW EXTERNAL VOLUMES` for the given external volume. (see [below for nested schema](#nestedatt--show_output)) + + +### Nested Schema for `storage_location` + +Required: + +- `storage_base_url` (String) Specifies the base URL for your cloud storage location. +- `storage_location_name` (String) Name of the storage location. Must be unique for the external volume. +- `storage_provider` (String) Specifies the cloud storage provider that stores your data files. Valid values are (case-insensitive): `GCS` | `AZURE` | `S3` | `S3GOV`. + +Optional: + +- `azure_tenant_id` (String) Specifies the ID for your Office 365 tenant that the allowed and blocked storage accounts belong to. +- `encryption_kms_key_id` (String) Specifies the ID for the KMS-managed key used to encrypt files. +- `encryption_type` (String) Specifies the encryption type used. +- `storage_aws_role_arn` (String) Specifies the case-sensitive Amazon Resource Name (ARN) of the AWS identity and access management (IAM) role that grants privileges on the S3 bucket containing your data files. + +Read-Only: + +- `storage_aws_external_id` (String) External ID that Snowflake uses to establish a trust relationship with AWS. + + + +### Nested Schema for `describe_output` + +Read-Only: + +- `default` (String) +- `name` (String) +- `parent` (String) +- `type` (String) +- `value` (String) + + + +### Nested Schema for `show_output` + +Read-Only: + +- `allow_writes` (Boolean) +- `comment` (String) +- `name` (String) diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/external_volume_resource_ext.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/external_volume_resource_ext.go new file mode 100644 index 0000000000..411854a941 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/external_volume_resource_ext.go @@ -0,0 +1,12 @@ +package resourceassert + +import ( + "strconv" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" +) + +func (e *ExternalVolumeResourceAssert) HasStorageLocationLength(len int) *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueSet("storage_location.#", strconv.FormatInt(int64(len), 10))) + return e +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/external_volume_resource_gen.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/external_volume_resource_gen.go new file mode 100644 index 0000000000..2a7a71d6ba --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/external_volume_resource_gen.go @@ -0,0 +1,87 @@ +// Code generated by assertions generator; DO NOT EDIT. + +package resourceassert + +import ( + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" +) + +type ExternalVolumeResourceAssert struct { + *assert.ResourceAssert +} + +func ExternalVolumeResource(t *testing.T, name string) *ExternalVolumeResourceAssert { + t.Helper() + + return &ExternalVolumeResourceAssert{ + ResourceAssert: assert.NewResourceAssert(name, "resource"), + } +} + +func ImportedExternalVolumeResource(t *testing.T, id string) *ExternalVolumeResourceAssert { + t.Helper() + + return &ExternalVolumeResourceAssert{ + ResourceAssert: assert.NewImportedResourceAssert(id, "imported resource"), + } +} + +/////////////////////////////////// +// Attribute value string checks // +/////////////////////////////////// + +func (e *ExternalVolumeResourceAssert) HasAllowWritesString(expected string) *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueSet("allow_writes", expected)) + return e +} + +func (e *ExternalVolumeResourceAssert) HasCommentString(expected string) *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueSet("comment", expected)) + return e +} + +func (e *ExternalVolumeResourceAssert) HasFullyQualifiedNameString(expected string) *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueSet("fully_qualified_name", expected)) + return e +} + +func (e *ExternalVolumeResourceAssert) HasNameString(expected string) *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueSet("name", expected)) + return e +} + +func (e *ExternalVolumeResourceAssert) HasStorageLocationString(expected string) *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueSet("storage_location", expected)) + return e +} + +//////////////////////////// +// Attribute empty checks // +//////////////////////////// + +func (e *ExternalVolumeResourceAssert) HasNoAllowWrites() *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueNotSet("allow_writes")) + return e +} + +func (e *ExternalVolumeResourceAssert) HasNoComment() *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueNotSet("comment")) + return e +} + +func (e *ExternalVolumeResourceAssert) HasNoFullyQualifiedName() *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueNotSet("fully_qualified_name")) + return e +} + +func (e *ExternalVolumeResourceAssert) HasNoName() *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueNotSet("name")) + return e +} + +func (e *ExternalVolumeResourceAssert) HasNoStorageLocation() *ExternalVolumeResourceAssert { + e.AddAssertion(assert.ValueNotSet("storage_location")) + return e +} diff --git a/pkg/acceptance/check_destroy.go b/pkg/acceptance/check_destroy.go index 0001f75795..e7102a8b18 100644 --- a/pkg/acceptance/check_destroy.go +++ b/pkg/acceptance/check_destroy.go @@ -113,6 +113,9 @@ var showByIdFunctions = map[resources.Resource]showByIdFunc{ resources.ExternalTable: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { return runShowById(ctx, id, client.ExternalTables.ShowByID) }, + resources.ExternalVolume: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { + return runShowById(ctx, id, client.ExternalVolumes.ShowByID) + }, resources.FailoverGroup: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error { return runShowById(ctx, id, client.FailoverGroups.ShowByID) }, diff --git a/pkg/acceptance/helpers/external_volume_client.go b/pkg/acceptance/helpers/external_volume_client.go index 415f7bea0c..621bf364a1 100644 --- a/pkg/acceptance/helpers/external_volume_client.go +++ b/pkg/acceptance/helpers/external_volume_client.go @@ -2,7 +2,6 @@ package helpers import ( "context" - "fmt" "testing" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" @@ -21,39 +20,56 @@ func NewExternalVolumeClient(context *TestClientContext, idsGenerator *IdsGenera } } -func (c *ExternalVolumeClient) exec(sql string) error { - ctx := context.Background() - _, err := c.context.client.ExecForTests(ctx, sql) - return err +func (c *ExternalVolumeClient) client() sdk.ExternalVolumes { + return c.context.client.ExternalVolumes } -// TODO(SNOW-999142): Use SDK implementation for External Volume once it's available +// TODO switch to returning *sdk.ExternalVolume +// need to update existing acceptance tests for this func (c *ExternalVolumeClient) Create(t *testing.T) (sdk.AccountObjectIdentifier, func()) { t.Helper() + ctx := context.Background() + id := c.ids.RandomAccountObjectIdentifier() - err := c.exec(fmt.Sprintf(` -create external volume %s - storage_locations = - ( - ( - name = 'my-s3-us-west-2' - storage_provider = 's3' - storage_base_url = 's3://my_example_bucket/' - storage_aws_role_arn = 'arn:aws:iam::123456789012:role/myrole' - encryption=(type='aws_sse_kms' kms_key_id='1234abcd-12ab-34cd-56ef-1234567890ab') - ) - ); -`, id.FullyQualifiedName())) + kmsKeyId := "1234abcd-12ab-34cd-56ef-1234567890ab" + storageLocations := []sdk.ExternalVolumeStorageLocation{ + { + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: "my-s3-us-west-2", + StorageProvider: "S3", + StorageAwsRoleArn: "arn:aws:iam::123456789012:role/myrole", + StorageBaseUrl: "s3://my_example_bucket/", + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: "AWS_SSE_KMS", + KmsKeyId: &kmsKeyId, + }, + }, + }, + } + + req := sdk.NewCreateExternalVolumeRequest(id, storageLocations) + err := c.client().Create(ctx, req) require.NoError(t, err) + _, showErr := c.client().ShowByID(ctx, id) + require.NoError(t, showErr) + return id, c.DropFunc(t, id) } +func (c *ExternalVolumeClient) Alter(t *testing.T, req *sdk.AlterExternalVolumeRequest) { + t.Helper() + ctx := context.Background() + err := c.client().Alter(ctx, req) + require.NoError(t, err) +} + func (c *ExternalVolumeClient) DropFunc(t *testing.T, id sdk.AccountObjectIdentifier) func() { t.Helper() + ctx := context.Background() return func() { - err := c.exec(fmt.Sprintf(`drop external volume if exists %s`, id.FullyQualifiedName())) + err := c.client().Drop(ctx, sdk.NewDropExternalVolumeRequest(id).WithIfExists(true)) require.NoError(t, err) } } diff --git a/pkg/helpers/helpers.go b/pkg/helpers/helpers.go index 0c94f05585..c36cb1cc79 100644 --- a/pkg/helpers/helpers.go +++ b/pkg/helpers/helpers.go @@ -2,6 +2,7 @@ package helpers import ( "encoding/csv" + "encoding/json" "fmt" "log" "path" @@ -163,6 +164,247 @@ func ConcatSlices[T any](slices ...[]T) []T { return tmp } +// Structs for parsing external volume desribe output +type S3StorageLocation struct { + Name string `json:"NAME"` + StorageProvider string `json:"STORAGE_PROVIDER"` + StorageBaseUrl string `json:"STORAGE_BASE_URL"` + StorageAllowedLocations []string `json:"-"` + StorageAwsRoleArn string `json:"STORAGE_AWS_ROLE_ARN"` + StroageAwsIamUserArn string `json:"-"` + StorageAwsExternalId string `json:"STORAGE_AWS_EXTERNAL_ID"` + EncryptionType string `json:"ENCRYPTION_TYPE,omitempty"` + EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID,omitempty"` +} + +type GCSStorageLocation struct { + Name string `json:"NAME"` + StorageProvider string `json:"STORAGE_PROVIDER"` + StorageBaseUrl string `json:"STORAGE_BASE_URL"` + StorageAllowedLocations []string `json:"-"` + StorageGcpServiceAccount string `json:"-"` + EncryptionType string `json:"ENCRYPTION_TYPE,omitempty"` + EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID,omitempty"` +} + +type AzureStorageLocation struct { + Name string `json:"NAME"` + StorageProvider string `json:"STORAGE_PROVIDER"` + StorageBaseUrl string `json:"STORAGE_BASE_URL"` + StorageAllowedLocations []string `json:"-"` + AzureTenantId string `json:"AZURE_TENANT_ID"` + AzureMultiTenantAppName string `json:"-"` + AzureConsentUrl string `json:"-"` + EncryptionType string `json:"-"` + EncryptionKmsId string `json:"-"` +} + +type StorageLocation struct { + Name string `json:"NAME"` + StorageProvider string `json:"STORAGE_PROVIDER"` + StorageBaseUrl string `json:"STORAGE_BASE_URL"` + StorageAwsRoleArn string `json:"STORAGE_AWS_ROLE_ARN,omitempty"` + StorageAwsExternalId string `json:"STORAGE_AWS_EXTERNAL_ID,omitempty"` + EncryptionType string `json:"ENCRYPTION_TYPE,omitempty"` + EncryptionKmsKeyId string `json:"ENCRYPTION_KMS_KEY_ID,omitempty"` + AzureTenantId string `json:"AZURE_TENANT_ID,omitempty"` +} + +func storageLocationsEqual(s1 StorageLocation, s2 StorageLocation) bool { + return s1.Name == s2.Name && + s1.StorageProvider == s2.StorageProvider && + s1.StorageBaseUrl == s2.StorageBaseUrl && + s1.StorageAwsRoleArn == s2.StorageAwsRoleArn && + s1.StorageAwsExternalId == s2.StorageAwsExternalId && + s1.EncryptionType == s2.EncryptionType && + s1.EncryptionKmsKeyId == s2.EncryptionKmsKeyId && + s1.AzureTenantId == s2.AzureTenantId +} + +func validateParsedExternalVolumeDescribed(p ParsedExternalVolumeDescribed) error { + if len(p.StorageLocations) == 0 { + return fmt.Errorf("No storage locations could be parsed from the external volume.") + } + if len(p.AllowWrites) == 0 { + return fmt.Errorf("The external volume AllowWrites property could not be parsed.") + } + + for _, s := range p.StorageLocations { + if len(s.Name) == 0 { + return fmt.Errorf("A storage location's Name in this volume could not be parsed.") + } + if len(s.StorageProvider) == 0 { + return fmt.Errorf("A storage location's StorageProvider in this volume could not be parsed.") + } + if len(s.StorageBaseUrl) == 0 { + return fmt.Errorf("A storage location's StorageBaseUrl in this volume could not be parsed.") + } + + storageProvider, err := sdk.ToStorageProvider(s.StorageProvider) + if err != nil { + return err + } + + switch storageProvider { + case sdk.StorageProviderS3, sdk.StorageProviderS3GOV: + if len(s.StorageAwsRoleArn) == 0 { + return fmt.Errorf("An S3 storage location's StorageAwsRoleArn in this volume could not be parsed.") + } + case sdk.StorageProviderAzure: + if len(s.AzureTenantId) == 0 { + return fmt.Errorf("An Azure storage location's AzureTenantId in this volume could not be parsed.") + } + } + } + + return nil +} + +type ParsedExternalVolumeDescribed struct { + StorageLocations []StorageLocation + Active string + Comment string + AllowWrites string +} + +func ParsedExternalVolumesDescribedEqual(p1 ParsedExternalVolumeDescribed, p2 ParsedExternalVolumeDescribed) bool { + attributesEqual := p1.Active == p2.Active && p1.Comment == p2.Comment && p1.AllowWrites == p2.AllowWrites + if attributesEqual && (len(p1.StorageLocations) == len(p2.StorageLocations)) { + for i := range p1.StorageLocations { + if !storageLocationsEqual(p1.StorageLocations[i], p2.StorageLocations[i]) { + return false + } + } + + return true + } + return false +} + +func ParseExternalVolumeDescribed(props []sdk.ExternalVolumeProperty) (ParsedExternalVolumeDescribed, error) { + parsedExternalVolumeDescribed := ParsedExternalVolumeDescribed{} + var storageLocations []StorageLocation + for _, p := range props { + switch { + case p.Name == "COMMENT": + parsedExternalVolumeDescribed.Comment = p.Value + case p.Name == "ACTIVE": + parsedExternalVolumeDescribed.Active = p.Value + case p.Name == "ALLOW_WRITES": + parsedExternalVolumeDescribed.AllowWrites = p.Value + case strings.Contains(p.Name, "STORAGE_LOCATION_"): + switch { + case strings.Contains(p.Value, `"STORAGE_PROVIDER":"S3"`): + s3StorageLocation := S3StorageLocation{} + err := json.Unmarshal([]byte(p.Value), &s3StorageLocation) + if err != nil { + return ParsedExternalVolumeDescribed{}, err + } + storageLocation := StorageLocation{ + Name: s3StorageLocation.Name, + StorageProvider: s3StorageLocation.StorageProvider, + StorageBaseUrl: s3StorageLocation.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocation.StorageAwsRoleArn, + StorageAwsExternalId: s3StorageLocation.StorageAwsExternalId, + EncryptionType: s3StorageLocation.EncryptionType, + EncryptionKmsKeyId: s3StorageLocation.EncryptionKmsId, + } + storageLocations = append( + storageLocations, + storageLocation, + ) + case strings.Contains(p.Value, `"STORAGE_PROVIDER":"GCS"`): + gcsStorageLocation := GCSStorageLocation{} + err := json.Unmarshal([]byte(p.Value), &gcsStorageLocation) + if err != nil { + return ParsedExternalVolumeDescribed{}, err + } + + storageLocation := StorageLocation{ + Name: gcsStorageLocation.Name, + StorageProvider: gcsStorageLocation.StorageProvider, + StorageBaseUrl: gcsStorageLocation.StorageBaseUrl, + EncryptionType: gcsStorageLocation.EncryptionType, + EncryptionKmsKeyId: gcsStorageLocation.EncryptionKmsId, + } + storageLocations = append( + storageLocations, + storageLocation, + ) + case strings.Contains(p.Value, `"STORAGE_PROVIDER":"AZURE"`): + azureStorageLocation := AzureStorageLocation{} + err := json.Unmarshal([]byte(p.Value), &azureStorageLocation) + if err != nil { + return ParsedExternalVolumeDescribed{}, err + } + + storageLocation := StorageLocation{ + Name: azureStorageLocation.Name, + StorageProvider: azureStorageLocation.StorageProvider, + StorageBaseUrl: azureStorageLocation.StorageBaseUrl, + AzureTenantId: azureStorageLocation.AzureTenantId, + } + storageLocations = append( + storageLocations, + storageLocation, + ) + default: + return ParsedExternalVolumeDescribed{}, fmt.Errorf("Unrecognized storage provider in storage location property: %s", p.Value) + } + default: + return ParsedExternalVolumeDescribed{}, fmt.Errorf("Unrecognized external volume property: %s", p.Name) + } + } + + parsedExternalVolumeDescribed.StorageLocations = storageLocations + validated := validateParsedExternalVolumeDescribed(parsedExternalVolumeDescribed) + if validated != nil { + return ParsedExternalVolumeDescribed{}, validated + } + + return parsedExternalVolumeDescribed, nil +} + +// Generate input to the ParseExternalVolumeDescribedInput, useful for testing purposes +func GenerateParseExternalVolumeDescribedInput(comment string, allowWrites string, storageLocations []string, active string) []sdk.ExternalVolumeProperty { + storageLocationProperties := make([]sdk.ExternalVolumeProperty, len(storageLocations)) + allowWritesProperty := sdk.ExternalVolumeProperty{ + Parent: "", + Name: "ALLOW_WRITES", + Type: "Boolean", + Value: allowWrites, + Default: "true", + } + + commentProperty := sdk.ExternalVolumeProperty{ + Parent: "", + Name: "COMMENT", + Type: "String", + Value: comment, + Default: "", + } + + activeProperty := sdk.ExternalVolumeProperty{ + Parent: "STORAGE_LOCATIONS", + Name: "ACTIVE", + Type: "String", + Value: active, + Default: "", + } + + for i, property := range storageLocations { + storageLocationProperties[i] = sdk.ExternalVolumeProperty{ + Parent: "STORAGE_LOCATIONS", + Name: fmt.Sprintf("STORAGE_LOCATION_%s", strconv.Itoa(i+1)), + Type: "String", + Value: property, + Default: "", + } + } + + return append(append([]sdk.ExternalVolumeProperty{allowWritesProperty, commentProperty}, storageLocationProperties...), activeProperty) +} + // TODO(SNOW-1569530): address during identifiers rework follow-up func ParseRootLocation(location string) (sdk.SchemaObjectIdentifier, string, error) { location = strings.TrimPrefix(location, "@") diff --git a/pkg/helpers/helpers_test.go b/pkg/helpers/helpers_test.go index fac9ae1858..0d1c008502 100644 --- a/pkg/helpers/helpers_test.go +++ b/pkg/helpers/helpers_test.go @@ -387,3 +387,1080 @@ func Test_ContainsIdentifierIgnoreQuotes(t *testing.T) { }) } } + +// External volume helper tests + +var ( + allowWritesTrue = "true" + allowWritesFalse = "false" + comment = "some comment" +) + +var ( + azureStorageLocationName = "azureTest" + azureStorageProvider = "AZURE" + azureStorageBaseUrl = "azure://123456789.blob.core.windows.net/my_example_container" + azureTenantId = "123456789" +) + +var azureStorageLocationStandard = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["azure://123456789.blob.core.windows.net/my_example_container"],"AZURE_TENANT_ID":"%s","AZURE_MULTI_TENANT_APP_NAME":"test12","AZURE_CONSENT_URL":"https://login.microsoftonline.com/123456789/oauth2/authorize?client_id=test&response_type=test","ENCRYPTION_TYPE":"NONE","ENCRYPTION_KMS_KEY_ID":""}`, + azureStorageLocationName, + azureStorageProvider, + azureStorageBaseUrl, + azureTenantId, +) + +var azureStorageLocationWithExtraFields = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["azure://123456789.blob.core.windows.net/my_example_container"],"AZURE_TENANT_ID":"%s","AZURE_MULTI_TENANT_APP_NAME":"test12","AZURE_CONSENT_URL":"https://login.microsoftonline.com/123456789/oauth2/authorize?client_id=test&response_type=test","ENCRYPTION_TYPE":"NONE","ENCRYPTION_KMS_KEY_ID":"","EXTRA_FIELD_ONE":"testing","EXTRA_FIELD_TWO":"123456"}`, + azureStorageLocationName, + azureStorageProvider, + azureStorageBaseUrl, + azureTenantId, +) + +var azureStorageLocationMissingTenantId = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["azure://123456789.blob.core.windows.net/my_example_container"],"AZURE_MULTI_TENANT_APP_NAME":"test12","AZURE_CONSENT_URL":"https://login.microsoftonline.com/123456789/oauth2/authorize?client_id=test&response_type=test","ENCRYPTION_TYPE":"NONE","ENCRYPTION_KMS_KEY_ID":""}`, + azureStorageLocationName, + azureStorageProvider, + azureStorageBaseUrl, +) + +var ( + gcsStorageLocationName = "gcsTest" + gcsStorageProvider = "GCS" + gcsStorageBaseUrl = "gcs://my_example_bucket" + gcsEncryptionTypeNone = "NONE" + gcsEncryptionTypeSseKms = "GCS_SSE_KMS" + gcsEncryptionKmsKeyId = "123456789" +) + +var gcsStorageLocationStandard = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["gcs://my_example_bucket/*"],"STORAGE_GCP_SERVICE_ACCOUNT":"test@test.iam.test.com","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":""}`, + gcsStorageLocationName, + gcsStorageProvider, + gcsStorageBaseUrl, + gcsEncryptionTypeNone, +) + +var gcsStorageLocationWithExtraFields = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["gcs://my_example_bucket/*"],"STORAGE_GCP_SERVICE_ACCOUNT":"test@test.iam.test.com","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"","EXTRA_FIELD_ONE":"testing","EXTRA_FIELD_TWO":"123456"}`, + gcsStorageLocationName, + gcsStorageProvider, + gcsStorageBaseUrl, + gcsEncryptionTypeNone, +) + +var gcsStorageLocationKmsEncryption = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["gcs://my_example_bucket/*"],"STORAGE_GCP_SERVICE_ACCOUNT":"test@test.iam.test.com","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"%s"}`, + gcsStorageLocationName, + gcsStorageProvider, + gcsStorageBaseUrl, + gcsEncryptionTypeSseKms, + gcsEncryptionKmsKeyId, +) + +var gcsStorageLocationMissingBaseUrl = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_ALLOWED_LOCATIONS":["gcs://my_example_bucket/*"],"STORAGE_GCP_SERVICE_ACCOUNT":"test@test.iam.test.com","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":""}`, + gcsStorageLocationName, + gcsStorageProvider, + gcsEncryptionTypeNone, +) + +var ( + s3StorageLocationName = "s3Test" + s3StorageProvider = "S3" + s3StorageBaseUrl = "s3://my_example_bucket" + s3StorageAwsRoleArn = "arn:aws:iam::123456789012:role/myrole" + s3StorageAwsExternalId = "123456789" + s3EncryptionTypeNone = "NONE" + s3EncryptionTypeSseS3 = "AWS_SSE_S3" + s3EncryptionTypeSseKms = "AWS_SSE_KMS" + s3EncryptionKmsKeyId = "123456789" +) + +var s3StorageLocationStandard = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["s3://my_example_bucket/*"],"STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_IAM_USER_ARN":"arn:aws:iam::123456789:user/a11b0000-s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s"}`, + s3StorageLocationName, + s3StorageProvider, + s3StorageBaseUrl, + s3StorageAwsRoleArn, + s3StorageAwsExternalId, + s3EncryptionTypeNone, +) + +var s3StorageLocationWithExtraFields = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["s3://my_example_bucket/*"],"STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_IAM_USER_ARN":"arn:aws:iam::123456789:user/a11b0000-s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"%s","EXTRA_FIELD_ONE":"testing","EXTRA_FIELD_TWO":"123456"}`, + s3StorageLocationName, + s3StorageProvider, + s3StorageBaseUrl, + s3StorageAwsRoleArn, + s3StorageAwsExternalId, + s3EncryptionTypeSseKms, + s3EncryptionKmsKeyId, +) + +var s3StorageLocationSseS3Encryption = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["s3://my_example_bucket/*"],"STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_IAM_USER_ARN":"arn:aws:iam::123456789:user/a11b0000-s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s"}`, + s3StorageLocationName, + s3StorageProvider, + s3StorageBaseUrl, + s3StorageAwsRoleArn, + s3StorageAwsExternalId, + s3EncryptionTypeSseS3, +) + +var s3StorageLocationSseKmsEncryption = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["s3://my_example_bucket/*"],"STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_IAM_USER_ARN":"arn:aws:iam::123456789:user/a11b0000-s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s", "ENCRYPTION_KMS_KEY_ID":"%s"}`, + s3StorageLocationName, + s3StorageProvider, + s3StorageBaseUrl, + s3StorageAwsRoleArn, + s3StorageAwsExternalId, + s3EncryptionTypeSseKms, + s3EncryptionKmsKeyId, +) + +var s3StorageLocationMissingRoleArn = fmt.Sprintf( + `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_ALLOWED_LOCATIONS":["s3://my_example_bucket/*"],"STORAGE_AWS_IAM_USER_ARN":"arn:aws:iam::123456789:user/a11b0000-s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s"}`, + s3StorageLocationName, + s3StorageProvider, + s3StorageBaseUrl, + s3StorageAwsExternalId, + s3EncryptionTypeNone, +) + +func Test_ParsedExternalVolumesDescribedEqual(t *testing.T) { + equalCases := []struct { + Name string + ParsedVolumeA ParsedExternalVolumeDescribed + ParsedVolumeB ParsedExternalVolumeDescribed + }{ + { + Name: "All values matching", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + } + + notEqualCases := []struct { + Name string + ParsedVolumeA ParsedExternalVolumeDescribed + ParsedVolumeB ParsedExternalVolumeDescribed + }{ + { + Name: "Different Active", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "b", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Comment", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "b", + AllowWrites: "a", + }, + }, + { + Name: "Different AllowWrites", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "b", + }, + }, + { + Name: "Different Storage Location - Name", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "b", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - StorageProvider", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "b", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - StorageBaseUrl", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "b", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - StorageAwsRoleArn", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "b", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - StorageAwsExternalId", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "b", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - EncryptionType", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "b", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - EncryptionKmsKeyId", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "b", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + { + Name: "Different Storage Location - AzureTenantId", + ParsedVolumeA: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "a", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + ParsedVolumeB: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: "a", + StorageProvider: "a", + StorageBaseUrl: "a", + StorageAwsRoleArn: "a", + StorageAwsExternalId: "a", + EncryptionType: "a", + EncryptionKmsKeyId: "a", + AzureTenantId: "b", + }, + }, + Active: "a", + Comment: "a", + AllowWrites: "a", + }, + }, + } + + for _, tc := range equalCases { + t.Run(tc.Name, func(t *testing.T) { + assert.True(t, ParsedExternalVolumesDescribedEqual(tc.ParsedVolumeA, tc.ParsedVolumeB)) + }) + } + + for _, tc := range notEqualCases { + t.Run(tc.Name, func(t *testing.T) { + assert.False(t, ParsedExternalVolumesDescribedEqual(tc.ParsedVolumeA, tc.ParsedVolumeB)) + }) + } +} + +func Test_GenerateParseExternalVolumeDescribedInput(t *testing.T) { + cases := []struct { + TestName string + Comment string + AllowWrites string + StorageLocations []string + Active string + ExpectedOutput []sdk.ExternalVolumeProperty + }{ + { + TestName: "Generate input", + Comment: comment, + AllowWrites: allowWritesTrue, + StorageLocations: []string{s3StorageLocationStandard}, + Active: "", + ExpectedOutput: []sdk.ExternalVolumeProperty{ + { + Parent: "", + Name: "ALLOW_WRITES", + Type: "Boolean", + Value: allowWritesTrue, + Default: "true", + }, + { + Parent: "", + Name: "COMMENT", + Type: "String", + Value: comment, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "STORAGE_LOCATION_1", + Type: "String", + Value: s3StorageLocationStandard, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "ACTIVE", + Type: "String", + Value: "", + Default: "", + }, + }, + }, + { + TestName: "Generate input - multiple locations and active set", + Comment: comment, + AllowWrites: allowWritesTrue, + StorageLocations: []string{s3StorageLocationStandard, azureStorageLocationStandard, gcsStorageLocationStandard}, + Active: s3StorageLocationName, + ExpectedOutput: []sdk.ExternalVolumeProperty{ + { + Parent: "", + Name: "ALLOW_WRITES", + Type: "Boolean", + Value: allowWritesTrue, + Default: "true", + }, + { + Parent: "", + Name: "COMMENT", + Type: "String", + Value: comment, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "STORAGE_LOCATION_1", + Type: "String", + Value: s3StorageLocationStandard, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "STORAGE_LOCATION_2", + Type: "String", + Value: azureStorageLocationStandard, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "STORAGE_LOCATION_3", + Type: "String", + Value: gcsStorageLocationStandard, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "ACTIVE", + Type: "String", + Value: s3StorageLocationName, + Default: "", + }, + }, + }, + } + + for _, tc := range cases { + t.Run(tc.TestName, func(t *testing.T) { + generatedInput := GenerateParseExternalVolumeDescribedInput( + tc.Comment, + tc.AllowWrites, + tc.StorageLocations, + tc.Active, + ) + + assert.Equal(t, len(tc.ExpectedOutput), len(generatedInput)) + for i := range generatedInput { + assert.Equal(t, tc.ExpectedOutput[i].Parent, generatedInput[i].Parent) + assert.Equal(t, tc.ExpectedOutput[i].Name, generatedInput[i].Name) + assert.Equal(t, tc.ExpectedOutput[i].Type, generatedInput[i].Type) + assert.Equal(t, tc.ExpectedOutput[i].Value, generatedInput[i].Value) + assert.Equal(t, tc.ExpectedOutput[i].Default, generatedInput[i].Default) + } + }) + } +} + +func Test_ParseExternalVolumeDescribed(t *testing.T) { + validCases := []struct { + Name string + DescribeOutput []sdk.ExternalVolumeProperty + ParsedDescribeOutput ParsedExternalVolumeDescribed + }{ + { + Name: "Volume with azure storage location", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesFalse, []string{azureStorageLocationStandard}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: azureStorageLocationName, + StorageProvider: azureStorageProvider, + StorageBaseUrl: azureStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: "", + EncryptionKmsKeyId: "", + AzureTenantId: azureTenantId, + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesFalse, + }, + }, + { + Name: "Volume with azure storage location, with extra fields", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesFalse, []string{azureStorageLocationWithExtraFields}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: azureStorageLocationName, + StorageProvider: azureStorageProvider, + StorageBaseUrl: azureStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: "", + EncryptionKmsKeyId: "", + AzureTenantId: azureTenantId, + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesFalse, + }, + }, + { + Name: "Volume with gcs storage location", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{gcsStorageLocationStandard}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: gcsStorageLocationName, + StorageProvider: gcsStorageProvider, + StorageBaseUrl: gcsStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: gcsEncryptionTypeNone, + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with gcs storage location, with extra fields", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{gcsStorageLocationWithExtraFields}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: gcsStorageLocationName, + StorageProvider: gcsStorageProvider, + StorageBaseUrl: gcsStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: gcsEncryptionTypeNone, + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with gcs storage location, sse kms encryption", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{gcsStorageLocationKmsEncryption}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: gcsStorageLocationName, + StorageProvider: gcsStorageProvider, + StorageBaseUrl: gcsStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: gcsEncryptionTypeSseKms, + EncryptionKmsKeyId: gcsEncryptionKmsKeyId, + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with s3 storage location", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{s3StorageLocationStandard}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: s3StorageLocationName, + StorageProvider: s3StorageProvider, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: s3StorageAwsExternalId, + EncryptionType: s3EncryptionTypeNone, + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with s3 storage location, with extra fields", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{s3StorageLocationWithExtraFields}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: s3StorageLocationName, + StorageProvider: s3StorageProvider, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: s3StorageAwsExternalId, + EncryptionType: s3EncryptionTypeSseKms, + EncryptionKmsKeyId: s3EncryptionKmsKeyId, + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with s3 storage location, sse s3 encryption", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{s3StorageLocationSseS3Encryption}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: s3StorageLocationName, + StorageProvider: s3StorageProvider, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: s3StorageAwsExternalId, + EncryptionType: s3EncryptionTypeSseS3, + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with s3 storage location, sse kms encryption", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{s3StorageLocationSseKmsEncryption}, ""), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: s3StorageLocationName, + StorageProvider: s3StorageProvider, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: s3StorageAwsExternalId, + EncryptionType: s3EncryptionTypeSseKms, + EncryptionKmsKeyId: s3EncryptionKmsKeyId, + AzureTenantId: "", + }, + }, + Active: "", + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with multiple storage locations and active set", + DescribeOutput: GenerateParseExternalVolumeDescribedInput( + comment, + allowWritesTrue, + []string{s3StorageLocationStandard, gcsStorageLocationStandard, azureStorageLocationStandard}, + s3StorageLocationName, + ), + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: s3StorageLocationName, + StorageProvider: s3StorageProvider, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: s3StorageAwsExternalId, + EncryptionType: s3EncryptionTypeNone, + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + { + Name: gcsStorageLocationName, + StorageProvider: gcsStorageProvider, + StorageBaseUrl: gcsStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: gcsEncryptionTypeNone, + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + { + Name: azureStorageLocationName, + StorageProvider: azureStorageProvider, + StorageBaseUrl: azureStorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: "", + EncryptionKmsKeyId: "", + AzureTenantId: azureTenantId, + }, + }, + Active: s3StorageLocationName, + Comment: comment, + AllowWrites: allowWritesTrue, + }, + }, + { + Name: "Volume with s3 storage location that has no comment set (in this case describe doesn't contain a comment property)", + DescribeOutput: []sdk.ExternalVolumeProperty{ + { + Parent: "", + Name: "ALLOW_WRITES", + Type: "Boolean", + Value: allowWritesTrue, + Default: "true", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "STORAGE_LOCATION_1", + Type: "String", + Value: s3StorageLocationSseKmsEncryption, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "ACTIVE", + Type: "String", + Value: s3StorageLocationName, + Default: "", + }, + }, + ParsedDescribeOutput: ParsedExternalVolumeDescribed{ + StorageLocations: []StorageLocation{ + { + Name: s3StorageLocationName, + StorageProvider: s3StorageProvider, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: s3StorageAwsExternalId, + EncryptionType: s3EncryptionTypeSseKms, + EncryptionKmsKeyId: s3EncryptionKmsKeyId, + AzureTenantId: "", + }, + }, + Active: s3StorageLocationName, + Comment: "", + AllowWrites: allowWritesTrue, + }, + }, + } + + invalidCases := []struct { + Name string + DescribeOutput []sdk.ExternalVolumeProperty + }{ + { + Name: "Volume with s3 storage location, missing STORAGE_AWS_ROLE_ARN", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{s3StorageLocationMissingRoleArn}, ""), + }, + { + Name: "Volume with azure storage location, missing AZURE_TENANT_ID", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{azureStorageLocationMissingTenantId}, ""), + }, + { + Name: "Volume with gcs storage location, missing STORAGE_BASE_URL", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{gcsStorageLocationMissingBaseUrl}, ""), + }, + { + Name: "Volume with no storage locations", + DescribeOutput: GenerateParseExternalVolumeDescribedInput(comment, allowWritesTrue, []string{}, ""), + }, + { + Name: "Volume with no allow writes", + DescribeOutput: []sdk.ExternalVolumeProperty{ + { + Parent: "STORAGE_LOCATIONS", + Name: "STORAGE_LOCATION_1", + Type: "String", + Value: s3StorageLocationSseKmsEncryption, + Default: "", + }, + { + Parent: "STORAGE_LOCATIONS", + Name: "ACTIVE", + Type: "String", + Value: s3StorageLocationName, + Default: "", + }, + }, + }, + } + + for _, tc := range validCases { + t.Run(tc.Name, func(t *testing.T) { + parsed, err := ParseExternalVolumeDescribed(tc.DescribeOutput) + require.NoError(t, err) + assert.True(t, ParsedExternalVolumesDescribedEqual(tc.ParsedDescribeOutput, parsed)) + }) + } + + for _, tc := range invalidCases { + t.Run(tc.Name, func(t *testing.T) { + _, err := ParseExternalVolumeDescribed(tc.DescribeOutput) + require.Error(t, err) + }) + } +} diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index edb760e412..97bd689bfe 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -439,6 +439,7 @@ func getResources() map[string]*schema.Resource { "snowflake_external_function": resources.ExternalFunction(), "snowflake_external_oauth_integration": resources.ExternalOauthIntegration(), "snowflake_external_table": resources.ExternalTable(), + "snowflake_external_volume": resources.ExternalVolume(), "snowflake_failover_group": resources.FailoverGroup(), "snowflake_file_format": resources.FileFormat(), "snowflake_function": resources.Function(), diff --git a/pkg/provider/resources/resources.go b/pkg/provider/resources/resources.go index 219617d4e6..c555e656a1 100644 --- a/pkg/provider/resources/resources.go +++ b/pkg/provider/resources/resources.go @@ -19,6 +19,7 @@ const ( ExternalFunction resource = "snowflake_external_function" ExternalTable resource = "snowflake_external_table" ExternalOauthSecurityIntegration resource = "snowflake_external_oauth_security_integration" + ExternalVolume resource = "snowflake_external_volume" FailoverGroup resource = "snowflake_failover_group" FileFormat resource = "snowflake_file_format" Function resource = "snowflake_function" diff --git a/pkg/resources/external_volume.go b/pkg/resources/external_volume.go new file mode 100644 index 0000000000..89c7e6e6d7 --- /dev/null +++ b/pkg/resources/external_volume.go @@ -0,0 +1,711 @@ +package resources + +import ( + "context" + "errors" + "fmt" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/logging" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/provider" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/schemas" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var externalVolumeSchema = map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + Description: blocklistedCharactersFieldDescription("Identifier for the external volume; must be unique for your account."), + DiffSuppressFunc: suppressIdentifierQuoting, + }, + // A list is used as the order of storage locations matter. Storage location position in the list is used to select + // the active storage location - https://docs.snowflake.com/en/user-guide/tables-iceberg-storage#active-storage-location + // This is also why it has been left as one list with optional cloud dependent parameters, rather than splitting into + // one list per cloud provider. + "storage_location": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Description: "List of named cloud storage locations in different regions and, optionally, cloud platforms. Minimum 1 required. Note that not all parameter combinations are valid as they depend on the given storage_provider. Consult [the docs](https://docs.snowflake.com/en/sql-reference/sql/create-external-volume#cloud-provider-parameters-cloudproviderparams) for more details on this.", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "storage_location_name": { + Type: schema.TypeString, + Required: true, + Description: "Name of the storage location. Must be unique for the external volume.", + }, + "storage_provider": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: sdkValidation(sdk.ToStorageProvider), + DiffSuppressFunc: SuppressIfAny(NormalizeAndCompare(sdk.ToStorageProvider)), + Description: fmt.Sprintf("Specifies the cloud storage provider that stores your data files. Valid values are (case-insensitive): %s.", possibleValuesListed(sdk.ValidStorageProviderString)), + }, + "storage_base_url": { + Type: schema.TypeString, + Required: true, + Description: "Specifies the base URL for your cloud storage location.", + }, + "storage_aws_role_arn": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the case-sensitive Amazon Resource Name (ARN) of the AWS identity and access management (IAM) role that grants privileges on the S3 bucket containing your data files.", + }, + "storage_aws_external_id": { + Type: schema.TypeString, + Computed: true, + Description: "External ID that Snowflake uses to establish a trust relationship with AWS.", + }, + "encryption_type": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the encryption type used.", + DiffSuppressFunc: func(k, oldValue, newValue string, d *schema.ResourceData) bool { + return oldValue == "NONE" && newValue == "" + }, + }, + "encryption_kms_key_id": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the ID for the KMS-managed key used to encrypt files.", + }, + "azure_tenant_id": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies the ID for your Office 365 tenant that the allowed and blocked storage accounts belong to.", + }, + }, + }, + }, + "comment": { + Type: schema.TypeString, + Optional: true, + Description: "Specifies a comment for the external volume.", + }, + "allow_writes": { + Type: schema.TypeString, + Optional: true, + Default: BooleanDefault, + Description: booleanStringFieldDescription("Specifies whether write operations are allowed for the external volume; must be set to TRUE for Iceberg tables that use Snowflake as the catalog."), + }, + ShowOutputAttributeName: { + Type: schema.TypeList, + Computed: true, + Description: "Outputs the result of `SHOW EXTERNAL VOLUMES` for the given external volume.", + Elem: &schema.Resource{ + Schema: schemas.ShowExternalVolumeSchema, + }, + }, + DescribeOutputAttributeName: { + Type: schema.TypeList, + Computed: true, + Description: "Outputs the result of `DESCRIBE EXTERNAL VOLUME` for the given external volume.", + Elem: &schema.Resource{ + Schema: schemas.DescribeExternalVolumeSchema, + }, + }, + FullyQualifiedNameAttributeName: schemas.FullyQualifiedNameSchema, +} + +// ExternalVolume returns a pointer to the resource representing an external volume. +func ExternalVolume() *schema.Resource { + return &schema.Resource{ + SchemaVersion: 1, + + CreateContext: CreateContextExternalVolume, + UpdateContext: UpdateContextExternalVolume, + ReadContext: ReadContextExternalVolume(true), + DeleteContext: DeleteContextExternalVolume, + Description: "Resource used to manage external volume objects. For more information, check [external volume documentation](https://docs.snowflake.com/en/sql-reference/commands-data-loading#external-volume).", + + Schema: externalVolumeSchema, + Importer: &schema.ResourceImporter{ + StateContext: ImportExternalVolume, + }, + + CustomizeDiff: customdiff.All( + ComputedIfAnyAttributeChanged(externalVolumeSchema, ShowOutputAttributeName, "name", "allow_writes", "comment"), + ComputedIfAnyAttributeChanged(externalVolumeSchema, FullyQualifiedNameAttributeName, "name"), + ComputedIfAnyAttributeChanged(externalVolumeSchema, DescribeOutputAttributeName, "name", "allow_writes", "comment", "storage_location"), + ), + } +} + +func ImportExternalVolume(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) { + logging.DebugLogger.Printf("[DEBUG] Starting external volume import") + client := meta.(*provider.Context).Client + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + + if err := d.Set("name", id.Name()); err != nil { + return nil, err + } + + externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) + if err != nil { + return nil, err + } + + if err = d.Set("allow_writes", booleanStringFromBool(externalVolume.AllowWrites)); err != nil { + return nil, err + } + + if err = d.Set("comment", externalVolume.Comment); err != nil { + return nil, err + } + + externalVolumeDescribe, err := client.ExternalVolumes.Describe(ctx, id) + if err != nil { + return nil, err + } + + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(externalVolumeDescribe) + if err != nil { + return nil, err + } + + storageLocations := make([]map[string]any, len(parsedExternalVolumeDescribed.StorageLocations)) + for i, storageLocation := range parsedExternalVolumeDescribed.StorageLocations { + storageLocations[i] = map[string]any{ + "storage_location_name": storageLocation.Name, + "storage_provider": storageLocation.StorageProvider, + "storage_base_url": storageLocation.StorageBaseUrl, + "storage_aws_role_arn": storageLocation.StorageAwsRoleArn, + "storage_aws_external_id": storageLocation.StorageAwsExternalId, + "encryption_type": storageLocation.EncryptionType, + "encryption_kms_key_id": storageLocation.EncryptionKmsKeyId, + "azure_tenant_id": storageLocation.AzureTenantId, + } + } + + if err = d.Set("storage_location", storageLocations); err != nil { + return nil, err + } + + return []*schema.ResourceData{d}, nil +} + +func extractStorageLocations(v any, withAzureEncryptionCheck bool) ([]sdk.ExternalVolumeStorageLocation, error) { + _, ok := v.([]any) + if v == nil || !ok { + return nil, fmt.Errorf("unable to extract storage locations, input is either nil or non expected type (%T): %v", v, v) + } + + storageLocations := make([]sdk.ExternalVolumeStorageLocation, len(v.([]any))) + for i, storageLocationConfigRaw := range v.([]any) { + storageLocationConfig, ok := storageLocationConfigRaw.(map[string]any) + if !ok { + return nil, fmt.Errorf("unable to extract storage location, non expected type of %T: %v", storageLocationConfigRaw, storageLocationConfigRaw) + } + + name, ok := storageLocationConfig["storage_location_name"].(string) + if !ok { + return nil, fmt.Errorf("unable to extract storage location, missing storage_location_name key in storage location") + } + + storageProvider, ok := storageLocationConfig["storage_provider"].(string) + if !ok { + return nil, fmt.Errorf("unable to extract storage location, missing storage_provider key in storage location") + } + + storage_base_url, ok := storageLocationConfig["storage_base_url"].(string) + if !ok { + return nil, fmt.Errorf("unable to extract storage location, missing storage_base_url key in storage location") + } + + storageProviderParsed, err := sdk.ToStorageProvider(storageProvider) + if err != nil { + return nil, err + } + + var storageLocation sdk.ExternalVolumeStorageLocation + switch storageProviderParsed { + case sdk.StorageProviderS3, sdk.StorageProviderS3GOV: + // Test that azure_tenant_id is not given + // If given non empty plans will be produced + azure_tenant_id, ok := storageLocationConfig["azure_tenant_id"].(string) + if ok && len(azure_tenant_id) > 0 { + return nil, fmt.Errorf("unable to extract storage location, azure_tenant_id provided for s3 storage location") + } + + storage_aws_role_arn, ok := storageLocationConfig["storage_aws_role_arn"].(string) + if !ok || len(storage_aws_role_arn) == 0 { + return nil, fmt.Errorf("unable to extract storage location, missing storage_aws_role_arn key in an s3 storage location") + } + + s3StorageProvider, err := sdk.ToS3StorageProvider(storageProvider) + if err != nil { + return nil, err + } + + s3StorageLocation := &sdk.S3StorageLocationParams{ + Name: name, + StorageProvider: s3StorageProvider, + StorageBaseUrl: storage_base_url, + StorageAwsRoleArn: storage_aws_role_arn, + } + + encryption_type, ok := storageLocationConfig["encryption_type"].(string) + if ok && len(encryption_type) > 0 { + encryptionTypeParsed, err := sdk.ToS3EncryptionType(encryption_type) + if err != nil { + return nil, err + } + + encryption_kms_key_id, ok := storageLocationConfig["encryption_kms_key_id"].(string) + if ok && len(encryption_kms_key_id) > 0 { + s3StorageLocation.Encryption = &sdk.ExternalVolumeS3Encryption{ + Type: encryptionTypeParsed, + KmsKeyId: &encryption_kms_key_id, + } + } else { + s3StorageLocation.Encryption = &sdk.ExternalVolumeS3Encryption{ + Type: encryptionTypeParsed, + } + } + } + + storageLocation = sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: s3StorageLocation, + } + case sdk.StorageProviderGCS: + // Test that azure_tenant_id and storage_aws_role_arn are not given + // If given non empty plans will be produced + azure_tenant_id, ok := storageLocationConfig["azure_tenant_id"].(string) + storage_aws_role_arn, ok := storageLocationConfig["storage_aws_role_arn"].(string) + if ok && len(azure_tenant_id) > 0 { + return nil, fmt.Errorf("unable to extract storage location, azure_tenant_id provided for gcs storage location") + } + if ok && len(storage_aws_role_arn) > 0 { + return nil, fmt.Errorf("unable to extract storage location, storage_aws_role_arn provided for gcs storage location") + } + + gcsStorageLocation := &sdk.GCSStorageLocationParams{ + Name: name, + StorageBaseUrl: storage_base_url, + } + encryption_type, ok := storageLocationConfig["encryption_type"].(string) + if ok && len(encryption_type) > 0 { + encryptionTypeParsed, err := sdk.ToGCSEncryptionType(encryption_type) + if err != nil { + return nil, err + } + encryption_kms_key_id, ok := storageLocationConfig["encryption_kms_key_id"].(string) + if ok && len(encryption_kms_key_id) > 0 { + gcsStorageLocation.Encryption = &sdk.ExternalVolumeGCSEncryption{ + Type: encryptionTypeParsed, + KmsKeyId: &encryption_kms_key_id, + } + } else { + gcsStorageLocation.Encryption = &sdk.ExternalVolumeGCSEncryption{ + Type: encryptionTypeParsed, + } + } + } + + storageLocation = sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: gcsStorageLocation, + } + case sdk.StorageProviderAzure: + // Test that storage_aws_role_arn is not given + // If given non empty plans will be produced + storage_aws_role_arn, ok := storageLocationConfig["storage_aws_role_arn"].(string) + if ok && len(storage_aws_role_arn) > 0 { + return nil, fmt.Errorf("unable to extract storage location, storage_aws_role_arn provided for azure storage location") + } + + // Encryption fields are set on describe requests, although they are not a valid parameter. + // Allowing optional checking of these fields as they will be present in some cases. + if withAzureEncryptionCheck { + encryption_type, ok := storageLocationConfig["encryption_type"].(string) + if ok && len(encryption_type) > 0 { + return nil, fmt.Errorf("unable to extract storage location, encryption_type provided for azure storage location") + } + + encryption_kms_key_id, ok := storageLocationConfig["encryption_kms_key_id"].(string) + if ok && len(encryption_kms_key_id) > 0 { + return nil, fmt.Errorf("unable to extract storage location, encryption_kms_key_id provided for azure storage location") + } + } + + azure_tenant_id, ok := storageLocationConfig["azure_tenant_id"].(string) + if !ok || len(azure_tenant_id) == 0 { + return nil, fmt.Errorf("unable to extract storage location, missing azure_tenant_id provider key in an azure storage location") + } + + storageLocation = sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: name, + AzureTenantId: azure_tenant_id, + StorageBaseUrl: storage_base_url, + }, + } + } + storageLocations[i] = storageLocation + } + return storageLocations, nil +} + +func CreateContextExternalVolume(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client + + name := d.Get("name").(string) + id := sdk.NewAccountObjectIdentifier(name) + + storageLocations, err := extractStorageLocations(d.Get("storage_location"), true) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating external volume %v err = %w", id.Name(), err)) + } + + req := sdk.NewCreateExternalVolumeRequest(id, storageLocations) + + if v, ok := d.GetOk("comment"); ok { + req.WithComment(v.(string)) + } + + if v := d.Get("allow_writes").(string); v != BooleanDefault { + parsed, err := booleanStringToBool(v) + if err != nil { + return diag.FromErr(err) + } + req.WithAllowWrites(parsed) + } + + createErr := client.ExternalVolumes.Create(ctx, req) + if err != nil { + return diag.FromErr(fmt.Errorf("error creating external volume %v err = %w", id.Name(), createErr)) + } + + d.SetId(helpers.EncodeResourceIdentifier(id)) + return ReadContextExternalVolume(false)(ctx, d, meta) +} + +func ReadContextExternalVolume(withExternalChangesMarking bool) schema.ReadContextFunc { + return func(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + + if err := d.Set("name", id.Name()); err != nil { + return diag.FromErr(err) + } + + externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) + if err != nil { + return diag.FromErr(err) + } + + if withExternalChangesMarking { + if err = handleExternalChangesToObjectInShow(d, + showMapping{"allow_writes", "allow_writes", externalVolume.AllowWrites, booleanStringFromBool(externalVolume.AllowWrites), nil}, + ); err != nil { + return diag.FromErr(err) + } + } + + if err = setStateToValuesFromConfig(d, externalVolumeSchema, []string{ + "allow_writes", + }); err != nil { + return diag.FromErr(err) + } + + if err = d.Set("comment", externalVolume.Comment); err != nil { + return diag.FromErr(err) + } + + externalVolumeDescribe, err := client.ExternalVolumes.Describe(ctx, id) + if err != nil { + return diag.FromErr(err) + } + + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(externalVolumeDescribe) + if err != nil { + return diag.FromErr(err) + } + + storageLocations := make([]map[string]any, len(parsedExternalVolumeDescribed.StorageLocations)) + for i, storageLocation := range parsedExternalVolumeDescribed.StorageLocations { + storageLocations[i] = map[string]any{ + "storage_location_name": storageLocation.Name, + "storage_provider": storageLocation.StorageProvider, + "storage_base_url": storageLocation.StorageBaseUrl, + "storage_aws_role_arn": storageLocation.StorageAwsRoleArn, + "storage_aws_external_id": storageLocation.StorageAwsExternalId, + "encryption_type": storageLocation.EncryptionType, + "encryption_kms_key_id": storageLocation.EncryptionKmsKeyId, + "azure_tenant_id": storageLocation.AzureTenantId, + } + } + + if err = d.Set("storage_location", storageLocations); err != nil { + return diag.FromErr(err) + } + if err = d.Set(DescribeOutputAttributeName, schemas.ExternalVolumeDescriptionToSchema(externalVolumeDescribe)); err != nil { + return diag.FromErr(err) + } + if err = d.Set(ShowOutputAttributeName, []map[string]any{schemas.ExternalVolumeToSchema(externalVolume)}); err != nil { + return diag.FromErr(err) + } + + return nil + } +} + +func addStorageLocation( + addedLocation sdk.ExternalVolumeStorageLocation, + client *sdk.Client, + ctx context.Context, + id sdk.AccountObjectIdentifier, +) error { + storageProvider, err := GetStorageLocationStorageProvider(addedLocation) + if err != nil { + return err + } + + var newStorageLocationreq *sdk.ExternalVolumeStorageLocationRequest + switch storageProvider { + case sdk.StorageProviderS3, sdk.StorageProviderS3GOV: + addedLocation := addedLocation.S3StorageLocationParams + s3ParamsRequest := sdk.NewS3StorageLocationParamsRequest( + addedLocation.Name, + addedLocation.StorageProvider, + addedLocation.StorageAwsRoleArn, + addedLocation.StorageBaseUrl, + ) + if addedLocation.Encryption != nil { + if addedLocation.Encryption.KmsKeyId != nil { + s3ParamsRequest = s3ParamsRequest.WithEncryption( + *sdk.NewExternalVolumeS3EncryptionRequest(addedLocation.Encryption.Type). + WithKmsKeyId(*addedLocation.Encryption.KmsKeyId), + ) + } else { + s3ParamsRequest = s3ParamsRequest.WithEncryption( + *sdk.NewExternalVolumeS3EncryptionRequest(addedLocation.Encryption.Type), + ) + } + } + + newStorageLocationreq = sdk.NewExternalVolumeStorageLocationRequest().WithS3StorageLocationParams(*s3ParamsRequest) + case sdk.StorageProviderGCS: + addedLocation := addedLocation.GCSStorageLocationParams + gcsParamsRequest := sdk.NewGCSStorageLocationParamsRequest( + addedLocation.Name, + addedLocation.StorageBaseUrl, + ) + + if addedLocation.Encryption != nil { + if addedLocation.Encryption.KmsKeyId != nil { + gcsParamsRequest = gcsParamsRequest.WithEncryption( + *sdk.NewExternalVolumeGCSEncryptionRequest(addedLocation.Encryption.Type). + WithKmsKeyId(*addedLocation.Encryption.KmsKeyId), + ) + } else { + gcsParamsRequest = gcsParamsRequest.WithEncryption( + *sdk.NewExternalVolumeGCSEncryptionRequest(addedLocation.Encryption.Type), + ) + } + } + + newStorageLocationreq = sdk.NewExternalVolumeStorageLocationRequest().WithGCSStorageLocationParams(*gcsParamsRequest) + case sdk.StorageProviderAzure: + addedLocation := addedLocation.AzureStorageLocationParams + azureParamsRequest := sdk.NewAzureStorageLocationParamsRequest( + addedLocation.Name, + addedLocation.AzureTenantId, + addedLocation.StorageBaseUrl, + ) + newStorageLocationreq = sdk.NewExternalVolumeStorageLocationRequest().WithAzureStorageLocationParams(*azureParamsRequest) + } + + if err := client.ExternalVolumes.Alter(ctx, sdk.NewAlterExternalVolumeRequest(id).WithAddStorageLocation(*newStorageLocationreq)); err != nil { + return err + } else { + return nil + } +} + +func removeStorageLocation( + removedLocation sdk.ExternalVolumeStorageLocation, + client *sdk.Client, + ctx context.Context, + id sdk.AccountObjectIdentifier, +) error { + removedName, err := GetStorageLocationName(removedLocation) + if err != nil { + return err + } + + if err := client.ExternalVolumes.Alter(ctx, sdk.NewAlterExternalVolumeRequest(id).WithRemoveStorageLocation(removedName)); err != nil { + return err + } + + return nil +} + +// Process the removal / addition storage location requests. +// to avoid creating storage locations with duplicate names. +// len(removedLocations) should be less than the total number +// of storage locations the external volume has, else this function will fail. +func updateStorageLocations( + removedLocations []sdk.ExternalVolumeStorageLocation, + addedLocations []sdk.ExternalVolumeStorageLocation, + client *sdk.Client, + ctx context.Context, + id sdk.AccountObjectIdentifier, +) error { + for _, removedLocation := range removedLocations { + err := removeStorageLocation(removedLocation, client, ctx, id) + if err != nil { + return err + } + } + for _, addedLocation := range addedLocations { + err := addStorageLocation(addedLocation, client, ctx, id) + if err != nil { + return err + } + } + + return nil +} + +func UpdateContextExternalVolume(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client + id, err := sdk.ParseAccountObjectIdentifier(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + set := sdk.NewAlterExternalVolumeSetRequest() + + if d.HasChange("comment") { + // not using d.GetOk as that doesn't let comments be reset to the empty string + set.WithComment(d.Get("comment").(string)) + } + + if d.HasChange("allow_writes") { + if v := d.Get("allow_writes").(string); v != BooleanDefault { + parsed, err := booleanStringToBool(v) + if err != nil { + return diag.FromErr(err) + } + set.WithAllowWrites(parsed) + } else { + // no way to unset allow writes - set to false as a default + set.WithAllowWrites(false) + } + } + + if (*set != sdk.AlterExternalVolumeSetRequest{}) { + if err := client.ExternalVolumes.Alter(ctx, sdk.NewAlterExternalVolumeRequest(id).WithSet(*set)); err != nil { + return diag.FromErr(err) + } + } + + if d.HasChange("storage_location") { + old, new := d.GetChange("storage_location") + oldLocations, err := extractStorageLocations(old, false) + if err != nil { + return diag.FromErr(err) + } + + newLocations, err := extractStorageLocations(new, false) + if err != nil { + return diag.FromErr(err) + } + + // Storage locations can only be added to the tail of the list, but can be + // removed at any position. Given this limitation, to keep the configuration order + // matching that on Snowflake the list needs to be partially recreated. For example, if a location + // is added in the configuration at index 5 in the list, all existing storage locations from index 5 + // need to be removed, then the new location can be added, and then the removed locations + // can be added back. The storage locations lower than index 5 don't need to be modified. + // The removal process could be done without the above recreation, but it handles this case + // too so it's used for both actions. + longestCommonPrefix, err := LongestCommonPrefix(newLocations, oldLocations) + if err != nil { + return diag.FromErr(err) + } + + var removedLocations []sdk.ExternalVolumeStorageLocation + var addedLocations []sdk.ExternalVolumeStorageLocation + if longestCommonPrefix == -1 { + removedLocations = oldLocations + addedLocations = newLocations + } else { + // Could +1 on the prefix here as the lists until and including this index + // are identical, would need to add some more checks for list length to avoid + // an array index out of bounds error + removedLocations = oldLocations[longestCommonPrefix:] + addedLocations = newLocations[longestCommonPrefix:] + } + + if len(removedLocations) == len(oldLocations) { + // Create a temporary storage location, which is a copy of a storage location currently existing + // except with a different name. This is done to avoid recreating the external volume, which + // would otherwise be necessary as a minimum of 1 storage location per external volume is required. + // The alternative solution of adding volumes before removing them isn't possible as + // name must be unique for storage locations + if len(removedLocations) > 1 { + // To ensure the name of the temporary storage location is unique, + // first remove all but 1 storage locations from the list + for _, removedStorageLocation := range removedLocations[1:] { + err = removeStorageLocation(removedStorageLocation, client, ctx, id) + if err != nil { + return diag.FromErr(err) + } + } + } + + temp_storage_location, err := CopyStorageLocationWithTempName(removedLocations[0]) + if err != nil { + return diag.FromErr(err) + } + + addTempErr := addStorageLocation(temp_storage_location, client, ctx, id) + if addTempErr != nil { + return diag.FromErr(addTempErr) + } + + updateErr := updateStorageLocations([]sdk.ExternalVolumeStorageLocation{removedLocations[0]}, addedLocations, client, ctx, id) + if updateErr != nil { + // Try to remove the temp location and then return with error + removeErr := removeStorageLocation(temp_storage_location, client, ctx, id) + if removeErr != nil { + return diag.FromErr(errors.Join(updateErr, removeErr)) + } + + return diag.FromErr(updateErr) + } + + removeErr := removeStorageLocation(temp_storage_location, client, ctx, id) + if removeErr != nil { + return diag.FromErr(removeErr) + } + } else { + updateErr := updateStorageLocations(removedLocations, addedLocations, client, ctx, id) + if updateErr != nil { + return diag.FromErr(err) + } + } + + } + + return ReadContextExternalVolume(false)(ctx, d, meta) +} + +func DeleteContextExternalVolume(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*provider.Context).Client + id := helpers.DecodeSnowflakeID(d.Id()).(sdk.AccountObjectIdentifier) + + err := client.ExternalVolumes.Drop(ctx, sdk.NewDropExternalVolumeRequest(id).WithIfExists(true)) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("") + return nil +} diff --git a/pkg/resources/external_volume_acceptance_test.go b/pkg/resources/external_volume_acceptance_test.go new file mode 100644 index 0000000000..e6a7e4cd79 --- /dev/null +++ b/pkg/resources/external_volume_acceptance_test.go @@ -0,0 +1,1928 @@ +package resources_test + +// TODO Add test that includes Iceberg table creation, as this impacts the describe output (updates ACTIVE) + +import ( + "regexp" + "testing" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/config" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +var ( + comment = random.Comment() + comment2 = random.Comment() + allowWritesTrue = "true" + allowWritesFalse = "false" +) + +var ( + s3StorageLocationName = "s3Test" + s3StorageLocationName2 = "s3Test2" + s3StorageProvider = "S3" + s3StorageBaseUrl = "s3://my_example_bucket" + s3StorageBaseUrl2 = "s3://my_example_bucket2" + s3StorageAwsRoleArn = "arn:aws:iam::123456789012:role/myrole" + s3StorageAwsRoleArn2 = "arn:aws:iam::123456789012:role/myrole2" + s3EncryptionTypeNone = "NONE" + s3EncryptionTypeSseS3 = "AWS_SSE_S3" + s3EncryptionTypeSseKms = "AWS_SSE_KMS" + s3EncryptionKmsKeyId = "123456789" + s3EncryptionKmsKeyId2 = "987654321" +) + +var ( + s3StorageLocation = getS3StorageLocation(s3StorageLocationName, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeNone, "") + s3StorageLocationUpdatedBaseUrl = getS3StorageLocation(s3StorageLocationName, s3StorageProvider, s3StorageBaseUrl2, s3StorageAwsRoleArn, s3EncryptionTypeNone, "") + s3StorageLocationUpdatedRoleArn = getS3StorageLocation(s3StorageLocationName, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn2, s3EncryptionTypeNone, "") + s3StorageLocationUpdatedName = getS3StorageLocation(s3StorageLocationName2, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeNone, "") + s3StorageLocationSseEncryption = getS3StorageLocation(s3StorageLocationName, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeSseS3, "") + s3StorageLocationKmsEncryption = getS3StorageLocation(s3StorageLocationName, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeSseKms, s3EncryptionKmsKeyId) + s3StorageLocationKmsEncryptionUpdatedName = getS3StorageLocation(s3StorageLocationName2, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeSseKms, s3EncryptionKmsKeyId) + s3StorageLocationKmsEncryptionUpdatedKey = getS3StorageLocation(s3StorageLocationName, s3StorageProvider, s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeSseKms, s3EncryptionKmsKeyId2) +) + +var ( + gcsStorageLocationName = "gcsTest" + gcsStorageLocationName2 = "gcsTest2" + gcsStorageProvider = "GCS" + gcsStorageBaseUrl = "gcs://my_example_bucket" + gcsStorageBaseUrl2 = "gcs://my_example_bucket2" + gcsEncryptionTypeNone = "NONE" + gcsEncryptionTypeSseKms = "GCS_SSE_KMS" + gcsEncryptionKmsKeyId = "123456789" + gcsEncryptionKmsKeyId2 = "987654321" +) + +var ( + gcsStorageLocation = getGcsStorageLocation(gcsStorageLocationName, gcsStorageBaseUrl, gcsEncryptionTypeNone, "") + gcsStorageLocationUpdatedName = getGcsStorageLocation(gcsStorageLocationName2, gcsStorageBaseUrl, gcsEncryptionTypeNone, "") + gcsStorageLocationUpdatedBaseUrl = getGcsStorageLocation(gcsStorageLocationName, gcsStorageBaseUrl2, gcsEncryptionTypeNone, "") + gcsStorageLocationKmsEncryption = getGcsStorageLocation(gcsStorageLocationName, gcsStorageBaseUrl, gcsEncryptionTypeSseKms, gcsEncryptionKmsKeyId) + gcsStorageLocationKmsEncryptionUpdatedName = getGcsStorageLocation(gcsStorageLocationName2, gcsStorageBaseUrl, gcsEncryptionTypeSseKms, gcsEncryptionKmsKeyId) + gcsStorageLocationKmsEncryptionUpdatedKey = getGcsStorageLocation(gcsStorageLocationName, gcsStorageBaseUrl, gcsEncryptionTypeSseKms, gcsEncryptionKmsKeyId2) +) + +var ( + azureStorageLocationName = "azureTest" + azureStorageLocationName2 = "azureTest2" + azureStorageProvider = "AZURE" + azureStorageBaseUrl = "azure://123456789.blob.core.windows.net/my_example_container" + azureTenantId = "123456789" + azureTenantId2 = "987654321" +) + +var ( + azureStorageLocation = getAzureStorageLocation(azureStorageLocationName, azureStorageBaseUrl, azureTenantId) + azureStorageLocationUpdatedTenantId = getAzureStorageLocation(azureStorageLocationName, azureStorageBaseUrl, azureTenantId2) + azureStorageLocationUpdatedName = getAzureStorageLocation(azureStorageLocationName2, azureStorageBaseUrl, azureTenantId) +) + +// Note that generators currently don't handle lists of objects, which is required for storage locations +// Using the old approach of files for this reason + +func getS3StorageLocation( + locName string, + provider string, + baseUrl string, + roleArn string, + encryptionType string, + s3EncryptionKmsKeyId string, +) config.Variable { + if encryptionType == "AWS_SSE_KMS" { + return config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(locName), + "storage_provider": config.StringVariable(provider), + "storage_base_url": config.StringVariable(baseUrl), + "storage_aws_role_arn": config.StringVariable(roleArn), + "encryption_type": config.StringVariable(encryptionType), + "encryption_kms_key_id": config.StringVariable(s3EncryptionKmsKeyId), + }) + } else { + return config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(locName), + "storage_provider": config.StringVariable(provider), + "storage_base_url": config.StringVariable(baseUrl), + "storage_aws_role_arn": config.StringVariable(roleArn), + "encryption_type": config.StringVariable(encryptionType), + }) + } +} + +func getGcsStorageLocation( + locName string, + baseUrl string, + encryptionType string, + gcsEncryptionKmsKeyId string, +) config.Variable { + if encryptionType == "GCS_SSE_KMS" { + return config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(locName), + "storage_provider": config.StringVariable(gcsStorageProvider), + "storage_base_url": config.StringVariable(baseUrl), + "encryption_type": config.StringVariable(encryptionType), + "encryption_kms_key_id": config.StringVariable(gcsEncryptionKmsKeyId), + }) + } else { + return config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(locName), + "storage_provider": config.StringVariable(gcsStorageProvider), + "storage_base_url": config.StringVariable(baseUrl), + "encryption_type": config.StringVariable(encryptionType), + }) + } +} + +func getAzureStorageLocation( + locName string, + baseUrl string, + azureTenantId string, +) config.Variable { + return config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(locName), + "storage_provider": config.StringVariable(azureStorageProvider), + "storage_base_url": config.StringVariable(baseUrl), + "azure_tenant_id": config.StringVariable(azureTenantId), + }) +} + +func externalVolume(storageLocations config.Variable, name string, comment string, allowWrites string) config.Variables { + return config.Variables{ + "name": config.StringVariable(name), + "comment": config.StringVariable(comment), + "allow_writes": config.StringVariable(allowWrites), + "storage_location": storageLocations, + } +} + +func externalVolumeMultiple(s3StorageLocations config.Variable, gcsStorageLocations config.Variable, azureStorageLocations config.Variable, name string, comment string, allowWrites string) config.Variables { + return config.Variables{ + "name": config.StringVariable(name), + "comment": config.StringVariable(comment), + "allow_writes": config.StringVariable(allowWrites), + "s3_storage_locations": s3StorageLocations, + "gcs_storage_locations": gcsStorageLocations, + "azure_storage_locations": azureStorageLocations, + } +} + +// Test volume with s3 storage locations +func TestAcc_External_Volume_S3(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + externalVolumeName := id.Name() + resourceId := helpers.EncodeResourceIdentifier(id) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.ExternalVolume), + Steps: []resource.TestStep{ + // without optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/basic"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, "", ""), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(""). + HasAllowWritesString(r.BooleanDefault). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "3")), + ), + }, + // import - without optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/basic"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, "", ""), + ResourceName: "snowflake_external_volume.test", + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedExternalVolumeResource(t, resourceId). + HasNameString(externalVolumeName). + HasStorageLocationLength(1), + ), + }, + // set external volume optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // import - with external volume optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // add second storage location without s3 optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // import - 2 storage locations without all s3 optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // update comment and change back to 1 storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment2, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // update allowWrites + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // add none encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // add AWS_SSE_S3 encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationSseEncryption), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeSseS3)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // add AWS_SSE_KMS encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationKmsEncryption), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", s3EncryptionKmsKeyId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // update kms key + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationKmsEncryptionUpdatedKey), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", s3EncryptionKmsKeyId2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // import - all optional s3 storage location optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationKmsEncryption), externalVolumeName, comment2, allowWritesFalse), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // add second storage location with all s3 optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationKmsEncryptionUpdatedKey, s3StorageLocationKmsEncryptionUpdatedName), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", s3EncryptionKmsKeyId2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", s3EncryptionKmsKeyId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // import - 2 s3 storage locations, with all s3 optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationKmsEncryptionUpdatedKey, s3StorageLocationKmsEncryptionUpdatedName), externalVolumeName, comment2, allowWritesFalse), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // change back to AWS_SSE_S3 encryption with 1 s3 storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationSseEncryption), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeSseS3)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // change back to none encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete-add-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // change back to no encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // remove allow writes and comment from config + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/basic"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, "", ""), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(""). + HasAllowWritesString(r.BooleanDefault). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "3")), + ), + }, + }, + }) +} + +// Test volume with gcs storage locations +func TestAcc_External_Volume_GCS(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + externalVolumeName := id.Name() + resourceId := helpers.EncodeResourceIdentifier(id) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.ExternalVolume), + Steps: []resource.TestStep{ + // without optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/basic"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, "", ""), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(""). + HasAllowWritesString(r.BooleanDefault). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "3")), + ), + }, + // import - without optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/basic"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, "", ""), + ResourceName: "snowflake_external_volume.test", + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedExternalVolumeResource(t, resourceId). + HasNameString(externalVolumeName). + HasStorageLocationLength(1), + ), + }, + // set external volume optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // import - with external volume optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // add second storage location without gcs optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation, gcsStorageLocationUpdatedName), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // import - 2 storage locations without all gcs optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation, gcsStorageLocationUpdatedName), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // update comment and change back to 1 storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment2, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // update allowWrites + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // add none encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // add GCS_SSE_KMS encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationKmsEncryption), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", gcsEncryptionKmsKeyId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // update kms key + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationKmsEncryptionUpdatedKey), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", gcsEncryptionKmsKeyId2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // import - all gcs storage location optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationKmsEncryption), externalVolumeName, comment2, allowWritesFalse), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // add second storage location with all gcs optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationKmsEncryptionUpdatedKey, gcsStorageLocationKmsEncryptionUpdatedName), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", gcsEncryptionKmsKeyId2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeSseKms)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", gcsEncryptionKmsKeyId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // import - 2 gcs storage locations, with all gcs optionals set + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationKmsEncryptionUpdatedKey, gcsStorageLocationKmsEncryptionUpdatedName), externalVolumeName, comment2, allowWritesFalse), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // change back to none encryption with 1 gcs storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete-add-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // change back to no encryption + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/complete"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // remove allow writes and comment from config + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/basic"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocation), externalVolumeName, "", ""), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(""). + HasAllowWritesString(r.BooleanDefault). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "3")), + ), + }, + }, + }) +} + +// Test volume with azure storage locations +func TestAcc_External_Volume_Azure(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + externalVolumeName := id.Name() + resourceId := helpers.EncodeResourceIdentifier(id) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.ExternalVolume), + Steps: []resource.TestStep{ + // without optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/basic"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, "", ""), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(""). + HasAllowWritesString(r.BooleanDefault). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "3")), + ), + }, + // import - without optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/basic"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, "", ""), + ResourceName: "snowflake_external_volume.test", + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedExternalVolumeResource(t, resourceId). + HasNameString(externalVolumeName). + HasStorageLocationLength(1), + ), + }, + // set external volume optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/complete"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // import - with external volume optionals + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/complete"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // add second storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/complete"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation, azureStorageLocationUpdatedName), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", azureStorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // import - 2 storage locations + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/complete"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // update comment and change back to 1 storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/complete"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, comment2, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // update allowWrites + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/complete"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, comment2, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment2). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "4")), + ), + }, + // remove allow writes and comment from config + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/basic"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, "", ""), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(""). + HasAllowWritesString(r.BooleanDefault). + HasStorageLocationLength(1), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "3")), + ), + }, + }, + }) +} + +// Test volume with multiple storage locations that span multiple providers +// Test adding/removing storage locations at different positions in the storage_location list +func TestAcc_External_Volume_Multiple(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + externalVolumeName := id.Name() + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.ExternalVolume), + Steps: []resource.TestStep{ + // one location of each provider + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // import + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + ResourceName: "snowflake_external_volume.complete", + ImportState: true, + ImportStateVerify: true, + }, + // change the s3 base url at position 0 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocationUpdatedBaseUrl), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // change back the s3 base url at position 0 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // add new s3 storage location to position 0 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocationUpdatedName, s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(4), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "7")), + ), + }, + // remove s3 storage location at position 0 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // change the encryption type of the gcs storage location at position 1 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocationUpdatedBaseUrl), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // change back the encryption type of the gcs storage location at position 1 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // add new s3 storage location to position 1 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(4), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "7")), + ), + }, + // remove s3 storage location at position 1 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // change the tenant id of the azure storage location at position 2 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocationUpdatedTenantId), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // change back the tenant id of the azure storage location at position 2 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // add new gcs storage location to position 2 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation, gcsStorageLocationUpdatedName), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(4), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", gcsStorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "7")), + ), + }, + // remove gcs storage location at position 2 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + // add new azure storage location to position 3 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation, azureStorageLocationUpdatedName), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(4), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_location_name", azureStorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.3.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "7")), + ), + }, + // remove azure storage location from position 3 + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/multiple/complete"), + ConfigVariables: externalVolumeMultiple(config.ListVariable(s3StorageLocation), config.ListVariable(gcsStorageLocation), config.ListVariable(azureStorageLocation), externalVolumeName, comment, allowWritesTrue), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesTrue). + HasStorageLocationLength(3), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", gcsStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", gcsStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", gcsStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", gcsEncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_location_name", azureStorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_provider", azureStorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.storage_base_url", azureStorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.2.azure_tenant_id", azureTenantId)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesTrue)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "6")), + ), + }, + }, + }) +} + +// Test that drifts are detected and fixed +func TestAcc_External_Volume_External_Changes(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + externalVolumeName := id.Name() + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.ExternalVolume), + Steps: []resource.TestStep{ + // create volume with 2 s3 storage locations + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // externally remove storage location + { + PreConfig: func() { + acc.TestClient().ExternalVolume.Alter(t, sdk.NewAlterExternalVolumeRequest(id).WithRemoveStorageLocation(s3StorageLocationName)) + }, + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // externally add storage location + { + PreConfig: func() { + acc.TestClient().ExternalVolume.Alter( + t, + sdk.NewAlterExternalVolumeRequest(id).WithAddStorageLocation( + *sdk.NewExternalVolumeStorageLocationRequest().WithS3StorageLocationParams( + *sdk.NewS3StorageLocationParamsRequest( + "externally-added-s3-storage-location", + "s3", + "arn:aws:iam::123456789012:role/externally-added-role", + "s3://externally-added-bucket", + ), + ), + ), + ) + }, + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // externally drop external volume + { + PreConfig: func() { + acc.TestClient().ExternalVolume.DropFunc(t, id) + }, + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // externally update comment + { + PreConfig: func() { + acc.TestClient().ExternalVolume.Alter(t, sdk.NewAlterExternalVolumeRequest(id).WithSet( + *sdk.NewAlterExternalVolumeSetRequest().WithComment(comment2), + )) + }, + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + // externally update allow writes + { + PreConfig: func() { + acc.TestClient().ExternalVolume.Alter(t, sdk.NewAlterExternalVolumeRequest(id).WithSet( + *sdk.NewAlterExternalVolumeSetRequest().WithAllowWrites(true), + )) + }, + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/complete"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation, s3StorageLocationUpdatedName), externalVolumeName, comment, allowWritesFalse), + Check: assert.AssertThat(t, + resourceassert.ExternalVolumeResource(t, "snowflake_external_volume.complete"). + HasNameString(externalVolumeName). + HasCommentString(comment). + HasAllowWritesString(allowWritesFalse). + HasStorageLocationLength(2), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_location_name", s3StorageLocationName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.0.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_location_name", s3StorageLocationName2)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_provider", s3StorageProvider)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_base_url", s3StorageBaseUrl)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.storage_aws_role_arn", s3StorageAwsRoleArn)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_type", s3EncryptionTypeNone)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "storage_location.1.encryption_kms_key_id", "")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.#", "1")), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.name", externalVolumeName)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.allow_writes", allowWritesFalse)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "show_output.0.comment", comment)), + assert.Check(resource.TestCheckResourceAttr("snowflake_external_volume.complete", "describe_output.#", "5")), + ), + }, + }, + }) +} + +// Test invalid parameter combinations throw errors +func TestAcc_External_Volume_Invalid_Cases(t *testing.T) { + id := acc.TestClient().Ids.RandomAccountObjectIdentifier() + externalVolumeName := id.Name() + s3StorageLocationInvalidStorageProvider := getS3StorageLocation(s3StorageLocationName, "invalid-storage-provider", s3StorageBaseUrl, s3StorageAwsRoleArn, s3EncryptionTypeNone, "") + s3StorageLocationWithAzureTenantId := config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(s3StorageLocationName), + "storage_provider": config.StringVariable(s3StorageProvider), + "storage_base_url": config.StringVariable(s3StorageBaseUrl), + "storage_aws_role_arn": config.StringVariable(s3StorageAwsRoleArn), + "encryption_type": config.StringVariable(s3EncryptionTypeSseKms), + "encryption_kms_key_id": config.StringVariable(s3EncryptionKmsKeyId), + "azure_tenant_id": config.StringVariable(azureTenantId), + }) + gcsStorageLocationAllParams := config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(gcsStorageLocationName), + "storage_provider": config.StringVariable(gcsStorageProvider), + "storage_base_url": config.StringVariable(gcsStorageBaseUrl), + "storage_aws_role_arn": config.StringVariable(s3StorageAwsRoleArn), + "encryption_type": config.StringVariable(gcsEncryptionTypeSseKms), + "encryption_kms_key_id": config.StringVariable(gcsEncryptionKmsKeyId), + "azure_tenant_id": config.StringVariable(azureTenantId), + }) + azureStorageLocationAllParams := config.MapVariable(map[string]config.Variable{ + "storage_location_name": config.StringVariable(azureStorageLocationName), + "storage_provider": config.StringVariable(azureStorageProvider), + "storage_base_url": config.StringVariable(azureStorageBaseUrl), + "storage_aws_role_arn": config.StringVariable(s3StorageAwsRoleArn), + "encryption_type": config.StringVariable(s3EncryptionTypeSseKms), + "encryption_kms_key_id": config.StringVariable(s3EncryptionKmsKeyId), + "azure_tenant_id": config.StringVariable(azureTenantId), + }) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + PreCheck: func() { acc.TestAccPreCheck(t) }, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + CheckDestroy: acc.CheckDestroy(t, resources.Warehouse), + Steps: []resource.TestStep{ + // invalid storage provider test + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/basic"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationInvalidStorageProvider), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("invalid storage provider: invalid-storage-provider"), + }, + // no storage locations test + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/basic"), + ConfigVariables: externalVolume(config.ListVariable(), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("At least 1 \"storage_location\" blocks are required"), + }, + // aws storage location doesn't specify storage_aws_role_arn + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/no-role-arn"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocation), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, missing storage_aws_role_arn key in an s3 storage location"), + }, + // azure storage location doesn't specify azure_tenant_id + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/no-tenant-id"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocation), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, missing azure_tenant_id provider key in an azure storage location"), + }, + // azure_tenant_id specified for s3 storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/s3/with-azure-tenant-id"), + ConfigVariables: externalVolume(config.ListVariable(s3StorageLocationWithAzureTenantId), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, azure_tenant_id provided for s3 storage location"), + }, + // storage_aws_role_arn specified for gcs storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationAllParams), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, storage_aws_role_arn provided for gcs storage location"), + }, + // azure_tenant_id specified for gcs storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/gcs/with-azure-tenant-id"), + ConfigVariables: externalVolume(config.ListVariable(gcsStorageLocationAllParams), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, azure_tenant_id provided for gcs storage location"), + }, + // storage_aws_role_arn specified for azure storage location + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/with-storage-aws-role-arn"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocationAllParams), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, storage_aws_role_arn provided for azure storage location"), + }, + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/with-encryption-type"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocationAllParams), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, encryption_type provided for azure storage location"), + }, + { + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_ExternalVolume/azure/with-encryption-kms-key-id"), + ConfigVariables: externalVolume(config.ListVariable(azureStorageLocationAllParams), externalVolumeName, "", ""), + ExpectError: regexp.MustCompile("unable to extract storage location, encryption_kms_key_id provided for azure storage location"), + }, + }, + }) +} diff --git a/pkg/resources/helpers.go b/pkg/resources/helpers.go index a7c78d2532..8a11630652 100644 --- a/pkg/resources/helpers.go +++ b/pkg/resources/helpers.go @@ -330,3 +330,183 @@ func ListDiff[T comparable](beforeList []T, afterList []T) (added []T, removed [ return added, removed } + +func StorageLocationsEqual(s1 sdk.ExternalVolumeStorageLocation, s2 sdk.ExternalVolumeStorageLocation) (bool, error) { + s1StorageProvider, err := GetStorageLocationStorageProvider(s1) + if err != nil { + return false, err + } + + s2StorageProvider, err := GetStorageLocationStorageProvider(s2) + if err != nil { + return false, err + } + + if s1StorageProvider != s2StorageProvider { + return false, nil + } + + switch s1StorageProvider { + case sdk.StorageProviderS3, sdk.StorageProviderS3GOV: + externalIdsEqual := s1.S3StorageLocationParams.StorageAwsExternalId == nil && s2.S3StorageLocationParams.StorageAwsExternalId == nil || + (s1.S3StorageLocationParams.StorageAwsExternalId != nil && s2.S3StorageLocationParams.StorageAwsExternalId != nil && + *s1.S3StorageLocationParams.StorageAwsExternalId == *s2.S3StorageLocationParams.StorageAwsExternalId) + + if externalIdsEqual && + s1.S3StorageLocationParams.Name == s2.S3StorageLocationParams.Name && + s1.S3StorageLocationParams.StorageProvider == s2.S3StorageLocationParams.StorageProvider && + s1.S3StorageLocationParams.StorageAwsRoleArn == s2.S3StorageLocationParams.StorageAwsRoleArn && + s1.S3StorageLocationParams.StorageBaseUrl == s2.S3StorageLocationParams.StorageBaseUrl { + + if s1.S3StorageLocationParams.Encryption == nil && s2.S3StorageLocationParams.Encryption == nil { + return true, nil + } else if s1.S3StorageLocationParams.Encryption != nil && s2.S3StorageLocationParams.Encryption != nil { + typeEqual := s1.S3StorageLocationParams.Encryption.Type == s2.S3StorageLocationParams.Encryption.Type + kmsKeyIdEqual := s1.S3StorageLocationParams.Encryption.KmsKeyId == nil && s2.S3StorageLocationParams.Encryption.KmsKeyId == nil || + (s1.S3StorageLocationParams.Encryption.KmsKeyId != nil && s2.S3StorageLocationParams.Encryption.KmsKeyId != nil && + *s1.S3StorageLocationParams.Encryption.KmsKeyId == *s2.S3StorageLocationParams.Encryption.KmsKeyId) + return typeEqual && kmsKeyIdEqual, nil + } + } + case sdk.StorageProviderGCS: + if s1.GCSStorageLocationParams.Name == s2.GCSStorageLocationParams.Name && + s1.GCSStorageLocationParams.StorageBaseUrl == s2.GCSStorageLocationParams.StorageBaseUrl { + + if s1.GCSStorageLocationParams.Encryption == nil && s2.GCSStorageLocationParams.Encryption == nil { + return true, nil + } else if s1.GCSStorageLocationParams.Encryption != nil && s2.GCSStorageLocationParams.Encryption != nil { + typeEqual := s1.GCSStorageLocationParams.Encryption.Type == s2.GCSStorageLocationParams.Encryption.Type + kmsKeyIdEqual := s1.GCSStorageLocationParams.Encryption.KmsKeyId == nil && s2.GCSStorageLocationParams.Encryption.KmsKeyId == nil || + (s1.GCSStorageLocationParams.Encryption.KmsKeyId != nil && s2.GCSStorageLocationParams.Encryption.KmsKeyId != nil && + *s1.GCSStorageLocationParams.Encryption.KmsKeyId == *s2.GCSStorageLocationParams.Encryption.KmsKeyId) + return typeEqual && kmsKeyIdEqual, nil + } + } + case sdk.StorageProviderAzure: + return s1.AzureStorageLocationParams.Name == s2.AzureStorageLocationParams.Name && + s1.AzureStorageLocationParams.AzureTenantId == s2.AzureStorageLocationParams.AzureTenantId && + s1.AzureStorageLocationParams.StorageBaseUrl == s2.AzureStorageLocationParams.StorageBaseUrl, nil + } + + return false, nil +} + +// Returns a copy of the given storage location with a 'temp_' prefix on the Name field +func CopyStorageLocationWithTempName( + storageLocation sdk.ExternalVolumeStorageLocation, +) (sdk.ExternalVolumeStorageLocation, error) { + storageProvider, err := GetStorageLocationStorageProvider(storageLocation) + if err != nil { + return sdk.ExternalVolumeStorageLocation{}, err + } + + currName, err := GetStorageLocationName(storageLocation) + if err != nil { + return sdk.ExternalVolumeStorageLocation{}, err + } + + newName := fmt.Sprintf("temp_%s", currName) + var tempNameStorageLocation sdk.ExternalVolumeStorageLocation + switch storageProvider { + case sdk.StorageProviderS3, sdk.StorageProviderS3GOV: + tempNameStorageLocation = sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: newName, + StorageProvider: storageLocation.S3StorageLocationParams.StorageProvider, + StorageBaseUrl: storageLocation.S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: storageLocation.S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: storageLocation.S3StorageLocationParams.StorageAwsExternalId, + Encryption: storageLocation.S3StorageLocationParams.Encryption, + }, + } + case sdk.StorageProviderGCS: + tempNameStorageLocation = sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: newName, + StorageBaseUrl: storageLocation.GCSStorageLocationParams.StorageBaseUrl, + Encryption: storageLocation.GCSStorageLocationParams.Encryption, + }, + } + case sdk.StorageProviderAzure: + tempNameStorageLocation = sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: newName, + StorageBaseUrl: storageLocation.AzureStorageLocationParams.StorageBaseUrl, + AzureTenantId: storageLocation.AzureStorageLocationParams.AzureTenantId, + }, + } + } + + return tempNameStorageLocation, nil +} + +func GetStorageLocationName(s sdk.ExternalVolumeStorageLocation) (string, error) { + if s.S3StorageLocationParams != nil && (*s.S3StorageLocationParams != sdk.S3StorageLocationParams{}) { + if len(s.S3StorageLocationParams.Name) == 0 { + return "", fmt.Errorf("Invalid S3 storage location - no name set") + } + + return s.S3StorageLocationParams.Name, nil + } else if s.GCSStorageLocationParams != nil && (*s.GCSStorageLocationParams != sdk.GCSStorageLocationParams{}) { + if len(s.GCSStorageLocationParams.Name) == 0 { + return "", fmt.Errorf("Invalid GCS storage location - no name set") + } + + return s.GCSStorageLocationParams.Name, nil + } else if s.AzureStorageLocationParams != nil && (*s.AzureStorageLocationParams != sdk.AzureStorageLocationParams{}) { + if len(s.AzureStorageLocationParams.Name) == 0 { + return "", fmt.Errorf("Invalid Azure storage location - no name set") + } + + return s.AzureStorageLocationParams.Name, nil + } else { + return "", fmt.Errorf("Invalid storage location") + } +} + +func GetStorageLocationStorageProvider(s sdk.ExternalVolumeStorageLocation) (sdk.StorageProvider, error) { + if s.S3StorageLocationParams != nil && (*s.S3StorageLocationParams != sdk.S3StorageLocationParams{}) { + return sdk.ToStorageProvider(string(s.S3StorageLocationParams.StorageProvider)) + } else if s.GCSStorageLocationParams != nil && (*s.GCSStorageLocationParams != sdk.GCSStorageLocationParams{}) { + return sdk.StorageProviderGCS, nil + } else if s.AzureStorageLocationParams != nil && (*s.AzureStorageLocationParams != sdk.AzureStorageLocationParams{}) { + return sdk.StorageProviderAzure, nil + } else { + return "", fmt.Errorf("Invalid storage location") + } +} + +// Returns the index of the last matching elements in the list +// e.g. [1,2,3] [1,3,2] -> 0, [1,2,3] [1,2,4] -> 1 +// -1 is returned if there are no common prefixes in the list +func LongestCommonPrefix(a []sdk.ExternalVolumeStorageLocation, b []sdk.ExternalVolumeStorageLocation) (int, error) { + longestCommonPrefix := 0 + + if len(a) == 0 || len(b) == 0 { + return -1, nil + } + + first_elements_equal, err := StorageLocationsEqual(a[0], b[0]) + if err != nil { + return -1, err + } + + if !first_elements_equal { + return -1, nil + } + + for i := 1; i < min(len(a), len(b)); i++ { + storageLocationsAreEqual, err := StorageLocationsEqual(a[i], b[i]) + if err != nil { + return -1, err + } + + if !storageLocationsAreEqual { + break + } + + longestCommonPrefix = i + } + + return longestCommonPrefix, nil +} diff --git a/pkg/resources/helpers_test.go b/pkg/resources/helpers_test.go index c143d40f03..f4255c07af 100644 --- a/pkg/resources/helpers_test.go +++ b/pkg/resources/helpers_test.go @@ -403,3 +403,1769 @@ func Test_DataTypeIssue3007DiffSuppressFunc(t *testing.T) { }) } } + +// External volume helper tests + +var s3StorageLocationA = sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, +} + +var s3StorageLocationB = sdk.S3StorageLocationParams{ + Name: s3StorageLocationName2, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, +} + +var azureStorageLocationA = sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, +} + +var azureStorageLocationB = sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName2, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, +} + +var gcsStorageLocationA = sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, +} + +var gcsStorageLocationB = sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName2, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, +} + +var gcsStorageLocationC = sdk.GCSStorageLocationParams{ + Name: "test", + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, +} + +var s3GovStorageLocationA = sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, +} + +func Test_GetStorageLocationName(t *testing.T) { + testCases := []struct { + Name string + StorageLocation sdk.ExternalVolumeStorageLocation + ExpectedName string + }{ + { + Name: "S3 storage location name succesfully read", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &s3StorageLocationA}, + ExpectedName: s3StorageLocationA.Name, + }, + { + Name: "S3GOV storage location name succesfully read", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &s3GovStorageLocationA}, + ExpectedName: s3GovStorageLocationA.Name, + }, + { + Name: "GCS storage location name succesfully read", + StorageLocation: sdk.ExternalVolumeStorageLocation{GCSStorageLocationParams: &gcsStorageLocationA}, + ExpectedName: gcsStorageLocationA.Name, + }, + { + Name: "Azure storage location name succesfully read", + StorageLocation: sdk.ExternalVolumeStorageLocation{AzureStorageLocationParams: &azureStorageLocationA}, + ExpectedName: azureStorageLocationA.Name, + }, + } + + invalidTestCases := []struct { + Name string + StorageLocation sdk.ExternalVolumeStorageLocation + }{ + { + Name: "Empty S3 storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &sdk.S3StorageLocationParams{}}, + }, + { + Name: "Empty GCS storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{GCSStorageLocationParams: &sdk.GCSStorageLocationParams{}}, + }, + { + Name: "Empty Azure storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{AzureStorageLocationParams: &sdk.AzureStorageLocationParams{}}, + }, + { + Name: "Empty storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + name, err := resources.GetStorageLocationName(tc.StorageLocation) + require.NoError(t, err) + assert.Equal(t, tc.ExpectedName, name) + }) + } + for _, tc := range invalidTestCases { + t.Run(tc.Name, func(t *testing.T) { + _, err := resources.GetStorageLocationName(tc.StorageLocation) + require.Error(t, err) + }) + } +} + +func Test_GetStorageLocationStorageProvider(t *testing.T) { + testCases := []struct { + Name string + StorageLocation sdk.ExternalVolumeStorageLocation + ExpectedStorageProvider sdk.StorageProvider + }{ + { + Name: "S3 storage provider", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &s3StorageLocationA}, + ExpectedStorageProvider: sdk.StorageProviderS3, + }, + { + Name: "S3GOV storage provider", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &s3GovStorageLocationA}, + ExpectedStorageProvider: sdk.StorageProviderS3GOV, + }, + { + Name: "GCS storage provider", + StorageLocation: sdk.ExternalVolumeStorageLocation{GCSStorageLocationParams: &gcsStorageLocationA}, + ExpectedStorageProvider: sdk.StorageProviderGCS, + }, + { + Name: "Azure storage provider", + StorageLocation: sdk.ExternalVolumeStorageLocation{AzureStorageLocationParams: &azureStorageLocationA}, + ExpectedStorageProvider: sdk.StorageProviderAzure, + }, + } + + invalidTestCases := []struct { + Name string + StorageLocation sdk.ExternalVolumeStorageLocation + }{ + { + Name: "Empty S3 storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &sdk.S3StorageLocationParams{}}, + }, + { + Name: "Empty GCS storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{GCSStorageLocationParams: &sdk.GCSStorageLocationParams{}}, + }, + { + Name: "Empty Azure storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{AzureStorageLocationParams: &sdk.AzureStorageLocationParams{}}, + }, + { + Name: "Empty storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + storageProvider, err := resources.GetStorageLocationStorageProvider(tc.StorageLocation) + require.NoError(t, err) + assert.Equal(t, tc.ExpectedStorageProvider, storageProvider) + }) + } + for _, tc := range invalidTestCases { + t.Run(tc.Name, func(t *testing.T) { + _, err := resources.GetStorageLocationName(tc.StorageLocation) + require.Error(t, err) + }) + } +} + +var s3StorageAwsExternalId = "1234567890" + +func Test_CopyStorageLocationWithTempName(t *testing.T) { + t.Run("S3 storage location", func(t *testing.T) { + storageLocationInput := sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &s3StorageLocationA} + copiedStorageLocation, err := resources.CopyStorageLocationWithTempName(storageLocationInput) + require.NoError(t, err) + assert.Equal(t, copiedStorageLocation.S3StorageLocationParams.Name, fmt.Sprintf("temp_%s", s3StorageLocationA.Name)) + assert.Equal(t, copiedStorageLocation.S3StorageLocationParams.StorageProvider, s3StorageLocationA.StorageProvider) + assert.Equal(t, copiedStorageLocation.S3StorageLocationParams.StorageBaseUrl, s3StorageLocationA.StorageBaseUrl) + assert.Equal(t, copiedStorageLocation.S3StorageLocationParams.StorageAwsRoleArn, s3StorageLocationA.StorageAwsRoleArn) + assert.Equal(t, copiedStorageLocation.S3StorageLocationParams.StorageAwsExternalId, s3StorageLocationA.StorageAwsExternalId) + assert.Equal(t, copiedStorageLocation.S3StorageLocationParams.Encryption.Type, s3StorageLocationA.Encryption.Type) + assert.Equal(t, *copiedStorageLocation.S3StorageLocationParams.Encryption.KmsKeyId, *s3StorageLocationA.Encryption.KmsKeyId) + }) + + t.Run("GCS storage location", func(t *testing.T) { + storageLocationInput := sdk.ExternalVolumeStorageLocation{GCSStorageLocationParams: &gcsStorageLocationA} + copiedStorageLocation, err := resources.CopyStorageLocationWithTempName(storageLocationInput) + require.NoError(t, err) + assert.Equal(t, copiedStorageLocation.GCSStorageLocationParams.Name, fmt.Sprintf("temp_%s", gcsStorageLocationA.Name)) + assert.Equal(t, copiedStorageLocation.GCSStorageLocationParams.StorageBaseUrl, gcsStorageLocationA.StorageBaseUrl) + assert.Equal(t, copiedStorageLocation.GCSStorageLocationParams.Encryption.Type, gcsStorageLocationA.Encryption.Type) + assert.Equal(t, *copiedStorageLocation.GCSStorageLocationParams.Encryption.KmsKeyId, *gcsStorageLocationA.Encryption.KmsKeyId) + }) + + t.Run("Azure storage location", func(t *testing.T) { + storageLocationInput := sdk.ExternalVolumeStorageLocation{AzureStorageLocationParams: &azureStorageLocationA} + copiedStorageLocation, err := resources.CopyStorageLocationWithTempName(storageLocationInput) + require.NoError(t, err) + assert.Equal(t, copiedStorageLocation.AzureStorageLocationParams.Name, fmt.Sprintf("temp_%s", azureStorageLocationA.Name)) + assert.Equal(t, copiedStorageLocation.AzureStorageLocationParams.StorageBaseUrl, azureStorageLocationA.StorageBaseUrl) + assert.Equal(t, copiedStorageLocation.AzureStorageLocationParams.AzureTenantId, azureStorageLocationA.AzureTenantId) + }) + + invalidTestCases := []struct { + Name string + StorageLocation sdk.ExternalVolumeStorageLocation + }{ + { + Name: "Empty S3 storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{S3StorageLocationParams: &sdk.S3StorageLocationParams{}}, + }, + { + Name: "Empty GCS storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{GCSStorageLocationParams: &sdk.GCSStorageLocationParams{}}, + }, + { + Name: "Empty Azure storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{AzureStorageLocationParams: &sdk.AzureStorageLocationParams{}}, + }, + { + Name: "Empty storage location", + StorageLocation: sdk.ExternalVolumeStorageLocation{}, + }, + } + + for _, tc := range invalidTestCases { + t.Run(tc.Name, func(t *testing.T) { + _, err := resources.CopyStorageLocationWithTempName(tc.StorageLocation) + require.Error(t, err) + }) + } +} + +func Test_LongestCommonPrefix(t *testing.T) { + testCases := []struct { + Name string + ListA []sdk.ExternalVolumeStorageLocation + ListB []sdk.ExternalVolumeStorageLocation + ExpectedOutput int + }{ + { + Name: "Two empty lists", + ListA: []sdk.ExternalVolumeStorageLocation{}, + ListB: []sdk.ExternalVolumeStorageLocation{}, + ExpectedOutput: -1, + }, + { + Name: "First list empty", + ListA: []sdk.ExternalVolumeStorageLocation{}, + ListB: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ExpectedOutput: -1, + }, + { + Name: "Second list empty", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{}, + ExpectedOutput: -1, + }, + { + Name: "Lists with no common prefix - length 1", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationB}}, + ExpectedOutput: -1, + }, + { + Name: "Lists with no common prefix - length 2", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}, {AzureStorageLocationParams: &azureStorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationB}, {AzureStorageLocationParams: &azureStorageLocationB}}, + ExpectedOutput: -1, + }, + { + Name: "Identical lists - length 1", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ExpectedOutput: 0, + }, + { + Name: "Identical lists - length 2", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}, {AzureStorageLocationParams: &azureStorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}, {AzureStorageLocationParams: &azureStorageLocationA}}, + ExpectedOutput: 1, + }, + { + Name: "Identical lists - length 3", + ListA: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {S3StorageLocationParams: &s3GovStorageLocationA}, + }, + ListB: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {S3StorageLocationParams: &s3GovStorageLocationA}, + }, + ExpectedOutput: 2, + }, + { + Name: "Lists with a common prefix - length 3, matching up to and including index 1", + ListA: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationA}, + }, + ListB: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationB}, + }, + ExpectedOutput: 1, + }, + { + Name: "Lists with a common prefix - length 4, matching up to and including index 2", + ListA: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationB}, + }, + ListB: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationC}, + }, + ExpectedOutput: 2, + }, + { + Name: "Lists with a common prefix - length 4, matching up to and including index 1", + ListA: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationC}, + }, + ListB: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationB}, + {GCSStorageLocationParams: &gcsStorageLocationC}, + }, + ExpectedOutput: 1, + }, + { + Name: "Lists with a common prefix - different lengths, matching up to and including index 1 (last index of shorter list)", + ListA: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationA}, + }, + ListB: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + }, + ExpectedOutput: 1, + }, + { + Name: "Lists with a common prefix - different lengths, matching up to and including index 2", + ListA: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {S3StorageLocationParams: &s3StorageLocationB}, + {GCSStorageLocationParams: &gcsStorageLocationA}, + {GCSStorageLocationParams: &gcsStorageLocationB}, + {AzureStorageLocationParams: &azureStorageLocationB}, + }, + ListB: []sdk.ExternalVolumeStorageLocation{ + {S3StorageLocationParams: &s3StorageLocationA}, + {AzureStorageLocationParams: &azureStorageLocationA}, + {S3StorageLocationParams: &s3StorageLocationB}, + {GCSStorageLocationParams: &gcsStorageLocationB}, + {AzureStorageLocationParams: &azureStorageLocationB}, + }, + ExpectedOutput: 2, + }, + } + + invalidTestCases := []struct { + Name string + ListA []sdk.ExternalVolumeStorageLocation + ListB []sdk.ExternalVolumeStorageLocation + }{ + { + Name: "Empty S3 storage location", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &sdk.S3StorageLocationParams{}}}, + }, + { + Name: "Empty GCS storage location", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{GCSStorageLocationParams: &sdk.GCSStorageLocationParams{}}}, + }, + { + Name: "Empty Azure storage location", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{AzureStorageLocationParams: &sdk.AzureStorageLocationParams{}}}, + }, + { + Name: "Empty storage location", + ListA: []sdk.ExternalVolumeStorageLocation{{S3StorageLocationParams: &s3StorageLocationA}}, + ListB: []sdk.ExternalVolumeStorageLocation{{}}, + }, + } + + for _, tc := range invalidTestCases { + t.Run(tc.Name, func(t *testing.T) { + _, err := resources.LongestCommonPrefix(tc.ListA, tc.ListB) + require.Error(t, err) + }) + } + + for _, tc := range testCases { + t.Run(tc.Name, func(t *testing.T) { + longestCommonPrefix, err := resources.LongestCommonPrefix(tc.ListA, tc.ListB) + require.NoError(t, err) + assert.Equal(t, tc.ExpectedOutput, longestCommonPrefix) + }) + } +} + +func Test_StorageLocationsEqual(t *testing.T) { + equalCases := []struct { + Name string + StorageLocationA sdk.ExternalVolumeStorageLocation + StorageLocationB sdk.ExternalVolumeStorageLocation + }{ + { + Name: "S3 storage location", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3 storage location - sse s3 encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + }, + { + Name: "S3 storage location - none encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionNone, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionNone, + }, + }, + }, + }, + { + Name: "S3 storage location - no encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + }, + { + Name: "S3 storage location - no StorageAwsExternalId", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + }, + { + Name: "S3Gov storage location", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3Gov storage location - sse s3 encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + }, + { + Name: "S3Gov storage location - none encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionNone, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionNone, + }, + }, + }, + }, + { + Name: "S3Gov storage location - no encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + }, + { + Name: "S3Gov storage location - no StorageAwsExternalId", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + }, + { + Name: "GCS storage location", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "GCS storage location - no kms key id", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeNone, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeNone, + }, + }, + }, + }, + { + Name: "GCS storage location - no encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + }, + }, + }, + { + Name: "Azure storage location", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + } + + notEqualCases := []struct { + Name string + StorageLocationA sdk.ExternalVolumeStorageLocation + StorageLocationB sdk.ExternalVolumeStorageLocation + }{ + // Types that don't match + { + Name: "S3/S3Gov storage locations", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3/GCS storage locations", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3/Azure storage locations", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + { + Name: "S3Gov/GCS storage locations", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3Gov/Azure storage locations", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + { + Name: "GCS/Azure storage locations", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + // Types that match, but some have optional fields and others don't + { + Name: "S3 storage location - missing kms key id", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + }, + { + Name: "S3 storage location - missing encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + }, + { + Name: "S3 storage location - missing StorageAwsExternalId", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + }, + { + Name: "S3GOV storage location - missing kms key id", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + }, + { + Name: "S3GOV storage location - missing encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseS3, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + }, + { + Name: "S3GOV storage location - missing StorageAwsExternalId", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + }, + { + Name: "GCS storage location - missing kms key id", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeNone, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeNone, + }, + }, + }, + }, + { + Name: "GCS storage location - missing encryption", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeNone, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + }, + }, + }, + // Types and fields match, but values not equal + { + Name: "S3 storage location - names don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: "a", + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3 storage location - base urls don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: "a", + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3 storage location - role arns", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: "a", + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3 storage location - external ids don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageLocationName, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3 storage location - encryption types don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionNone, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3 storage location - kms key ids don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3StorageLocationName, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3GOV storage location - names don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: "a", + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3GOV storage location - base urls don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: "a", + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3GOV storage location - role arns", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: "a", + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3GOV storage location - external ids don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageLocationName, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3GOV storage location - encryption types don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionNone, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "S3GOV storage location - kms key ids don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3StorageLocationName, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3GOV, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "GCS storage location - names don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: "a", + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "GCS storage location - base urls don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: "a", + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "GCS storage location - encryption types don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeNone, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "GCS storage location - encryption kms ids don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsStorageLocationName, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "Azure storage location - names don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: "a", + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + { + Name: "Azure storage location - base urls don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: "a", + AzureTenantId: azureTenantId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + { + Name: "Azure storage location - tenant ids don't match", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: "a", + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + } + + invalidTestCases := []struct { + Name string + StorageLocationA sdk.ExternalVolumeStorageLocation + StorageLocationB sdk.ExternalVolumeStorageLocation + }{ + { + Name: "Empty S3 storage location as argument 1", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{}, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "Empty S3 storage location as argument 2", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + StorageAwsExternalId: &s3StorageAwsExternalId, + Encryption: &sdk.ExternalVolumeS3Encryption{ + Type: sdk.S3EncryptionTypeSseKms, + KmsKeyId: &s3EncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{}, + }, + }, + { + Name: "Empty GCS storage location as argument 1", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{}, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + }, + { + Name: "Empty GCS storage location as argument 2", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{ + Name: gcsStorageLocationName, + StorageBaseUrl: gcsStorageBaseUrl, + Encryption: &sdk.ExternalVolumeGCSEncryption{ + Type: sdk.GCSEncryptionTypeSseKms, + KmsKeyId: &gcsEncryptionKmsKeyId, + }, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + GCSStorageLocationParams: &sdk.GCSStorageLocationParams{}, + }, + }, + { + Name: "Empty Azure storage location as argument 1", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{}, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + }, + { + Name: "Empty Azure storage location as argument 2", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{ + Name: azureStorageLocationName, + StorageBaseUrl: azureStorageBaseUrl, + AzureTenantId: azureTenantId, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + AzureStorageLocationParams: &sdk.AzureStorageLocationParams{}, + }, + }, + { + Name: "Empty storage location as argument 1", + StorageLocationA: sdk.ExternalVolumeStorageLocation{}, + StorageLocationB: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + }, + { + Name: "Empty storage location as argument 2", + StorageLocationA: sdk.ExternalVolumeStorageLocation{ + S3StorageLocationParams: &sdk.S3StorageLocationParams{ + Name: s3StorageLocationName, + StorageProvider: sdk.S3StorageProviderS3, + StorageBaseUrl: s3StorageBaseUrl, + StorageAwsRoleArn: s3StorageAwsRoleArn, + }, + }, + StorageLocationB: sdk.ExternalVolumeStorageLocation{}, + }, + } + + for _, tc := range equalCases { + t.Run(tc.Name, func(t *testing.T) { + storageLocationsEqual, err := resources.StorageLocationsEqual(tc.StorageLocationA, tc.StorageLocationB) + require.NoError(t, err) + assert.True(t, storageLocationsEqual) + }) + } + + for _, tc := range notEqualCases { + t.Run(tc.Name, func(t *testing.T) { + storageLocationsEqual, err := resources.StorageLocationsEqual(tc.StorageLocationA, tc.StorageLocationB) + require.NoError(t, err) + assert.False(t, storageLocationsEqual) + }) + } + + for _, tc := range invalidTestCases { + t.Run(tc.Name, func(t *testing.T) { + _, err := resources.StorageLocationsEqual(tc.StorageLocationA, tc.StorageLocationB) + require.Error(t, err) + }) + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/basic/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/basic/test.tf new file mode 100644 index 0000000000..e0f7a42a41 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/basic/test.tf @@ -0,0 +1,12 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/basic/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/basic/variables.tf new file mode 100644 index 0000000000..a704fdd13a --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/basic/variables.tf @@ -0,0 +1,6 @@ +variable "name" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/complete/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/complete/test.tf new file mode 100644 index 0000000000..2744f4180f --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/complete/test.tf @@ -0,0 +1,14 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/complete/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/complete/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/complete/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/no-tenant-id/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/no-tenant-id/test.tf new file mode 100644 index 0000000000..e7b761012e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/no-tenant-id/test.tf @@ -0,0 +1,11 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/no-tenant-id/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/no-tenant-id/variables.tf new file mode 100644 index 0000000000..a704fdd13a --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/no-tenant-id/variables.tf @@ -0,0 +1,6 @@ +variable "name" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-kms-key-id/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-kms-key-id/test.tf new file mode 100644 index 0000000000..9c73c53a6e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-kms-key-id/test.tf @@ -0,0 +1,15 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + encryption_kms_key_id = storage_location.value["encryption_kms_key_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-kms-key-id/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-kms-key-id/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-kms-key-id/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-type/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-type/test.tf new file mode 100644 index 0000000000..dabc182639 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-type/test.tf @@ -0,0 +1,15 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + encryption_type = storage_location.value["encryption_type"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-type/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-type/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-encryption-type/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-storage-aws-role-arn/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-storage-aws-role-arn/test.tf new file mode 100644 index 0000000000..e61ce6e150 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-storage-aws-role-arn/test.tf @@ -0,0 +1,15 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-storage-aws-role-arn/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-storage-aws-role-arn/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/azure/with-storage-aws-role-arn/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/basic/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/basic/test.tf new file mode 100644 index 0000000000..e7b761012e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/basic/test.tf @@ -0,0 +1,11 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/basic/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/basic/variables.tf new file mode 100644 index 0000000000..a704fdd13a --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/basic/variables.tf @@ -0,0 +1,6 @@ +variable "name" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-encryption-type/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-encryption-type/test.tf new file mode 100644 index 0000000000..4e061d603a --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-encryption-type/test.tf @@ -0,0 +1,14 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + encryption_type = storage_location.value["encryption_type"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-encryption-type/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-encryption-type/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-encryption-type/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type/test.tf new file mode 100644 index 0000000000..6ae64ecfa3 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type/test.tf @@ -0,0 +1,15 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + encryption_type = storage_location.value["encryption_type"] + encryption_kms_key_id = storage_location.value["encryption_kms_key_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete-add-kms-encryption-type/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete/test.tf new file mode 100644 index 0000000000..85042d7b39 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete/test.tf @@ -0,0 +1,13 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/complete/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-azure-tenant-id/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-azure-tenant-id/test.tf new file mode 100644 index 0000000000..1fd261f47c --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-azure-tenant-id/test.tf @@ -0,0 +1,16 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + encryption_type = storage_location.value["encryption_type"] + encryption_kms_key_id = storage_location.value["encryption_kms_key_id"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-azure-tenant-id/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-azure-tenant-id/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-azure-tenant-id/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn/test.tf new file mode 100644 index 0000000000..713a8e9bf0 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn/test.tf @@ -0,0 +1,16 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + encryption_type = storage_location.value["encryption_type"] + encryption_kms_key_id = storage_location.value["encryption_kms_key_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/gcs/with-storage-aws-role-arn/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/multiple/complete/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/multiple/complete/test.tf new file mode 100644 index 0000000000..25c33e59ad --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/multiple/complete/test.tf @@ -0,0 +1,31 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.s3_storage_locations + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + } + } + dynamic "storage_location" { + for_each = var.gcs_storage_locations + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + } + } + dynamic "storage_location" { + for_each = var.azure_storage_locations + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/multiple/complete/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/multiple/complete/variables.tf new file mode 100644 index 0000000000..de24426a29 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/multiple/complete/variables.tf @@ -0,0 +1,18 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "s3_storage_locations" { + type = list(map(string)) +} +variable "gcs_storage_locations" { + type = list(map(string)) +} +variable "azure_storage_locations" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/basic/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/basic/test.tf new file mode 100644 index 0000000000..ec5f3d0d87 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/basic/test.tf @@ -0,0 +1,12 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/basic/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/basic/variables.tf new file mode 100644 index 0000000000..a704fdd13a --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/basic/variables.tf @@ -0,0 +1,6 @@ +variable "name" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-encryption-type/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-encryption-type/test.tf new file mode 100644 index 0000000000..7c043f8d3d --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-encryption-type/test.tf @@ -0,0 +1,15 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + encryption_type = storage_location.value["encryption_type"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-encryption-type/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-encryption-type/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-encryption-type/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type/test.tf new file mode 100644 index 0000000000..713a8e9bf0 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type/test.tf @@ -0,0 +1,16 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + encryption_type = storage_location.value["encryption_type"] + encryption_kms_key_id = storage_location.value["encryption_kms_key_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete-add-kms-encryption-type/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete/test.tf new file mode 100644 index 0000000000..89c7b847f0 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete/test.tf @@ -0,0 +1,14 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/complete/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/no-role-arn/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/no-role-arn/test.tf new file mode 100644 index 0000000000..e7b761012e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/no-role-arn/test.tf @@ -0,0 +1,11 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/no-role-arn/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/no-role-arn/variables.tf new file mode 100644 index 0000000000..a704fdd13a --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/no-role-arn/variables.tf @@ -0,0 +1,6 @@ +variable "name" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/with-azure-tenant-id/test.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/with-azure-tenant-id/test.tf new file mode 100644 index 0000000000..9c6a49d6a7 --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/with-azure-tenant-id/test.tf @@ -0,0 +1,17 @@ +resource "snowflake_external_volume" "complete" { + name = var.name + comment = var.comment + allow_writes = var.allow_writes + dynamic "storage_location" { + for_each = var.storage_location + content { + storage_location_name = storage_location.value["storage_location_name"] + storage_provider = storage_location.value["storage_provider"] + storage_base_url = storage_location.value["storage_base_url"] + storage_aws_role_arn = storage_location.value["storage_aws_role_arn"] + encryption_type = storage_location.value["encryption_type"] + encryption_kms_key_id = storage_location.value["encryption_kms_key_id"] + azure_tenant_id = storage_location.value["azure_tenant_id"] + } + } +} diff --git a/pkg/resources/testdata/TestAcc_ExternalVolume/s3/with-azure-tenant-id/variables.tf b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/with-azure-tenant-id/variables.tf new file mode 100644 index 0000000000..e3491d338e --- /dev/null +++ b/pkg/resources/testdata/TestAcc_ExternalVolume/s3/with-azure-tenant-id/variables.tf @@ -0,0 +1,12 @@ +variable "name" { + type = string +} +variable "comment" { + type = string +} +variable "allow_writes" { + type = string +} +variable "storage_location" { + type = list(map(string)) +} diff --git a/pkg/schemas/external_volume.go b/pkg/schemas/external_volume.go new file mode 100644 index 0000000000..0a6d9184b1 --- /dev/null +++ b/pkg/schemas/external_volume.go @@ -0,0 +1,47 @@ +package schemas + +import ( + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +var DescribeExternalVolumeSchema = map[string]*schema.Schema{ + "parent": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Computed: true, + }, + "value": { + Type: schema.TypeString, + Computed: true, + }, + "default": { + Type: schema.TypeString, + Computed: true, + }, +} + +var _ = ShowExternalVolumeSchema + +func ExternalVolumeDescriptionToSchema(description []sdk.ExternalVolumeProperty) []map[string]any { + result := make([]map[string]any, len(description)) + for i, row := range description { + result[i] = map[string]any{ + "parent": row.Parent, + "name": row.Name, + "type": row.Type, + "value": row.Value, + "default": row.Default, + } + } + return result +} + +var _ = ExternalVolumeDescriptionToSchema diff --git a/pkg/schemas/external_volume_gen.go b/pkg/schemas/external_volume_gen.go new file mode 100644 index 0000000000..1a9f112980 --- /dev/null +++ b/pkg/schemas/external_volume_gen.go @@ -0,0 +1,36 @@ +// Code generated by sdk-to-schema generator; DO NOT EDIT. + +package schemas + +import ( + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// ShowExternalVolumeSchema represents output of SHOW query for the single ExternalVolume. +var ShowExternalVolumeSchema = map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "allow_writes": { + Type: schema.TypeBool, + Computed: true, + }, + "comment": { + Type: schema.TypeString, + Computed: true, + }, +} + +var _ = ShowExternalVolumeSchema + +func ExternalVolumeToSchema(externalVolume *sdk.ExternalVolume) map[string]any { + externalVolumeSchema := make(map[string]any) + externalVolumeSchema["name"] = externalVolume.Name + externalVolumeSchema["allow_writes"] = externalVolume.AllowWrites + externalVolumeSchema["comment"] = externalVolume.Comment + return externalVolumeSchema +} + +var _ = ExternalVolumeToSchema diff --git a/pkg/schemas/gen/sdk_show_result_structs.go b/pkg/schemas/gen/sdk_show_result_structs.go index ea2e977160..0d1ac4ff31 100644 --- a/pkg/schemas/gen/sdk_show_result_structs.go +++ b/pkg/schemas/gen/sdk_show_result_structs.go @@ -51,6 +51,7 @@ var SdkShowResultStructs = []any{ sdk.User{}, sdk.View{}, sdk.Warehouse{}, + sdk.ExternalVolume{}, } // TODO [SNOW-1501905]: currently all this structs have the "Show" added to the schema, while these are not show outputs diff --git a/pkg/sdk/external_volumes_def.go b/pkg/sdk/external_volumes_def.go index fb4f610be9..5cfee4ddf7 100644 --- a/pkg/sdk/external_volumes_def.go +++ b/pkg/sdk/external_volumes_def.go @@ -1,12 +1,18 @@ package sdk -import g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/generator" +import ( + "fmt" + "strings" + + g "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/poc/generator" +) //go:generate go run ./poc/main.go type ( - S3EncryptionType string + StorageProvider string S3StorageProvider string + S3EncryptionType string GCSEncryptionType string ) @@ -18,8 +24,62 @@ var ( GCSEncryptionTypeNone GCSEncryptionType = "NONE" S3StorageProviderS3 S3StorageProvider = "S3" S3StorageProviderS3GOV S3StorageProvider = "S3GOV" + StorageProviderGCS StorageProvider = "GCS" + StorageProviderAzure StorageProvider = "AZURE" + StorageProviderS3 StorageProvider = "S3" + StorageProviderS3GOV StorageProvider = "S3GOV" ) +func ToS3EncryptionType(s string) (S3EncryptionType, error) { + switch strings.ToUpper(s) { + case string(S3EncryptionTypeSseS3): + return S3EncryptionTypeSseS3, nil + case string(S3EncryptionTypeSseKms): + return S3EncryptionTypeSseKms, nil + case string(S3EncryptionNone): + return S3EncryptionNone, nil + default: + return "", fmt.Errorf("invalid s3 encryption type: %s", s) + } +} + +func ToGCSEncryptionType(s string) (GCSEncryptionType, error) { + switch strings.ToUpper(s) { + case string(GCSEncryptionTypeSseKms): + return GCSEncryptionTypeSseKms, nil + case string(GCSEncryptionTypeNone): + return GCSEncryptionTypeNone, nil + default: + return "", fmt.Errorf("invalid gcs encryption type: %s", s) + } +} + +func ToStorageProvider(s string) (StorageProvider, error) { + switch strings.ToUpper(s) { + case string(StorageProviderGCS): + return StorageProviderGCS, nil + case string(StorageProviderAzure): + return StorageProviderAzure, nil + case string(StorageProviderS3): + return StorageProviderS3, nil + case string(StorageProviderS3GOV): + return StorageProviderS3GOV, nil + default: + return "", fmt.Errorf("invalid storage provider: %s", s) + } +} + +func ToS3StorageProvider(s string) (S3StorageProvider, error) { + switch strings.ToUpper(s) { + case string(S3StorageProviderS3): + return S3StorageProviderS3, nil + case string(S3StorageProviderS3GOV): + return S3StorageProviderS3GOV, nil + default: + return "", fmt.Errorf("invalid s3 storage provider: %s", s) + } +} + var externalS3StorageLocationDef = g.NewQueryStruct("S3StorageLocationParams"). TextAssignment("NAME", g.ParameterOptions().SingleQuotes().Required()). Assignment("STORAGE_PROVIDER", g.KindOfT[S3StorageProvider](), g.ParameterOptions().SingleQuotes().Required()). @@ -36,7 +96,7 @@ var externalS3StorageLocationDef = g.NewQueryStruct("S3StorageLocationParams"). var externalGCSStorageLocationDef = g.NewQueryStruct("GCSStorageLocationParams"). TextAssignment("NAME", g.ParameterOptions().SingleQuotes().Required()). - PredefinedQueryStructField("StorageProviderGcs", "string", g.StaticOptions().SQL("STORAGE_PROVIDER = 'GCS'")). + PredefinedQueryStructField("StorageProviderGcs", "string", g.StaticOptions().SQL(fmt.Sprintf("STORAGE_PROVIDER = '%s'", StorageProviderGCS))). TextAssignment("STORAGE_BASE_URL", g.ParameterOptions().SingleQuotes().Required()). OptionalQueryStructField( "Encryption", @@ -48,7 +108,7 @@ var externalGCSStorageLocationDef = g.NewQueryStruct("GCSStorageLocationParams") var externalAzureStorageLocationDef = g.NewQueryStruct("AzureStorageLocationParams"). TextAssignment("NAME", g.ParameterOptions().SingleQuotes().Required()). - PredefinedQueryStructField("StorageProviderAzure", "string", g.StaticOptions().SQL("STORAGE_PROVIDER = 'AZURE'")). + PredefinedQueryStructField("StorageProviderAzure", "string", g.StaticOptions().SQL(fmt.Sprintf("STORAGE_PROVIDER = '%s'", StorageProviderAzure))). TextAssignment("AZURE_TENANT_ID", g.ParameterOptions().SingleQuotes().Required()). TextAssignment("STORAGE_BASE_URL", g.ParameterOptions().SingleQuotes().Required()) @@ -148,11 +208,11 @@ var ExternalVolumesDef = g.NewInterface( "https://docs.snowflake.com/en/sql-reference/sql/show-external-volumes", g.DbStruct("externalVolumeShowRow"). Text("name"). - Text("allow_writes"). - Text("comment"), + Bool("allow_writes"). + OptionalText("comment"), g.PlainStruct("ExternalVolume"). Text("Name"). - Text("AllowWrites"). + Bool("AllowWrites"). Text("Comment"), g.NewQueryStruct("ShowExternalVolumes"). Show(). diff --git a/pkg/sdk/external_volumes_gen.go b/pkg/sdk/external_volumes_gen.go index 726e3ab819..a2361d0354 100644 --- a/pkg/sdk/external_volumes_gen.go +++ b/pkg/sdk/external_volumes_gen.go @@ -1,6 +1,9 @@ package sdk -import "context" +import ( + "context" + "database/sql" +) type ExternalVolumes interface { Create(ctx context.Context, request *CreateExternalVolumeRequest) error @@ -107,12 +110,12 @@ type ShowExternalVolumeOptions struct { Like *Like `ddl:"keyword" sql:"LIKE"` } type externalVolumeShowRow struct { - Name string `db:"name"` - AllowWrites string `db:"allow_writes"` - Comment string `db:"comment"` + Name string `db:"name"` + AllowWrites bool `db:"allow_writes"` + Comment sql.NullString `db:"comment"` } type ExternalVolume struct { Name string - AllowWrites string + AllowWrites bool Comment string } diff --git a/pkg/sdk/external_volumes_gen_test.go b/pkg/sdk/external_volumes_gen_test.go index 4278e47db6..fd2e5fc1a5 100644 --- a/pkg/sdk/external_volumes_gen_test.go +++ b/pkg/sdk/external_volumes_gen_test.go @@ -1,6 +1,10 @@ package sdk -import "testing" +import ( + "testing" + + "github.com/stretchr/testify/require" +) // Storage location structs for testing var s3StorageLocationParams = &S3StorageLocationParams{ @@ -439,3 +443,143 @@ func TestExternalVolumes_Show(t *testing.T) { assertOptsValidAndSQLEquals(t, opts, "SHOW EXTERNAL VOLUMES LIKE '%s'", id.Name()) }) } + +func Test_ExternalVolumes_ToS3EncryptionType(t *testing.T) { + type test struct { + input string + want S3EncryptionType + } + + valid := []test{ + {input: "aws_sse_s3", want: S3EncryptionTypeSseS3}, + {input: "AWS_SSE_S3", want: S3EncryptionTypeSseS3}, + {input: "AWS_SSE_KMS", want: S3EncryptionTypeSseKms}, + {input: "NONE", want: S3EncryptionNone}, + } + + invalid := []test{ + {input: ""}, + {input: "foo"}, + } + + for _, tc := range valid { + t.Run(tc.input, func(t *testing.T) { + got, err := ToS3EncryptionType(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + for _, tc := range invalid { + t.Run(tc.input, func(t *testing.T) { + _, err := ToS3EncryptionType(tc.input) + require.Error(t, err) + }) + } +} + +func Test_ExternalVolumes_ToStorageProvider(t *testing.T) { + type test struct { + input string + want StorageProvider + } + + valid := []test{ + {input: "s3", want: StorageProviderS3}, + {input: "S3", want: StorageProviderS3}, + {input: "s3gov", want: StorageProviderS3GOV}, + {input: "S3GOV", want: StorageProviderS3GOV}, + {input: "gcs", want: StorageProviderGCS}, + {input: "GCS", want: StorageProviderGCS}, + {input: "azure", want: StorageProviderAzure}, + {input: "AZURE", want: StorageProviderAzure}, + } + + invalid := []test{ + {input: ""}, + {input: "foo"}, + } + + for _, tc := range valid { + t.Run(tc.input, func(t *testing.T) { + got, err := ToStorageProvider(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + for _, tc := range invalid { + t.Run(tc.input, func(t *testing.T) { + _, err := ToStorageProvider(tc.input) + require.Error(t, err) + }) + } +} + +func Test_ExternalVolumes_ToS3StorageProvider(t *testing.T) { + type test struct { + input string + want S3StorageProvider + } + + valid := []test{ + {input: "s3", want: S3StorageProviderS3}, + {input: "S3", want: S3StorageProviderS3}, + {input: "s3gov", want: S3StorageProviderS3GOV}, + {input: "S3GOV", want: S3StorageProviderS3GOV}, + } + + invalid := []test{ + {input: ""}, + {input: "foo"}, + } + + for _, tc := range valid { + t.Run(tc.input, func(t *testing.T) { + got, err := ToS3StorageProvider(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + for _, tc := range invalid { + t.Run(tc.input, func(t *testing.T) { + _, err := ToS3StorageProvider(tc.input) + require.Error(t, err) + }) + } +} + +func Test_ExternalVolumes_ToGCSEncryptionType(t *testing.T) { + type test struct { + input string + want GCSEncryptionType + } + + valid := []test{ + {input: "gcs_sse_kms", want: GCSEncryptionTypeSseKms}, + {input: "GCS_SSE_KMS", want: GCSEncryptionTypeSseKms}, + {input: "NONE", want: GCSEncryptionTypeNone}, + {input: "none", want: GCSEncryptionTypeNone}, + } + + invalid := []test{ + {input: ""}, + {input: "foo"}, + } + + for _, tc := range valid { + t.Run(tc.input, func(t *testing.T) { + got, err := ToGCSEncryptionType(tc.input) + require.NoError(t, err) + require.Equal(t, tc.want, got) + }) + } + + for _, tc := range invalid { + t.Run(tc.input, func(t *testing.T) { + _, err := ToGCSEncryptionType(tc.input) + require.Error(t, err) + }) + } +} diff --git a/pkg/sdk/external_volumes_impl_gen.go b/pkg/sdk/external_volumes_impl_gen.go index 5b7de50826..7e6a8567fa 100644 --- a/pkg/sdk/external_volumes_impl_gen.go +++ b/pkg/sdk/external_volumes_impl_gen.go @@ -160,9 +160,14 @@ func (r *ShowExternalVolumeRequest) toOpts() *ShowExternalVolumeOptions { } func (r externalVolumeShowRow) convert() *ExternalVolume { - return &ExternalVolume{ + externalVolume := ExternalVolume{ Name: r.Name, AllowWrites: r.AllowWrites, - Comment: r.Comment, } + + if r.Comment.Valid { + externalVolume.Comment = r.Comment.String + } + + return &externalVolume } diff --git a/pkg/sdk/external_volumes_validations_gen.go b/pkg/sdk/external_volumes_validations_gen.go index 3d4d5eb03d..6e8bb874de 100644 --- a/pkg/sdk/external_volumes_validations_gen.go +++ b/pkg/sdk/external_volumes_validations_gen.go @@ -10,6 +10,13 @@ var ( _ validatable = new(ShowExternalVolumeOptions) ) +var ValidStorageProviderString = []string{ + string(StorageProviderGCS), + string(StorageProviderAzure), + string(StorageProviderS3), + string(StorageProviderS3GOV), +} + func (opts *CreateExternalVolumeOptions) validate() error { if opts == nil { return ErrNilOptions diff --git a/pkg/sdk/testint/external_volumes_gen_integration_test.go b/pkg/sdk/testint/external_volumes_gen_integration_test.go index 2c1c14056b..38fa11985f 100644 --- a/pkg/sdk/testint/external_volumes_gen_integration_test.go +++ b/pkg/sdk/testint/external_volumes_gen_integration_test.go @@ -1,13 +1,11 @@ package testint import ( - "encoding/json" - "fmt" "strconv" - "strings" "testing" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -31,144 +29,8 @@ func TestInt_ExternalVolumes(t *testing.T) { assertExternalVolumeShowResult := func(t *testing.T, s *sdk.ExternalVolume, name sdk.AccountObjectIdentifier, allowWrites bool, comment string) { t.Helper() assert.Equal(t, name.Name(), s.Name) - assert.Equal(t, strconv.FormatBool(allowWrites), s.AllowWrites) - assert.Equal(t, comment, s.Comment) - } - - // Structs for trimProperties function - type ExternalVolumePropNameValue struct { - Name string - Value string - } - - type S3StorageLocation struct { - Name string `json:"NAME"` - StorageProvider string `json:"STORAGE_PROVIDER"` - StorageBaseUrl string `json:"STORAGE_BASE_URL"` - StorageAllowedLocations []string `json:"STORAGE_ALLOWED_LOCATIONS"` - StorageAwsRoleArn string `json:"STORAGE_AWS_ROLE_ARN"` - StroageAwsIamUserArn string `json:"STORAGE_AWS_IAM_USER_ARN"` - StorageAwsExternalId string `json:"STORAGE_AWS_EXTERNAL_ID"` - EncryptionType string `json:"ENCRYPTION_TYPE"` - EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID"` - } - - type S3StorageLocationTrimmed struct { - Name string `json:"NAME"` - StorageProvider string `json:"STORAGE_PROVIDER"` - StorageBaseUrl string `json:"STORAGE_BASE_URL"` - StorageAwsRoleArn string `json:"STORAGE_AWS_ROLE_ARN"` - StorageAwsExternalId string `json:"STORAGE_AWS_EXTERNAL_ID"` - EncryptionType string `json:"ENCRYPTION_TYPE,omitempty"` - EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID,omitempty"` - } - - type GCSStorageLocation struct { - Name string `json:"NAME"` - StorageProvider string `json:"STORAGE_PROVIDER"` - StorageBaseUrl string `json:"STORAGE_BASE_URL"` - StorageAllowedLocations []string `json:"STORAGE_ALLOWED_LOCATIONS"` - StorageGcpServiceAccount string `json:"STORAGE_GCP_SERVICE_ACCOUNT"` - EncryptionType string `json:"ENCRYPTION_TYPE"` - EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID"` - } - - type GCSStorageLocationTrimmed struct { - Name string `json:"NAME"` - StorageProvider string `json:"STORAGE_PROVIDER"` - StorageBaseUrl string `json:"STORAGE_BASE_URL"` - EncryptionType string `json:"ENCRYPTION_TYPE,omitempty"` - EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID,omitempty"` - } - - type AzureStorageLocation struct { - Name string `json:"NAME"` - StorageProvider string `json:"STORAGE_PROVIDER"` - StorageBaseUrl string `json:"STORAGE_BASE_URL"` - StorageAllowedLocations []string `json:"STORAGE_ALLOWED_LOCATIONS"` - AzureTenantId string `json:"AZURE_TENANT_ID"` - AzureMultiTenantAppName string `json:"AZURE_MULTI_TENANT_APP_NAME"` - AzureConsentUrl string `json:"AZURE_CONSENT_URL"` - EncryptionType string `json:"ENCRYPTION_TYPE"` - EncryptionKmsId string `json:"ENCRYPTION_KMS_KEY_ID"` - } - - type AzureStorageLocationTrimmed struct { - Name string `json:"NAME"` - StorageProvider string `json:"STORAGE_PROVIDER"` - StorageBaseUrl string `json:"STORAGE_BASE_URL"` - AzureTenantId string `json:"AZURE_TENANT_ID"` - } - - // Enforce only property names and values in tests, not parent_property, type and property_default - // In addition the storage location properties are trimmed to only contain values that we set - trimProperties := func(t *testing.T, props []sdk.ExternalVolumeProperty) []ExternalVolumePropNameValue { - t.Helper() - var externalVolumePropNameValue []ExternalVolumePropNameValue - for _, p := range props { - if strings.Contains(p.Name, "STORAGE_LOCATION_") { - switch { - case strings.Contains(p.Value, `"STORAGE_PROVIDER":"S3"`): - s3StorageLocation := S3StorageLocation{} - err := json.Unmarshal([]byte(p.Value), &s3StorageLocation) - require.NoError(t, err) - s3StorageLocationTrimmed := S3StorageLocationTrimmed{ - Name: s3StorageLocation.Name, - StorageProvider: s3StorageLocation.StorageProvider, - StorageBaseUrl: s3StorageLocation.StorageBaseUrl, - StorageAwsRoleArn: s3StorageLocation.StorageAwsRoleArn, - StorageAwsExternalId: s3StorageLocation.StorageAwsExternalId, - EncryptionType: s3StorageLocation.EncryptionType, - EncryptionKmsId: s3StorageLocation.EncryptionKmsId, - } - s3StorageLocationTrimmedMarshaled, err := json.Marshal(s3StorageLocationTrimmed) - require.NoError(t, err) - externalVolumePropNameValue = append( - externalVolumePropNameValue, - ExternalVolumePropNameValue{Name: p.Name, Value: string(s3StorageLocationTrimmedMarshaled)}, - ) - case strings.Contains(p.Value, `"STORAGE_PROVIDER":"GCS"`): - gcsStorageLocation := GCSStorageLocation{} - err := json.Unmarshal([]byte(p.Value), &gcsStorageLocation) - require.NoError(t, err) - gcsStorageLocationTrimmed := GCSStorageLocationTrimmed{ - Name: gcsStorageLocation.Name, - StorageProvider: gcsStorageLocation.StorageProvider, - StorageBaseUrl: gcsStorageLocation.StorageBaseUrl, - EncryptionType: gcsStorageLocation.EncryptionType, - EncryptionKmsId: gcsStorageLocation.EncryptionKmsId, - } - gcsStorageLocationTrimmedMarshaled, err := json.Marshal(gcsStorageLocationTrimmed) - require.NoError(t, err) - externalVolumePropNameValue = append( - externalVolumePropNameValue, - ExternalVolumePropNameValue{Name: p.Name, Value: string(gcsStorageLocationTrimmedMarshaled)}, - ) - case strings.Contains(p.Value, `"STORAGE_PROVIDER":"AZURE"`): - azureStorageLocation := AzureStorageLocation{} - err := json.Unmarshal([]byte(p.Value), &azureStorageLocation) - require.NoError(t, err) - azureStorageLocationTrimmed := AzureStorageLocationTrimmed{ - Name: azureStorageLocation.Name, - StorageProvider: azureStorageLocation.StorageProvider, - StorageBaseUrl: azureStorageLocation.StorageBaseUrl, - AzureTenantId: azureStorageLocation.AzureTenantId, - } - azureStorageLocationTrimmedMarshaled, err := json.Marshal(azureStorageLocationTrimmed) - require.NoError(t, err) - externalVolumePropNameValue = append( - externalVolumePropNameValue, - ExternalVolumePropNameValue{Name: p.Name, Value: string(azureStorageLocationTrimmedMarshaled)}, - ) - default: - panic("Unrecognized storage provider in storage location property") - } - } else { - externalVolumePropNameValue = append(externalVolumePropNameValue, ExternalVolumePropNameValue{Name: p.Name, Value: p.Value}) - } - } - - return externalVolumePropNameValue + assert.Equal(t, allowWrites, s.AllowWrites) + assert.Equal(t, s.Comment, comment) } // Storage location structs for testing @@ -261,14 +123,17 @@ func TestInt_ExternalVolumes(t *testing.T) { }, } - createExternalVolume := func(t *testing.T, storageLocations []sdk.ExternalVolumeStorageLocation, allowWrites bool, comment string) sdk.AccountObjectIdentifier { + createExternalVolume := func(t *testing.T, storageLocations []sdk.ExternalVolumeStorageLocation, allowWrites bool, comment *string) sdk.AccountObjectIdentifier { t.Helper() id := testClientHelper().Ids.RandomAccountObjectIdentifier() req := sdk.NewCreateExternalVolumeRequest(id, storageLocations). WithIfNotExists(true). - WithAllowWrites(allowWrites). - WithComment(comment) + WithAllowWrites(allowWrites) + + if comment != nil { + req = req.WithComment(*comment) + } err := client.ExternalVolumes.Create(ctx, req) require.NoError(t, err) @@ -284,7 +149,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - S3 Storage Location", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, s3StorageLocations, allowWrites, comment) + id := createExternalVolume(t, s3StorageLocations, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -292,10 +157,31 @@ func TestInt_ExternalVolumes(t *testing.T) { assertExternalVolumeShowResult(t, externalVolume, id, allowWrites, comment) }) + t.Run("Create - S3 Storage Location empty Comment", func(t *testing.T) { + allowWrites := true + emptyComment := "" + id := createExternalVolume(t, s3StorageLocations, allowWrites, &emptyComment) + + externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) + require.NoError(t, err) + + assertExternalVolumeShowResult(t, externalVolume, id, allowWrites, emptyComment) + }) + + t.Run("Create - S3 Storage Location No Comment", func(t *testing.T) { + allowWrites := true + id := createExternalVolume(t, s3StorageLocations, allowWrites, nil) + + externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) + require.NoError(t, err) + + assertExternalVolumeShowResult(t, externalVolume, id, allowWrites, "") + }) + t.Run("Create - S3 Storage Location None Encryption", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, s3StorageLocationsNoneEncryption, allowWrites, comment) + id := createExternalVolume(t, s3StorageLocationsNoneEncryption, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -306,7 +192,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - S3 Storage Location No Encryption", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, s3StorageLocationsNoEncryption, allowWrites, comment) + id := createExternalVolume(t, s3StorageLocationsNoEncryption, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -317,7 +203,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - GCS Storage Location", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, gcsStorageLocations, allowWrites, comment) + id := createExternalVolume(t, gcsStorageLocations, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -328,7 +214,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - GCS Storage Location None Encryption", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, gcsStorageLocationsNoneEncryption, allowWrites, comment) + id := createExternalVolume(t, gcsStorageLocationsNoneEncryption, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -339,7 +225,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - GCS Storage Location No Encryption", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, gcsStorageLocationsNoEncryption, allowWrites, comment) + id := createExternalVolume(t, gcsStorageLocationsNoEncryption, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -350,7 +236,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - Azure Storage Location", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, azureStorageLocations, allowWrites, comment) + id := createExternalVolume(t, azureStorageLocations, allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -361,7 +247,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Create - Multiple Storage Locations", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, append(append(s3StorageLocations, gcsStorageLocationsNoneEncryption...), azureStorageLocations...), allowWrites, comment) + id := createExternalVolume(t, append(append(s3StorageLocations, gcsStorageLocationsNoneEncryption...), azureStorageLocations...), allowWrites, &comment) externalVolume, err := client.ExternalVolumes.ShowByID(ctx, id) require.NoError(t, err) @@ -372,7 +258,7 @@ func TestInt_ExternalVolumes(t *testing.T) { t.Run("Alter - remove storage location", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, append(s3StorageLocationsNoneEncryption, gcsStorageLocationsNoneEncryption...), allowWrites, comment) + id := createExternalVolume(t, append(s3StorageLocationsNoneEncryption, gcsStorageLocationsNoneEncryption...), allowWrites, &comment) req := sdk.NewAlterExternalVolumeRequest(id).WithRemoveStorageLocation(gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Name) @@ -382,36 +268,37 @@ func TestInt_ExternalVolumes(t *testing.T) { props, err := client.ExternalVolumes.Describe(ctx, id) require.NoError(t, err) - trimmedProperties := trimProperties(t, props) - assert.Equal(t, 4, len(trimmedProperties)) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "COMMENT", Value: comment}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ALLOW_WRITES", Value: strconv.FormatBool(allowWrites)}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ACTIVE", Value: ""}) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_1", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s"}`, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Name, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageProvider, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsExternalId, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Encryption.Type, - ), + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(props) + require.NoError(t, err) + expectedParsedExternalVolumeDescribed := helpers.ParsedExternalVolumeDescribed{ + StorageLocations: []helpers.StorageLocation{ + { + Name: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: string(s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, }, - ) + Active: "", + Comment: comment, + AllowWrites: strconv.FormatBool(allowWrites), + } + + assert.True(t, helpers.ParsedExternalVolumesDescribedEqual(parsedExternalVolumeDescribed, expectedParsedExternalVolumeDescribed)) }) t.Run("Alter - set comment", func(t *testing.T) { allowWrites := true - comment := "" - id := createExternalVolume(t, s3StorageLocationsNoneEncryption, allowWrites, "some comment") + comment1 := "some comment" + comment2 := "" + id := createExternalVolume(t, s3StorageLocationsNoneEncryption, allowWrites, &comment1) req := sdk.NewAlterExternalVolumeRequest(id).WithSet( - *sdk.NewAlterExternalVolumeSetRequest().WithComment(comment), + *sdk.NewAlterExternalVolumeSetRequest().WithComment(comment2), ) err := client.ExternalVolumes.Alter(ctx, req) @@ -420,32 +307,33 @@ func TestInt_ExternalVolumes(t *testing.T) { props, err := client.ExternalVolumes.Describe(ctx, id) require.NoError(t, err) - trimmedProperties := trimProperties(t, props) - assert.Equal(t, 3, len(trimmedProperties)) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ALLOW_WRITES", Value: strconv.FormatBool(allowWrites)}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ACTIVE", Value: ""}) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_1", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s"}`, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Name, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageProvider, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsExternalId, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Encryption.Type, - ), + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(props) + require.NoError(t, err) + expectedParsedExternalVolumeDescribed := helpers.ParsedExternalVolumeDescribed{ + StorageLocations: []helpers.StorageLocation{ + { + Name: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: string(s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, }, - ) + Active: "", + Comment: comment2, + AllowWrites: strconv.FormatBool(allowWrites), + } + + assert.True(t, helpers.ParsedExternalVolumesDescribedEqual(parsedExternalVolumeDescribed, expectedParsedExternalVolumeDescribed)) }) t.Run("Alter - set allow writes", func(t *testing.T) { allowWrites := false comment := "some comment" - id := createExternalVolume(t, s3StorageLocations, true, comment) + id := createExternalVolume(t, s3StorageLocations, true, &comment) req := sdk.NewAlterExternalVolumeRequest(id).WithSet( *sdk.NewAlterExternalVolumeSetRequest().WithAllowWrites(allowWrites), @@ -457,34 +345,33 @@ func TestInt_ExternalVolumes(t *testing.T) { props, err := client.ExternalVolumes.Describe(ctx, id) require.NoError(t, err) - trimmedProperties := trimProperties(t, props) - assert.Equal(t, 4, len(trimmedProperties)) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "COMMENT", Value: comment}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ALLOW_WRITES", Value: strconv.FormatBool(allowWrites)}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ACTIVE", Value: ""}) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_1", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"%s"}`, - s3StorageLocations[0].S3StorageLocationParams.Name, - s3StorageLocations[0].S3StorageLocationParams.StorageProvider, - s3StorageLocations[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocations[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocations[0].S3StorageLocationParams.StorageAwsExternalId, - s3StorageLocations[0].S3StorageLocationParams.Encryption.Type, - *s3StorageLocations[0].S3StorageLocationParams.Encryption.KmsKeyId, - ), + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(props) + require.NoError(t, err) + expectedParsedExternalVolumeDescribed := helpers.ParsedExternalVolumeDescribed{ + StorageLocations: []helpers.StorageLocation{ + { + Name: s3StorageLocations[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocations[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocations[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocations[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocations[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: string(s3StorageLocations[0].S3StorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: *s3StorageLocations[0].S3StorageLocationParams.Encryption.KmsKeyId, + AzureTenantId: "", + }, }, - ) + Active: "", + Comment: comment, + AllowWrites: strconv.FormatBool(allowWrites), + } + + assert.True(t, helpers.ParsedExternalVolumesDescribedEqual(parsedExternalVolumeDescribed, expectedParsedExternalVolumeDescribed)) }) t.Run("Alter - add s3 storage location to external volume", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, gcsStorageLocationsNoneEncryption, allowWrites, comment) + id := createExternalVolume(t, gcsStorageLocationsNoneEncryption, allowWrites, &comment) req := sdk.NewAlterExternalVolumeRequest(id).WithAddStorageLocation( *sdk.NewExternalVolumeStorageLocationRequest().WithS3StorageLocationParams( @@ -507,41 +394,37 @@ func TestInt_ExternalVolumes(t *testing.T) { props, err := client.ExternalVolumes.Describe(ctx, id) require.NoError(t, err) - trimmedProperties := trimProperties(t, props) - assert.Equal(t, 5, len(trimmedProperties)) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "COMMENT", Value: comment}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ALLOW_WRITES", Value: strconv.FormatBool(allowWrites)}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ACTIVE", Value: ""}) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_1", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"GCS","STORAGE_BASE_URL":"%s","ENCRYPTION_TYPE":"%s"}`, - gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Name, - gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.StorageBaseUrl, - gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Encryption.Type, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_2", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"%s"}`, - s3StorageLocations[0].S3StorageLocationParams.Name, - s3StorageLocations[0].S3StorageLocationParams.StorageProvider, - s3StorageLocations[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocations[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocations[0].S3StorageLocationParams.StorageAwsExternalId, - s3StorageLocations[0].S3StorageLocationParams.Encryption.Type, - *s3StorageLocations[0].S3StorageLocationParams.Encryption.KmsKeyId, - ), + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(props) + require.NoError(t, err) + expectedParsedExternalVolumeDescribed := helpers.ParsedExternalVolumeDescribed{ + StorageLocations: []helpers.StorageLocation{ + { + Name: gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Name, + StorageProvider: string(sdk.StorageProviderGCS), + StorageBaseUrl: gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: string(gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + { + Name: s3StorageLocations[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocations[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocations[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocations[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocations[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: string(s3StorageLocations[0].S3StorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: *s3StorageLocations[0].S3StorageLocationParams.Encryption.KmsKeyId, + AzureTenantId: "", + }, }, - ) + Active: "", + Comment: comment, + AllowWrites: strconv.FormatBool(allowWrites), + } + + assert.True(t, helpers.ParsedExternalVolumesDescribedEqual(parsedExternalVolumeDescribed, expectedParsedExternalVolumeDescribed)) }) t.Run("Describe", func(t *testing.T) { @@ -551,123 +434,99 @@ func TestInt_ExternalVolumes(t *testing.T) { t, append(append(append(append(append(append(s3StorageLocations, gcsStorageLocationsNoneEncryption...), azureStorageLocations...), s3StorageLocationsNoneEncryption...), gcsStorageLocations...), s3StorageLocationsNoEncryption...), gcsStorageLocationsNoEncryption...), allowWrites, - comment, + &comment, ) props, err := client.ExternalVolumes.Describe(ctx, id) require.NoError(t, err) - trimmedProperties := trimProperties(t, props) - assert.Equal(t, 10, len(trimmedProperties)) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "COMMENT", Value: comment}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ALLOW_WRITES", Value: strconv.FormatBool(allowWrites)}) - assert.Contains(t, trimmedProperties, ExternalVolumePropNameValue{Name: "ACTIVE", Value: ""}) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_1", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"%s"}`, - s3StorageLocations[0].S3StorageLocationParams.Name, - s3StorageLocations[0].S3StorageLocationParams.StorageProvider, - s3StorageLocations[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocations[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocations[0].S3StorageLocationParams.StorageAwsExternalId, - s3StorageLocations[0].S3StorageLocationParams.Encryption.Type, - *s3StorageLocations[0].S3StorageLocationParams.Encryption.KmsKeyId, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_2", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"GCS","STORAGE_BASE_URL":"%s","ENCRYPTION_TYPE":"%s"}`, - gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Name, - gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.StorageBaseUrl, - gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Encryption.Type, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_3", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"AZURE","STORAGE_BASE_URL":"%s","AZURE_TENANT_ID":"%s"}`, - azureStorageLocations[0].AzureStorageLocationParams.Name, - azureStorageLocations[0].AzureStorageLocationParams.StorageBaseUrl, - azureStorageLocations[0].AzureStorageLocationParams.AzureTenantId, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_4", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"%s"}`, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Name, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageProvider, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsExternalId, - s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Encryption.Type, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_5", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"GCS","STORAGE_BASE_URL":"%s","ENCRYPTION_TYPE":"%s","ENCRYPTION_KMS_KEY_ID":"%s"}`, - gcsStorageLocations[0].GCSStorageLocationParams.Name, - gcsStorageLocations[0].GCSStorageLocationParams.StorageBaseUrl, - gcsStorageLocations[0].GCSStorageLocationParams.Encryption.Type, - *gcsStorageLocations[0].GCSStorageLocationParams.Encryption.KmsKeyId, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_6", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"%s","STORAGE_BASE_URL":"%s","STORAGE_AWS_ROLE_ARN":"%s","STORAGE_AWS_EXTERNAL_ID":"%s","ENCRYPTION_TYPE":"NONE"}`, - s3StorageLocationsNoEncryption[0].S3StorageLocationParams.Name, - s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageProvider, - s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageBaseUrl, - s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, - *s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageAwsExternalId, - ), - }, - ) - assert.Contains( - t, - trimmedProperties, - ExternalVolumePropNameValue{ - Name: "STORAGE_LOCATION_7", - Value: fmt.Sprintf( - `{"NAME":"%s","STORAGE_PROVIDER":"GCS","STORAGE_BASE_URL":"%s","ENCRYPTION_TYPE":"NONE"}`, - gcsStorageLocationsNoEncryption[0].GCSStorageLocationParams.Name, - gcsStorageLocationsNoEncryption[0].GCSStorageLocationParams.StorageBaseUrl, - ), + parsedExternalVolumeDescribed, err := helpers.ParseExternalVolumeDescribed(props) + require.NoError(t, err) + expectedParsedExternalVolumeDescribed := helpers.ParsedExternalVolumeDescribed{ + StorageLocations: []helpers.StorageLocation{ + { + Name: s3StorageLocations[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocations[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocations[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocations[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocations[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: string(s3StorageLocations[0].S3StorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: *s3StorageLocations[0].S3StorageLocationParams.Encryption.KmsKeyId, + AzureTenantId: "", + }, + { + Name: gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Name, + StorageProvider: string(sdk.StorageProviderGCS), + StorageBaseUrl: gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: string(gcsStorageLocationsNoneEncryption[0].GCSStorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + { + Name: azureStorageLocations[0].AzureStorageLocationParams.Name, + StorageProvider: string(sdk.StorageProviderAzure), + StorageBaseUrl: azureStorageLocations[0].AzureStorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: "", + EncryptionKmsKeyId: "", + AzureTenantId: azureStorageLocations[0].AzureStorageLocationParams.AzureTenantId, + }, + { + Name: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: string(s3StorageLocationsNoneEncryption[0].S3StorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + { + Name: gcsStorageLocations[0].GCSStorageLocationParams.Name, + StorageProvider: string(sdk.StorageProviderGCS), + StorageBaseUrl: gcsStorageLocations[0].GCSStorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: string(gcsStorageLocations[0].GCSStorageLocationParams.Encryption.Type), + EncryptionKmsKeyId: *gcsStorageLocations[0].GCSStorageLocationParams.Encryption.KmsKeyId, + AzureTenantId: "", + }, + { + Name: s3StorageLocationsNoEncryption[0].S3StorageLocationParams.Name, + StorageProvider: string(s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageProvider), + StorageBaseUrl: s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageAwsRoleArn, + StorageAwsExternalId: *s3StorageLocationsNoEncryption[0].S3StorageLocationParams.StorageAwsExternalId, + EncryptionType: "NONE", + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, + { + Name: gcsStorageLocationsNoEncryption[0].GCSStorageLocationParams.Name, + StorageProvider: string(sdk.StorageProviderGCS), + StorageBaseUrl: gcsStorageLocationsNoEncryption[0].GCSStorageLocationParams.StorageBaseUrl, + StorageAwsRoleArn: "", + StorageAwsExternalId: "", + EncryptionType: "NONE", + EncryptionKmsKeyId: "", + AzureTenantId: "", + }, }, - ) + Active: "", + Comment: comment, + AllowWrites: strconv.FormatBool(allowWrites), + } + + assert.True(t, helpers.ParsedExternalVolumesDescribedEqual(parsedExternalVolumeDescribed, expectedParsedExternalVolumeDescribed)) }) t.Run("Show with like", func(t *testing.T) { allowWrites := true comment := "some comment" - id := createExternalVolume(t, s3StorageLocations, allowWrites, comment) + id := createExternalVolume(t, s3StorageLocations, allowWrites, &comment) name := id.Name() req := sdk.NewShowExternalVolumeRequest().WithLike(sdk.Like{Pattern: &name})