From c6e12c95c40dbefd7041544b64f02ea6f2d2a97e Mon Sep 17 00:00:00 2001 From: Johan Andersson Date: Mon, 27 May 2024 11:48:17 +0200 Subject: [PATCH] Add support for Azure archival locations (#168) --- docs/changelog.md | 4 +- docs/resources/azure_archival_location.md | 59 +++ go.mod | 2 +- go.sum | 4 +- internal/provider/provider.go | 1 + .../resource_aws_archival_location.go | 9 +- .../resource_azure_archival_location.go | 373 ++++++++++++++++++ internal/provider/resource_names.go | 19 +- templates/changelog.md.tmpl | 4 +- 9 files changed, 457 insertions(+), 18 deletions(-) create mode 100644 docs/resources/azure_archival_location.md create mode 100644 internal/provider/resource_azure_archival_location.go diff --git a/docs/changelog.md b/docs/changelog.md index 57d2b3d..94bba49 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -5,9 +5,7 @@ page_title: "Changelog" # Changelog ## v0.9.0-beta.4 -* Fix an issue with the permissions of subscriptions onboarded using the `polaris_azure_subscription` resource where - the RSC UI would show the status as "Update permissions" even though the app registration would have all the required - permissions. +* Add support for creating Azure cloud native archival locations. [[docs](resources/azure_archival_location)] ## v0.9.0-beta.3 * Fix a bug in the `polaris_aws_exocompute` resource where customer supplied security groups were not validated diff --git a/docs/resources/azure_archival_location.md b/docs/resources/azure_archival_location.md new file mode 100644 index 0000000..d095d0a --- /dev/null +++ b/docs/resources/azure_archival_location.md @@ -0,0 +1,59 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "polaris_azure_archival_location Resource - terraform-provider-polaris" +subcategory: "" +description: |- + The polaris_azure_archival_location resource creates an RSC archival location for cloud-native workloads. + When creating an archival location, the region where the snapshots are stored needs to be specified: + * Source Region - Store snapshots in the same region to minimize data transfer charges. This is the default behaviour when the storage_account_region field is not specified. + * Specific region - Storing snapshots in another region can increase total data transfer charges. The storage_account_region field specifies the region. + Custom storage encryption is enabled by specifying one or more customer_managed_key blocks. Each customer_managed_key block specifies the encryption details to use for a region. For other regions, data will be encrypted using platform managed keys. + -> Note: The Azure storage account is not created until the first protected object is archived to the location. +--- + +# polaris_azure_archival_location (Resource) + +The `polaris_azure_archival_location` resource creates an RSC archival location for cloud-native workloads. + +When creating an archival location, the region where the snapshots are stored needs to be specified: + * *Source Region* - Store snapshots in the same region to minimize data transfer charges. This is the default behaviour when the `storage_account_region` field is not specified. + * *Specific region* - Storing snapshots in another region can increase total data transfer charges. The `storage_account_region` field specifies the region. + +Custom storage encryption is enabled by specifying one or more `customer_managed_key` blocks. Each `customer_managed_key` block specifies the encryption details to use for a region. For other regions, data will be encrypted using platform managed keys. + +-> **Note:** The Azure storage account is not created until the first protected object is archived to the location. + + + + +## Schema + +### Required + +- `cloud_account_id` (String) RSC cloud account ID. +- `name` (String) Cloud native archival location name. +- `storage_account_name_prefix` (String) Azure storage account name prefix. The storage account name prefix cannot be longer than 14 characters and can only consist of numbers and lower case letters. + +### Optional + +- `customer_managed_key` (Block Set) Customer managed storage encryption. Specify the regions and their respective encryption details. For other regions, data will be encrypted using platform managed keys. (see [below for nested schema](#nestedblock--customer_managed_key)) +- `redundancy` (String) Azure storage redundancy. Possible values are `GRS`, `GZRS`, `LRS`, `RA_GRS`, `RA_GZRS` and `ZRS`. Default value is `LRS`. +- `storage_account_region` (String) Azure region to store the snapshots in. If not specified, the snapshots will be stored in the same region as the workload. +- `storage_account_tags` (Map of String) Azure storage account tags. Each tag will be added to the storage account created by RSC. +- `storage_tier` (String) Azure storage tier. Possible values are `COOL` and `HOT`. Default value is `COOL`. + +### Read-Only + +- `connection_status` (String) Connection status of the cloud native archival location. +- `container_name` (String) Azure storage container name. +- `id` (String) Cloud native archival location ID. +- `location_template` (String) RSC location template. If a storage account region was specified, it will be `SPECIFIC_REGION`, otherwise `SOURCE_REGION`. + + +### Nested Schema for `customer_managed_key` + +Required: + +- `name` (String) Key name. +- `region` (String) The region in which the key will be used. Regions without customer managed keys will use platform managed keys. +- `vault_name` (String) Key vault name. diff --git a/go.mod b/go.mod index 3c0674c..c44cc84 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/terraform-plugin-docs v0.16.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.0 - github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.10.0-beta.5 + github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.10.0-beta.6 ) require ( diff --git a/go.sum b/go.sum index 014f68c..14da9b6 100644 --- a/go.sum +++ b/go.sum @@ -412,8 +412,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.10.0-beta.5 h1:J/+s4lkvAn9FHb8gYY14Ea6wsCSNMS/Dhz+hs+R4YOw= -github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.10.0-beta.5/go.mod h1:670TFQkxTdbsBwEwR/fDT75hfHwPDTTOiLnyZerbqQk= +github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.10.0-beta.6 h1:zGFHwJHotDDXgdN7WzQWTh8BDjCzGWTsrMJ1/3Ro+wg= +github.com/rubrikinc/rubrik-polaris-sdk-for-go v0.10.0-beta.6/go.mod h1:670TFQkxTdbsBwEwR/fDT75hfHwPDTTOiLnyZerbqQk= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= diff --git a/internal/provider/provider.go b/internal/provider/provider.go index ef17285..93f9361 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -61,6 +61,7 @@ func Provider() *schema.Provider { "polaris_aws_exocompute": resourceAwsExocompute(), "polaris_aws_exocompute_cluster_attachment": resourceAwsExocomputeClusterAttachment(), "polaris_aws_private_container_registry": resourceAwsPrivateContainerRegistry(), + keyPolarisAzureArchivalLocation: resourceAzureArchivalLocation(), keyPolarisAzureExocompute: resourceAzureExocompute(), keyPolarisAzureServicePrincipal: resourceAzureServicePrincipal(), keyPolarisAzureSubscription: resourceAzureSubscription(), diff --git a/internal/provider/resource_aws_archival_location.go b/internal/provider/resource_aws_archival_location.go index 48fa859..5ecdc53 100644 --- a/internal/provider/resource_aws_archival_location.go +++ b/internal/provider/resource_aws_archival_location.go @@ -214,7 +214,6 @@ func awsUpdateArchivalLocation(ctx context.Context, d *schema.ResourceData, m in // Lookup and parse the target mapping ID from the resource ID. targetMappingID, err := uuid.Parse(d.Id()) if err != nil { - d.SetId("") return diag.FromErr(err) } @@ -255,8 +254,8 @@ func awsDeleteArchivalLocation(ctx context.Context, d *schema.ResourceData, m in return nil } -// fromBucketTags converts from the bucket tags argument to a standard string to -// string map. +// fromBucketTags converts from the bucket tags argument to a standard +// string-to-string map. func fromBucketTags(bucketTags map[string]any) (map[string]string, error) { tags := make(map[string]string, len(bucketTags)) for key, value := range bucketTags { @@ -270,8 +269,8 @@ func fromBucketTags(bucketTags map[string]any) (map[string]string, error) { return tags, nil } -// toBucketTags converts to the bucket tags argument from a standard string to -// string map. +// toBucketTags converts to the bucket tags argument from a standard +// string-to-string map. func toBucketTags(tags map[string]string) map[string]any { bucketTags := make(map[string]any, len(tags)) for key, value := range tags { diff --git a/internal/provider/resource_azure_archival_location.go b/internal/provider/resource_azure_archival_location.go new file mode 100644 index 0000000..2df652b --- /dev/null +++ b/internal/provider/resource_azure_archival_location.go @@ -0,0 +1,373 @@ +// Copyright 2024 Rubrik, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +package provider + +import ( + "context" + "errors" + "fmt" + "log" + "regexp" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/rubrikinc/rubrik-polaris-sdk-for-go/pkg/polaris/azure" + "github.com/rubrikinc/rubrik-polaris-sdk-for-go/pkg/polaris/graphql" +) + +func resourceAzureArchivalLocation() *schema.Resource { + return &schema.Resource{ + CreateContext: azureCreateArchivalLocation, + ReadContext: azureReadArchivalLocation, + UpdateContext: azureUpdateArchivalLocation, + DeleteContext: azureDeleteArchivalLocation, + + Description: "The `polaris_azure_archival_location` resource creates an RSC archival location for cloud-native " + + "workloads.\n" + + "\n" + + "When creating an archival location, the region where the snapshots are stored needs to be specified:\n" + + " * *Source Region* - Store snapshots in the same region to minimize data transfer charges. This is the " + + " default behaviour when the `storage_account_region` field is not specified.\n" + + " * *Specific region* - Storing snapshots in another region can increase total data transfer charges. " + + " The `storage_account_region` field specifies the region.\n" + + "\n" + + "Custom storage encryption is enabled by specifying one or more `customer_managed_key` blocks. Each " + + "`customer_managed_key` block specifies the encryption details to use for a region. For other regions, " + + "data will be encrypted using platform managed keys. \n" + + "\n" + + "-> **Note:** The Azure storage account is not created until the first protected object is archived to the" + + " location.\n" + + "\n", + Schema: map[string]*schema.Schema{ + keyID: { + Type: schema.TypeString, + Computed: true, + Description: "Cloud native archival location ID.", + }, + keyCloudAccountID: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "RSC cloud account ID.", + ValidateFunc: validation.StringIsNotWhiteSpace, + }, + keyConnectionStatus: { + Type: schema.TypeString, + Computed: true, + Description: "Connection status of the cloud native archival location.", + }, + keyContainerName: { + Type: schema.TypeString, + Computed: true, + Description: "Azure storage container name.", + }, + keyCustomerManagedKey: { + Type: schema.TypeSet, + Elem: customerKeyResource(), + Optional: true, + Description: "Customer managed storage encryption. Specify the regions and their respective encryption " + + "details. For other regions, data will be encrypted using platform managed keys.", + }, + keyLocationTemplate: { + Type: schema.TypeString, + Computed: true, + Description: "RSC location template. If a storage account region was specified, it will be " + + "`SPECIFIC_REGION`, otherwise `SOURCE_REGION`.", + }, + keyName: { + Type: schema.TypeString, + Required: true, + Description: "Cloud native archival location name.", + ValidateFunc: validation.StringIsNotWhiteSpace, + }, + keyRedundancy: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "LRS", + Description: "Azure storage redundancy. Possible values are `GRS`, `GZRS`, `LRS`, `RA_GRS`, `RA_GZRS` " + + "and `ZRS`. Default value is `LRS`.", + ValidateFunc: validation.StringInSlice([]string{"GRS", "GZRS", "LRS", "RA_GRS", "RA_GZRS", "ZRS"}, false), + }, + keyStorageAccountNamePrefix: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Azure storage account name prefix. The storage account name prefix cannot be longer than " + + "14 characters and can only consist of numbers and lower case letters.", + ValidateFunc: validation.All(validation.StringLenBetween(1, 14), + validation.StringMatch(regexp.MustCompile("^[a-z0-9]*$"), "storage account name may only contain numbers and lowercase letters")), + }, + keyStorageAccountRegion: { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Azure region to store the snapshots in. If not specified, the snapshots will be stored " + + "in the same region as the workload.", + ValidateFunc: validation.StringIsNotWhiteSpace, + }, + keyStorageAccountTags: { + Type: schema.TypeMap, + Optional: true, + Description: "Azure storage account tags. Each tag will be added to the storage account created by RSC.", + }, + keyStorageTier: { + Type: schema.TypeString, + Optional: true, + Default: "COOL", + Description: "Azure storage tier. Possible values are `COOL` and `HOT`. Default value is `COOL`.", + ValidateFunc: validation.StringInSlice([]string{"COOL", "HOT"}, false), + }, + }, + } +} + +func azureCreateArchivalLocation(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + log.Print("[TRACE] azureCreateArchivalLocation") + + client, err := m.(*client).polaris() + if err != nil { + return diag.FromErr(err) + } + + accountID, err := uuid.Parse(d.Get(keyCloudAccountID).(string)) + if err != nil { + return diag.FromErr(err) + } + + customerKeys := fromCustomerManagedKeys(d.Get(keyCustomerManagedKey).(*schema.Set)) + name := d.Get(keyName).(string) + redundancy := d.Get(keyRedundancy).(string) + storageAccountName := d.Get(keyStorageAccountNamePrefix).(string) + storageAccountRegion := d.Get(keyStorageAccountRegion).(string) + storageAccountTags, err := fromBucketTags(d.Get(keyStorageAccountTags).(map[string]any)) + if err != nil { + return diag.FromErr(err) + } + storageTier := d.Get(keyStorageTier).(string) + + // Create the archival location. + targetMappingID, err := azure.Wrap(client).CreateStorageSetting( + ctx, azure.CloudAccountID(accountID), name, redundancy, storageTier, storageAccountName, storageAccountRegion, storageAccountTags, customerKeys) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(targetMappingID.String()) + azureReadArchivalLocation(ctx, d, m) + return nil +} + +func azureReadArchivalLocation(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + log.Print("[TRACE] azureReadArchivalLocation") + + client, err := m.(*client).polaris() + if err != nil { + return diag.FromErr(err) + } + + targetMappingID, err := uuid.Parse(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + // Read the archival location. If the archival location isn't found, we + // remove it from the local state and return. + targetMapping, err := azure.Wrap(client).TargetMappingByID(ctx, targetMappingID) + if errors.Is(err, graphql.ErrNotFound) { + d.SetId("") + return nil + } + if err != nil { + return diag.FromErr(err) + } + + if err := d.Set(keyConnectionStatus, targetMapping.ConnectionStatus); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyContainerName, targetMapping.ContainerName); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyCustomerManagedKey, toCustomerManagedKeys(targetMapping.CustomerKeys)); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyLocationTemplate, targetMapping.LocTemplate); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyName, targetMapping.Name); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyRedundancy, targetMapping.Redundancy); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyStorageAccountNamePrefix, targetMapping.StorageAccountName); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyStorageAccountRegion, targetMapping.StorageAccountRegion); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyStorageAccountTags, toStorageAccountTags(targetMapping.StorageAccountTags)); err != nil { + return diag.FromErr(err) + } + if err := d.Set(keyStorageTier, targetMapping.StorageTier); err != nil { + return diag.FromErr(err) + } + + return nil +} + +func azureUpdateArchivalLocation(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + log.Print("[TRACE] azureUpdateArchivalLocation") + + client, err := m.(*client).polaris() + if err != nil { + return diag.FromErr(err) + } + + targetMappingID, err := uuid.Parse(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + customerKeys := fromCustomerManagedKeys(d.Get(keyCustomerManagedKey).(*schema.Set)) + name := d.Get(keyName).(string) + storageAccountTags, err := fromStorageAccountTags(d.Get(keyStorageAccountTags).(map[string]any)) + if err != nil { + return diag.FromErr(err) + } + storageTier := d.Get(keyStorageTier).(string) + + // Update the archival location. Note, the API doesn't support updating + // all arguments. + err = azure.Wrap(client).UpdateStorageSetting(ctx, targetMappingID, name, storageTier, storageAccountTags, customerKeys) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func azureDeleteArchivalLocation(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics { + log.Print("[TRACE] azureDeleteArchivalLocation") + + client, err := m.(*client).polaris() + if err != nil { + return diag.FromErr(err) + } + + targetMappingID, err := uuid.Parse(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + // Delete the archival location. + if err := azure.Wrap(client).DeleteTargetMapping(ctx, targetMappingID); err != nil { + return diag.FromErr(err) + } + + return nil +} + +// customerKeyResource returns the schema for a customer managed key resource. +func customerKeyResource() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + keyName: { + Type: schema.TypeString, + Required: true, + Description: "Key name.", + ValidateFunc: validation.StringIsNotWhiteSpace, + }, + keyRegion: { + Type: schema.TypeString, + Required: true, + Description: "The region in which the key will be used. Regions without customer managed keys will " + + "use platform managed keys.", + ValidateFunc: validation.StringIsNotWhiteSpace, + }, + keyVaultName: { + Type: schema.TypeString, + Required: true, + Description: "Key vault name.", + ValidateFunc: validation.StringIsNotWhiteSpace, + }, + }, + } +} + +// fromCustomerManagedKeys converts from the customer managed keys field type +// to a customer key slice. +func fromCustomerManagedKeys(customerManagedKeys *schema.Set) []azure.CustomerKey { + var customerKeys []azure.CustomerKey + for _, key := range customerManagedKeys.List() { + key := key.(map[string]any) + customerKeys = append(customerKeys, azure.CustomerKey{ + Name: key[keyName].(string), + Region: key[keyRegion].(string), + VaultName: key[keyVaultName].(string), + }) + } + + return customerKeys +} + +// toStorageAccountTags converts to the customer managed keys field type from +// a customer key slice. +func toCustomerManagedKeys(customerKeys []azure.CustomerKey) *schema.Set { + customerManagedKeys := &schema.Set{F: schema.HashResource(customerKeyResource())} + for _, key := range customerKeys { + customerManagedKeys.Add(map[string]any{ + keyName: key.Name, + keyRegion: key.Region, + keyVaultName: key.VaultName, + }) + } + + return customerManagedKeys +} + +// fromStorageAccountTags converts from the storage account tags field type to +// a standard string-to-string map. +func fromStorageAccountTags(storageAccountTags map[string]any) (map[string]string, error) { + tags := make(map[string]string, len(storageAccountTags)) + for key, value := range storageAccountTags { + value, ok := value.(string) + if !ok { + return nil, fmt.Errorf("storage account tag value for key %q is not a string", key) + } + tags[key] = value + } + + return tags, nil +} + +// toStorageAccountTags converts to the storage account tags field type from a +// standard string-to-string map. +func toStorageAccountTags(tags map[string]string) map[string]any { + storageAccountTags := make(map[string]any, len(tags)) + for key, value := range tags { + storageAccountTags[key] = value + } + + return storageAccountTags +} diff --git a/internal/provider/resource_names.go b/internal/provider/resource_names.go index 86eee63..073aef0 100644 --- a/internal/provider/resource_names.go +++ b/internal/provider/resource_names.go @@ -10,6 +10,9 @@ const ( keyCloudNativeArchival = "cloud_native_archival" keyCloudNativeArchivalEncryption = "cloud_native_archival_encryption" keyCloudNativeProtection = "cloud_native_protection" + keyConnectionStatus = "connection_status" + keyContainerName = "container_name" + keyCustomerManagedKey = "customer_managed_key" keyDataActions = "data_actions" keyDeleteSnapshotsOnDestroy = "delete_snapshots_on_destroy" keyExocompute = "exocompute" @@ -20,10 +23,7 @@ const ( keyHostCloudAccountID = "host_cloud_account_id" keyID = "id" keyIPAddresses = "ip_addresses" - keyUserAssignedManagedIdentityName = "user_assigned_managed_identity_name" - keyUserAssignedManagedIdentityPrincipalID = "user_assigned_managed_identity_principal_id" - keyUserAssignedManagedIdentityRegion = "user_assigned_managed_identity_region" - keyUserAssignedManagedIdentityResourceGroupName = "user_assigned_managed_identity_resource_group_name" + keyLocationTemplate = "location_template" keyName = "name" keyNotActions = "not_actions" keyNotDataActions = "not_data_actions" @@ -31,12 +31,14 @@ const ( keyPermissionsHash = "permissions_hash" keyPodOverlayNetworkCIDR = "pod_overlay_network_cidr" keyPolarisAccount = "polaris_account" + keyPolarisAzureArchivalLocation = "polaris_azure_archival_location" keyPolarisAzureExocompute = "polaris_azure_exocompute" keyPolarisAzurePermissions = "polaris_azure_permissions" keyPolarisAzureServicePrincipal = "polaris_azure_service_principal" keyPolarisAzureSubscription = "polaris_azure_subscription" keyPolarisDeployment = "polaris_deployment" keyPolarisFeatures = "polaris_features" + keyRedundancy = "redundancy" keyRegion = "region" keyRegions = "regions" keyResourceGroupActions = "resource_group_actions" @@ -50,6 +52,10 @@ const ( keySQLDBProtection = "sql_db_protection" keySQLMIProtection = "sql_mi_protection" keyStatus = "status" + keyStorageAccountNamePrefix = "storage_account_name_prefix" + keyStorageAccountRegion = "storage_account_region" + keyStorageAccountTags = "storage_account_tags" + keyStorageTier = "storage_tier" keySubnet = "subnet" keySubscriptionActions = "subscription_actions" keySubscriptionDataActions = "subscription_data_actions" @@ -59,5 +65,10 @@ const ( keySubscriptionNotDataActions = "subscription_not_data_actions" keyTenantDomain = "tenant_domain" keyTenantID = "tenant_id" + keyUserAssignedManagedIdentityName = "user_assigned_managed_identity_name" + keyUserAssignedManagedIdentityPrincipalID = "user_assigned_managed_identity_principal_id" + keyUserAssignedManagedIdentityRegion = "user_assigned_managed_identity_region" + keyUserAssignedManagedIdentityResourceGroupName = "user_assigned_managed_identity_resource_group_name" + keyVaultName = "vault_name" keyVersion = "version" ) diff --git a/templates/changelog.md.tmpl b/templates/changelog.md.tmpl index 57d2b3d..94bba49 100644 --- a/templates/changelog.md.tmpl +++ b/templates/changelog.md.tmpl @@ -5,9 +5,7 @@ page_title: "Changelog" # Changelog ## v0.9.0-beta.4 -* Fix an issue with the permissions of subscriptions onboarded using the `polaris_azure_subscription` resource where - the RSC UI would show the status as "Update permissions" even though the app registration would have all the required - permissions. +* Add support for creating Azure cloud native archival locations. [[docs](resources/azure_archival_location)] ## v0.9.0-beta.3 * Fix a bug in the `polaris_aws_exocompute` resource where customer supplied security groups were not validated