diff --git a/azurerm/common_schema.go b/azurerm/common_schema.go index f15d7a754964..df39bb560b4f 100644 --- a/azurerm/common_schema.go +++ b/azurerm/common_schema.go @@ -56,3 +56,7 @@ func zonesSchemaComputed() *schema.Schema { func expandZones(v []interface{}) *[]string { return azure.ExpandZones(v) } + +func azureRMHashLocation(location interface{}) int { + return azure.HashAzureLocation(location) +} diff --git a/azurerm/config.go b/azurerm/config.go index 41e41e157458..7b674c834e1f 100644 --- a/azurerm/config.go +++ b/azurerm/config.go @@ -100,10 +100,11 @@ type ArmClient struct { dnsClient dns.RecordSetsClient zonesClient dns.ZonesClient - containerRegistryClient containerregistry.RegistriesClient - containerServicesClient containerservice.ContainerServicesClient - kubernetesClustersClient containerservice.ManagedClustersClient - containerGroupsClient containerinstance.ContainerGroupsClient + containerRegistryClient containerregistry.RegistriesClient + containerRegistryReplicationsClient containerregistry.ReplicationsClient + containerServicesClient containerservice.ContainerServicesClient + kubernetesClustersClient containerservice.ManagedClustersClient + containerGroupsClient containerinstance.ContainerGroupsClient eventGridTopicsClient eventgrid.TopicsClient eventHubClient eventhub.EventHubsClient @@ -607,6 +608,11 @@ func (c *ArmClient) registerContainerRegistryClients(endpoint, subscriptionId st crc := containerregistry.NewRegistriesClientWithBaseURI(endpoint, subscriptionId) c.configureClient(&crc.Client, auth) c.containerRegistryClient = crc + + // container registry replicalication client + crrc := containerregistry.NewReplicationsClientWithBaseURI(endpoint, subscriptionId) + c.configureClient(&crrc.Client, auth) + c.containerRegistryReplicationsClient = crrc } func (c *ArmClient) registerContainerServicesClients(endpoint, subscriptionId string, auth autorest.Authorizer) { diff --git a/azurerm/helpers/azure/location.go b/azurerm/helpers/azure/location.go index 1cb64b140cda..ef6e23444e69 100644 --- a/azurerm/helpers/azure/location.go +++ b/azurerm/helpers/azure/location.go @@ -3,6 +3,7 @@ package azure import ( "strings" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" ) @@ -46,3 +47,7 @@ func NormalizeLocation(location interface{}) string { func SuppressLocationDiff(k, old, new string, d *schema.ResourceData) bool { return NormalizeLocation(old) == NormalizeLocation(new) } + +func HashAzureLocation(location interface{}) int { + return hashcode.String(NormalizeLocation(location.(string))) +} diff --git a/azurerm/resource_arm_container_registry.go b/azurerm/resource_arm_container_registry.go index d6c2a6ad294c..1371cb93042d 100644 --- a/azurerm/resource_arm_container_registry.go +++ b/azurerm/resource_arm_container_registry.go @@ -57,6 +57,17 @@ func resourceArmContainerRegistry() *schema.Resource { Default: false, }, + "georeplication_locations": { + Type: schema.TypeSet, + MinItems: 1, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.NoZeroValues, + }, + Set: azureRMHashLocation, + }, + "storage_account_id": { Type: schema.TypeString, Optional: true, @@ -101,6 +112,17 @@ func resourceArmContainerRegistry() *schema.Resource { "tags": tagsSchema(), }, + + CustomizeDiff: func(d *schema.ResourceDiff, v interface{}) error { + sku := d.Get("sku").(string) + geoReplicationLocations := d.Get("georeplication_locations").(*schema.Set) + // if locations have been specified for geo-replication then, the SKU has to be Premium + if geoReplicationLocations != nil && geoReplicationLocations.Len() > 0 && !strings.EqualFold(sku, string(containerregistry.Premium)) { + return fmt.Errorf("ACR geo-replication can only be applied when using the Premium Sku.") + } + + return nil + }, } } @@ -115,6 +137,7 @@ func resourceArmContainerRegistryCreate(d *schema.ResourceData, meta interface{} sku := d.Get("sku").(string) adminUserEnabled := d.Get("admin_enabled").(bool) tags := d.Get("tags").(map[string]interface{}) + geoReplicationLocations := d.Get("georeplication_locations").(*schema.Set) parameters := containerregistry.Registry{ Location: &location, @@ -152,6 +175,16 @@ func resourceArmContainerRegistryCreate(d *schema.ResourceData, meta interface{} return fmt.Errorf("Error waiting for creation of Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) } + // locations have been specified for geo-replication + if geoReplicationLocations != nil && geoReplicationLocations.Len() > 0 { + // the ACR is being created so no previous geo-replication locations + oldGeoReplicationLocations := []interface{}{} + err = applyGeoReplicationLocations(meta, resourceGroup, name, oldGeoReplicationLocations, geoReplicationLocations.List()) + if err != nil { + return fmt.Errorf("Error applying geo replications for Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + read, err := client.Get(ctx, resourceGroup, name) if err != nil { return fmt.Errorf("Error retrieving Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) @@ -178,6 +211,11 @@ func resourceArmContainerRegistryUpdate(d *schema.ResourceData, meta interface{} adminUserEnabled := d.Get("admin_enabled").(bool) tags := d.Get("tags").(map[string]interface{}) + old, new := d.GetChange("georeplication_locations") + hasGeoReplicationChanges := d.HasChange("georeplication_locations") + oldGeoReplicationLocations := old.(*schema.Set) + newGeoReplicationLocations := new.(*schema.Set) + parameters := containerregistry.RegistryUpdateParameters{ RegistryPropertiesUpdateParameters: &containerregistry.RegistryPropertiesUpdateParameters{ AdminUserEnabled: utils.Bool(adminUserEnabled), @@ -190,7 +228,7 @@ func resourceArmContainerRegistryUpdate(d *schema.ResourceData, meta interface{} } if v, ok := d.GetOk("storage_account_id"); ok { - if strings.ToLower(sku) != strings.ToLower(string(containerregistry.Classic)) { + if !strings.EqualFold(sku, string(containerregistry.Classic)) { return fmt.Errorf("`storage_account_id` can only be specified for a Classic (unmanaged) Sku.") } @@ -198,11 +236,24 @@ func resourceArmContainerRegistryUpdate(d *schema.ResourceData, meta interface{} ID: utils.String(v.(string)), } } else { - if strings.ToLower(sku) == strings.ToLower(string(containerregistry.Classic)) { + if strings.EqualFold(sku, string(containerregistry.Classic)) { return fmt.Errorf("`storage_account_id` must be specified for a Classic (unmanaged) Sku.") } } + // geo replication is only supported by Premium Sku + if hasGeoReplicationChanges && newGeoReplicationLocations.Len() > 0 && !strings.EqualFold(sku, string(containerregistry.Premium)) { + return fmt.Errorf("ACR geo-replication can only be applied when using the Premium Sku.") + } + + // if the registry had replications and is updated to another Sku than premium - remove old locations + if !strings.EqualFold(sku, string(containerregistry.Premium)) && oldGeoReplicationLocations != nil && oldGeoReplicationLocations.Len() > 0 { + err := applyGeoReplicationLocations(meta, resourceGroup, name, oldGeoReplicationLocations.List(), newGeoReplicationLocations.List()) + if err != nil { + return fmt.Errorf("Error applying geo replications for Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + future, err := client.Update(ctx, resourceGroup, name, parameters) if err != nil { return fmt.Errorf("Error updating Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) @@ -213,6 +264,13 @@ func resourceArmContainerRegistryUpdate(d *schema.ResourceData, meta interface{} return fmt.Errorf("Error waiting for update of Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) } + if strings.EqualFold(sku, string(containerregistry.Premium)) && hasGeoReplicationChanges { + err = applyGeoReplicationLocations(meta, resourceGroup, name, oldGeoReplicationLocations.List(), newGeoReplicationLocations.List()) + if err != nil { + return fmt.Errorf("Error applying geo replications for Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) + } + } + read, err := client.Get(ctx, resourceGroup, name) if err != nil { return fmt.Errorf("Error retrieving Container Registry %q (Resource Group %q): %+v", name, resourceGroup, err) @@ -227,8 +285,78 @@ func resourceArmContainerRegistryUpdate(d *schema.ResourceData, meta interface{} return resourceArmContainerRegistryRead(d, meta) } +func applyGeoReplicationLocations(meta interface{}, resourceGroup string, name string, oldGeoReplicationLocations []interface{}, newGeoReplicationLocations []interface{}) error { + replicationClient := meta.(*ArmClient).containerRegistryReplicationsClient + ctx := meta.(*ArmClient).StopContext + log.Printf("[INFO] preparing to apply geo-replications for AzureRM Container Registry.") + + createLocations := make(map[string]bool) + + // loop on the new location values + for _, nl := range newGeoReplicationLocations { + newLocation := azureRMNormalizeLocation(nl) + createLocations[newLocation] = true // the location needs to be created + } + + // loop on the old location values + for _, ol := range oldGeoReplicationLocations { + // oldLocation was created from a previous deployment + oldLocation := azureRMNormalizeLocation(ol) + + // if the list of locations to create already contains the location + if _, ok := createLocations[oldLocation]; ok { + createLocations[oldLocation] = false // the location do not need to be created, it already exists + } + } + + // create new geo-replication locations + for locationToCreate := range createLocations { + // if false, the location does not need to be created, continue + if !createLocations[locationToCreate] { + continue + } + + // create the new replication location + replication := containerregistry.Replication{ + Location: &locationToCreate, + Name: &locationToCreate, + } + + future, err := replicationClient.Create(ctx, resourceGroup, name, locationToCreate, replication) + if err != nil { + return fmt.Errorf("Error creating Container Registry Replication %q (Resource Group %q, Location %q): %+v", name, resourceGroup, locationToCreate, err) + } + + if err = future.WaitForCompletionRef(ctx, replicationClient.Client); err != nil { + return fmt.Errorf("Error waiting for creation of Container Registry Replication %q (Resource Group %q, Location %q): %+v", name, resourceGroup, locationToCreate, err) + } + } + + // loop on the list of previously deployed locations + for _, ol := range oldGeoReplicationLocations { + oldLocation := azureRMNormalizeLocation(ol) + // if the old location is still in the list of locations, then continue + if _, ok := createLocations[oldLocation]; ok { + continue + } + + // the old location is not in the list of locations, delete it + future, err := replicationClient.Delete(ctx, resourceGroup, name, oldLocation) + if err != nil { + return fmt.Errorf("Error deleting Container Registry Replication %q (Resource Group %q, Location %q): %+v", name, resourceGroup, oldLocation, err) + } + + if err = future.WaitForCompletionRef(ctx, replicationClient.Client); err != nil { + return fmt.Errorf("Error waiting for deletion of Container Registry Replication %q (Resource Group %q, Location %q): %+v", name, resourceGroup, oldLocation, err) + } + } + + return nil +} + func resourceArmContainerRegistryRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*ArmClient).containerRegistryClient + replicationClient := meta.(*ArmClient).containerRegistryReplicationsClient ctx := meta.(*ArmClient).StopContext id, err := parseAzureResourceID(d.Id()) @@ -251,7 +379,9 @@ func resourceArmContainerRegistryRead(d *schema.ResourceData, meta interface{}) d.Set("name", resp.Name) d.Set("resource_group_name", resourceGroup) - if location := resp.Location; location != nil { + + location := resp.Location + if location != nil { d.Set("location", azureRMNormalizeLocation(*location)) } d.Set("admin_enabled", resp.AdminUserEnabled) @@ -266,9 +396,9 @@ func resourceArmContainerRegistryRead(d *schema.ResourceData, meta interface{}) } if *resp.AdminUserEnabled { - credsResp, err := client.ListCredentials(ctx, resourceGroup, name) - if err != nil { - return fmt.Errorf("Error making Read request on Azure Container Registry %s for Credentials: %s", name, err) + credsResp, errList := client.ListCredentials(ctx, resourceGroup, name) + if errList != nil { + return fmt.Errorf("Error making Read request on Azure Container Registry %s for Credentials: %s", name, errList) } d.Set("admin_username", credsResp.Username) @@ -283,6 +413,29 @@ func resourceArmContainerRegistryRead(d *schema.ResourceData, meta interface{}) flattenAndSetTags(d, resp.Tags) + replications, err := replicationClient.List(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Error making Read request on Azure Container Registry %s for replications: %s", name, err) + } + + replicationValues := replications.Values() + + // if there is more than one location (the main one and the replicas) + if replicationValues != nil || len(replicationValues) > 1 { + georeplication_locations := &schema.Set{F: schema.HashString} + + for _, value := range replicationValues { + if value.Location != nil { + valueLocation := azureRMNormalizeLocation(*value.Location) + if location != nil && valueLocation != azureRMNormalizeLocation(*location) { + georeplication_locations.Add(valueLocation) + } + } + } + + d.Set("georeplication_locations", georeplication_locations) + } + return nil } diff --git a/azurerm/resource_arm_container_registry_test.go b/azurerm/resource_arm_container_registry_test.go index 598aaf38edfb..62e4a9c51814 100644 --- a/azurerm/resource_arm_container_registry_test.go +++ b/azurerm/resource_arm_container_registry_test.go @@ -3,8 +3,10 @@ package azurerm import ( "fmt" "net/http" + "strings" "testing" + "github.com/Azure/azure-sdk-for-go/services/containerregistry/mgmt/2017-10-01/containerregistry" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" @@ -252,6 +254,85 @@ func TestAccAzureRMContainerRegistry_update(t *testing.T) { }) } +func TestAccAzureRMContainerRegistry_geoReplication(t *testing.T) { + dataSourceName := "azurerm_container_registry.test" + skuPremium := "Premium" + skuBasic := "Basic" + ri := acctest.RandInt() + containerRegistryName := fmt.Sprintf("testacccr%d", ri) + resourceGroupName := fmt.Sprintf("testAccRg-%d", ri) + config := testAccAzureRMContainerRegistry_geoReplication(ri, testLocation(), skuPremium, `"eastus", "westus"`) + updatedConfig := testAccAzureRMContainerRegistry_geoReplication(ri, testLocation(), skuPremium, `"centralus", "eastus"`) + updatedConfigWithNoLocation := testAccAzureRMContainerRegistry_geoReplicationUpdateWithNoLocation(ri, testLocation(), skuPremium) + updatedConfigBasicSku := testAccAzureRMContainerRegistry_geoReplicationUpdateWithNoLocation(ri, testLocation(), skuBasic) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMContainerRegistryDestroy, + Steps: []resource.TestStep{ + // first config creates an ACR with locations + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", containerRegistryName), + resource.TestCheckResourceAttr(dataSourceName, "resource_group_name", resourceGroupName), + resource.TestCheckResourceAttr(dataSourceName, "sku", skuPremium), + resource.TestCheckResourceAttr(dataSourceName, "georeplication_locations.#", "2"), + testCheckAzureRMContainerRegistryExists(dataSourceName), + testCheckAzureRMContainerRegistryGeoreplications(dataSourceName, skuPremium, []string{`"eastus"`, `"westus"`}), + ), + }, + // second config udpates the ACR with updated locations + { + Config: updatedConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", containerRegistryName), + resource.TestCheckResourceAttr(dataSourceName, "resource_group_name", resourceGroupName), + resource.TestCheckResourceAttr(dataSourceName, "sku", skuPremium), + resource.TestCheckResourceAttr(dataSourceName, "georeplication_locations.#", "2"), + testCheckAzureRMContainerRegistryExists(dataSourceName), + testCheckAzureRMContainerRegistryGeoreplications(dataSourceName, skuPremium, []string{`"eastus"`, `"centralus"`}), + ), + }, + // third config udpates the ACR with no location + { + Config: updatedConfigWithNoLocation, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", containerRegistryName), + resource.TestCheckResourceAttr(dataSourceName, "resource_group_name", resourceGroupName), + resource.TestCheckResourceAttr(dataSourceName, "sku", skuPremium), + testCheckAzureRMContainerRegistryExists(dataSourceName), + testCheckAzureRMContainerRegistryGeoreplications(dataSourceName, skuPremium, nil), + ), + }, + // fourth config updates an ACR with replicas + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", containerRegistryName), + resource.TestCheckResourceAttr(dataSourceName, "resource_group_name", resourceGroupName), + resource.TestCheckResourceAttr(dataSourceName, "sku", skuPremium), + resource.TestCheckResourceAttr(dataSourceName, "georeplication_locations.#", "2"), + testCheckAzureRMContainerRegistryExists(dataSourceName), + testCheckAzureRMContainerRegistryGeoreplications(dataSourceName, skuPremium, []string{`"eastus"`, `"westus"`}), + ), + }, + // fifth config updates the SKU to basic and no replicas (should remove the existing replicas if any) + { + Config: updatedConfigBasicSku, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "name", containerRegistryName), + resource.TestCheckResourceAttr(dataSourceName, "resource_group_name", resourceGroupName), + resource.TestCheckResourceAttr(dataSourceName, "sku", skuBasic), + testCheckAzureRMContainerRegistryExists(dataSourceName), + testCheckAzureRMContainerRegistryGeoreplications(dataSourceName, skuBasic, nil), + ), + }, + }, + }) +} + func testCheckAzureRMContainerRegistryDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*ArmClient).containerRegistryClient ctx := testAccProvider.Meta().(*ArmClient).StopContext @@ -307,6 +388,46 @@ func testCheckAzureRMContainerRegistryExists(name string) resource.TestCheckFunc } } +func testCheckAzureRMContainerRegistryGeoreplications(registryName string, sku string, expectedLocations []string) resource.TestCheckFunc { + return func(s *terraform.State) error { + // Ensure we have enough information in state to look up in API + rs, ok := s.RootModule().Resources[registryName] + if !ok { + return fmt.Errorf("Not found: %s", registryName) + } + + name := rs.Primary.Attributes["name"] + resourceGroup, hasResourceGroup := rs.Primary.Attributes["resource_group_name"] + if !hasResourceGroup { + return fmt.Errorf("Bad: no resource group found in state for Container Registry: %s", name) + } + + conn := testAccProvider.Meta().(*ArmClient).containerRegistryReplicationsClient + ctx := testAccProvider.Meta().(*ArmClient).StopContext + + resp, err := conn.List(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("Bad: Get on containerRegistryClient: %+v", err) + } + + georeplicationValues := resp.Values() + expectedLocationsCount := len(expectedLocations) + 1 // the main location is returned by the API as a geolocation for replication. + + // if Sku is not premium, listing the geo-replications locations returns an empty list + if strings.ToLower(sku) != strings.ToLower(string(containerregistry.Premium)) { + expectedLocationsCount = 0 + } + + actualLocationsCount := len(georeplicationValues) + + if expectedLocationsCount != actualLocationsCount { + return fmt.Errorf("Bad: Container Registry %q (resource group: %q) expected locations count is %d, actual location count is %d", name, resourceGroup, expectedLocationsCount, actualLocationsCount) + } + + return nil + } +} + func testAccAzureRMContainerRegistry_basicManaged(rInt int, location string, sku string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { @@ -407,3 +528,36 @@ resource "azurerm_container_registry" "test" { } `, rInt, location, rStr, rInt) } + +func testAccAzureRMContainerRegistry_geoReplication(rInt int, location string, sku string, georeplicationLocations string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "testAccRg-%d" + location = "%s" +} + +resource "azurerm_container_registry" "test" { + name = "testacccr%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + sku = "%s" + georeplication_locations = [%s] +} +`, rInt, location, rInt, sku, georeplicationLocations) +} + +func testAccAzureRMContainerRegistry_geoReplicationUpdateWithNoLocation(rInt int, location string, sku string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "testAccRg-%d" + location = "%s" +} + +resource "azurerm_container_registry" "test" { + name = "testacccr%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + sku = "%s" +} +`, rInt, location, rInt, sku) +} diff --git a/examples/container-registry/README.md b/examples/container-registry/README.md new file mode 100644 index 000000000000..1fd62cfb12a9 --- /dev/null +++ b/examples/container-registry/README.md @@ -0,0 +1,20 @@ +# Azure Container Registry Sample + +Sample to deploy an Azure Container Registry + +## Creates + +1. A Resource Group +2. An [Azure Container Registry](https://azure.microsoft.com/en-us/services/container-registry/) + +## Usage + +- Provide values to all variables. +- Create with `terraform apply` +- Destroy all with `terraform destroy --force` + +## Geo-Replication + +Azure Container Registry supports [geo-replication](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-geo-replication) to help you with multi-region deployment. It is only supported by `Premium` SKU. + +To enable geo-replication with Terraform, just fill the `georeplication_locations` set with the list of Azure locations where you want the registry to be geo-replicated. \ No newline at end of file diff --git a/examples/container-registry/main.tf b/examples/container-registry/main.tf new file mode 100644 index 000000000000..d2674d3ce9ad --- /dev/null +++ b/examples/container-registry/main.tf @@ -0,0 +1,18 @@ +resource "azurerm_resource_group" "rg" { + name = "${var.resource_group_name}" + location = "${var.resource_group_location}" +} + +resource "random_integer" "ri" { + min = 10000 + max = 99999 +} + +resource "azurerm_container_registry" "acr" { + name = "acr${random_integer.ri.result}" + resource_group_name = "${azurerm_resource_group.rg.name}" + location = "${azurerm_resource_group.rg.location}" + sku = "${var.sku}" + admin_enabled = "${var.admin_enabled}" + georeplication_locations = "${var.georeplication_locations}" +} diff --git a/examples/container-registry/outputs.tf b/examples/container-registry/outputs.tf new file mode 100644 index 000000000000..d3c82a49f1dc --- /dev/null +++ b/examples/container-registry/outputs.tf @@ -0,0 +1,3 @@ +output "login_server" { + value = "${azurerm_container_registry.acr.login_server}" +} diff --git a/examples/container-registry/variables.tf b/examples/container-registry/variables.tf new file mode 100644 index 000000000000..19c53fe8910e --- /dev/null +++ b/examples/container-registry/variables.tf @@ -0,0 +1,28 @@ +variable "resource_group_name" { + type = "string" + description = "Name of the azure resource group." + default = "tfex-container-registry" +} + +variable "resource_group_location" { + type = "string" + description = "Location of the azure resource group." + default = "westus" +} + +variable "sku" { + type = "string" + description = "SKU for the Azure Container Registry" + default = "Premium" +} + +variable "admin_enabled" { + description = "Flag that indicates wether an admin account/password should be created or not" + default = false +} + +variable "georeplication_locations" { + type = "list" + description = "Azure locations where the Container Registry should be geo-replicated - Only with Premium SKU" + default = ["eastus"] +} diff --git a/website/docs/r/container_registry.html.markdown b/website/docs/r/container_registry.html.markdown index 34cb23d6f557..ff640e36f8f6 100644 --- a/website/docs/r/container_registry.html.markdown +++ b/website/docs/r/container_registry.html.markdown @@ -16,6 +16,10 @@ Manages an Azure Container Registry. ## Example Usage +### Classic (unmanaged) Container Registry + +When using the `Classic` SKU, you need to provide the Azure storage account. + ```hcl resource "azurerm_resource_group" "test" { name = "resourceGroup1" @@ -40,6 +44,26 @@ resource "azurerm_container_registry" "test" { } ``` +### Managed Container Registry + +When using a SKU other than `Classic`, Azure Container Registry manages the storage account for you. + +```hcl +resource "azurerm_resource_group" "rg" { + name = "resourceGroup1" + location = "West US" +} + +resource "azurerm_container_registry" "acr" { + name = "containerRegistry1" + resource_group_name = "${azurerm_resource_group.rg.name}" + location = "${azurerm_resource_group.rg.location}" + sku = "Premium" + admin_enabled = false + georeplication_locations = ["East US", "West Europe"] +} +``` + ## Argument Reference The following arguments are supported: @@ -58,6 +82,8 @@ The following arguments are supported: * `tags` - (Optional) A mapping of tags to assign to the resource. +* `georeplication_locations` - (Optional) A list of Azure locations where the container registry should be geo-replicated. + ## Attributes Reference The following attributes are exported: