diff --git a/azurerm/internal/services/containers/client/client.go b/azurerm/internal/services/containers/client/client.go index 63ef60d9e205..be8d364b3cb9 100644 --- a/azurerm/internal/services/containers/client/client.go +++ b/azurerm/internal/services/containers/client/client.go @@ -17,6 +17,8 @@ type Client struct { ReplicationsClient *containerregistry.ReplicationsClient ServicesClient *legacy.ContainerServicesClient WebhooksClient *containerregistry.WebhooksClient + TokensClient *containerregistry.TokensClient + ScopeMapsClient *containerregistry.ScopeMapsClient Environment azure.Environment } @@ -31,6 +33,12 @@ func NewClient(o *common.ClientOptions) *Client { replicationsClient := containerregistry.NewReplicationsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&replicationsClient.Client, o.ResourceManagerAuthorizer) + tokensClient := containerregistry.NewTokensClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&tokensClient.Client, o.ResourceManagerAuthorizer) + + scopeMapsClient := containerregistry.NewScopeMapsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) + o.ConfigureClient(&scopeMapsClient.Client, o.ResourceManagerAuthorizer) + groupsClient := containerinstance.NewContainerGroupsClientWithBaseURI(o.ResourceManagerEndpoint, o.SubscriptionId) o.ConfigureClient(&groupsClient.Client, o.ResourceManagerAuthorizer) @@ -53,5 +61,7 @@ func NewClient(o *common.ClientOptions) *Client { ReplicationsClient: &replicationsClient, ServicesClient: &servicesClient, Environment: o.Environment, + TokensClient: &tokensClient, + ScopeMapsClient: &scopeMapsClient, } } diff --git a/azurerm/internal/services/containers/container_registry_scope_map_data_source.go b/azurerm/internal/services/containers/container_registry_scope_map_data_source.go new file mode 100644 index 000000000000..bbca746ce54f --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_scope_map_data_source.go @@ -0,0 +1,79 @@ +package containers + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceContainerRegistryScopeMap() *schema.Resource { + return &schema.Resource{ + Read: dataSourceContainerRegistryScopeMapRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "container_registry_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ContainerRegistryName, + }, + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + "description": { + Type: schema.TypeString, + Computed: true, + }, + "actions": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceContainerRegistryScopeMapRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.ScopeMapsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceGroup := d.Get("resource_group_name").(string) + containerRegistryName := d.Get("container_registry_name").(string) + name := d.Get("name").(string) + + resp, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Container Registry Scope Map %q was not found in Resource Group %q", name, resourceGroup) + } + + return fmt.Errorf("Error making Read request on Scope Map %q (Azure Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("retrieving Container Registry Scope Map %q (Azure Container Registry %q, Resource Group %q): `id` was nil", name, containerRegistryName, resourceGroup) + } + + d.SetId(*resp.ID) + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + d.Set("container_registry_name", containerRegistryName) + d.Set("description", resp.Description) + d.Set("actions", utils.FlattenStringSlice(resp.Actions)) + + return nil +} diff --git a/azurerm/internal/services/containers/container_registry_scope_map_data_source_test.go b/azurerm/internal/services/containers/container_registry_scope_map_data_source_test.go new file mode 100644 index 000000000000..2a6e0353daf6 --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_scope_map_data_source_test.go @@ -0,0 +1,52 @@ +package containers_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" +) + +type ContainerRegistryScopeMapDataSource struct { +} + +func TestAccDataSourceContainerRegistryScopeMap_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_container_registry_scope_map", "test") + r := ContainerRegistryScopeMapDataSource{} + + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("container_registry_name").Exists(), + check.That(data.ResourceName).Key("description").HasValue("A test scope map"), + check.That(data.ResourceName).Key("actions.#").HasValue("1"), + check.That(data.ResourceName).Key("actions.0").HasValue("repositories/testrepo/content/read"), + ), + }, + }) +} + +func (ContainerRegistryScopeMapDataSource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_scope_map" "test" { + name = "testscopemap%d" + description = "A test scope map" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + actions = ["repositories/testrepo/content/read"] +} + +data "azurerm_container_registry_scope_map" "test" { + name = azurerm_container_registry_scope_map.test.name + container_registry_name = azurerm_container_registry.test.name + resource_group_name = azurerm_container_registry.test.resource_group_name +} + `, ContainerRegistryResource{}.basicManaged(data, "Premium"), data.RandomInteger) +} diff --git a/azurerm/internal/services/containers/container_registry_scope_map_resource.go b/azurerm/internal/services/containers/container_registry_scope_map_resource.go new file mode 100644 index 000000000000..3de73d874b13 --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_scope_map_resource.go @@ -0,0 +1,229 @@ +package containers + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2020-11-01-preview/containerregistry" + "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceContainerRegistryScopeMap() *schema.Resource { + return &schema.Resource{ + Create: resourceContainerRegistryScopeMapCreate, + Read: resourceContainerRegistryScopeMapRead, + Update: resourceContainerRegistryScopeMapUpdate, + Delete: resourceContainerRegistryScopeMapDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ContainerRegistryName, + }, + + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "container_registry_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ContainerRegistryName, + }, + + "actions": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, + }, + } +} + +func resourceContainerRegistryScopeMapCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.ScopeMapsClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for AzureRM Container Registry scope map creation.") + resourceGroup := d.Get("resource_group_name").(string) + containerRegistryName := d.Get("container_registry_name").(string) + name := d.Get("name").(string) + + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing scope map %q in Container Registry %q (Resource Group %q): %s", name, containerRegistryName, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_container_registry_scope_map", *existing.ID) + } + } + + description := d.Get("description").(string) + actions := d.Get("actions").([]interface{}) + + parameters := containerregistry.ScopeMap{ + ScopeMapProperties: &containerregistry.ScopeMapProperties{ + Description: utils.String(description), + Actions: utils.ExpandStringSlice(actions), + }, + } + + future, err := client.Create(ctx, resourceGroup, containerRegistryName, name, parameters) + if err != nil { + return fmt.Errorf("Error creating scope map %q in Container Registry %q (Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of scope map %q (Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + return fmt.Errorf("Error retrieving scope map %q for Container Registry %q (Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if read.ID == nil { + return fmt.Errorf("Cannot read scope map %q for Container Registry %q (resource group %q) ID", name, containerRegistryName, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceContainerRegistryScopeMapRead(d, meta) +} + +func resourceContainerRegistryScopeMapUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.ScopeMapsClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for AzureRM Container Registry scope map update.") + resourceGroup := d.Get("resource_group_name").(string) + containerRegistryName := d.Get("container_registry_name").(string) + name := d.Get("name").(string) + description := d.Get("description").(string) + actions := d.Get("actions").([]interface{}) + + parameters := containerregistry.ScopeMapUpdateParameters{ + ScopeMapPropertiesUpdateParameters: &containerregistry.ScopeMapPropertiesUpdateParameters{ + Description: utils.String(description), + Actions: utils.ExpandStringSlice(actions), + }, + } + + future, err := client.Update(ctx, resourceGroup, containerRegistryName, name, parameters) + if err != nil { + return fmt.Errorf("Error updating scope map %q for Container Registry %q (Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for update of scope map %q (Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + return fmt.Errorf("Error retrieving scope map %q (Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if read.ID == nil { + return fmt.Errorf("Cannot read scope map %q (Container Registry %q, resource group %q) ID", name, containerRegistryName, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceContainerRegistryScopeMapRead(d, meta) +} + +func resourceContainerRegistryScopeMapRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.ScopeMapsClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ContainerRegistryScopeMapID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.RegistryName, id.ScopeMapName) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Scope Map %q was not found in Container Registry %q in Resource Group %q", id.ScopeMapName, id.RegistryName, id.ResourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error making Read request on scope map %q in Azure Container Registry %q (Resource Group %q): %+v", id.ScopeMapName, id.RegistryName, id.ResourceGroup, err) + } + + d.Set("name", resp.Name) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("container_registry_name", id.RegistryName) + d.Set("description", resp.Description) + d.Set("actions", utils.FlattenStringSlice(resp.Actions)) + + return nil +} + +func resourceContainerRegistryScopeMapDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.ScopeMapsClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ContainerRegistryScopeMapID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.RegistryName, id.ScopeMapName) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error issuing Azure ARM delete request of Container Registry scope map '%s': %+v", id.ScopeMapName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error issuing Azure ARM delete request of Container Registry scope map '%s': %+v", id.ScopeMapName, err) + } + + return nil +} diff --git a/azurerm/internal/services/containers/container_registry_scope_map_resource_test.go b/azurerm/internal/services/containers/container_registry_scope_map_resource_test.go new file mode 100644 index 000000000000..268569bc8d95 --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_scope_map_resource_test.go @@ -0,0 +1,218 @@ +package containers_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type ContainerRegistryScopeMapResource struct { +} + +func TestAccContainerRegistryScopeMap_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_scope_map", "test") + r := ContainerRegistryScopeMapResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccContainerRegistryScopeMap_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_scope_map", "test") + r := ContainerRegistryScopeMapResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("actions.#").HasValue("1"), + check.That(data.ResourceName).Key("actions.0").HasValue("repositories/testrepo/content/read"), + ), + }, + { + Config: r.requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_container_registry_scope_map"), + }, + }) +} + +func TestAccContainerRegistryScopeMap_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_scope_map", "test") + r := ContainerRegistryScopeMapResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("actions.#").HasValue("1"), + check.That(data.ResourceName).Key("actions.0").HasValue("repositories/testrepo/content/read"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccontainerRegistryScopeMap_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_scope_map", "test") + r := ContainerRegistryScopeMapResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("actions.#").HasValue("1"), + check.That(data.ResourceName).Key("actions.0").HasValue("repositories/testrepo/content/read"), + ), + }, + data.ImportStep(), + { + Config: r.completeUpdated(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("actions.#").HasValue("2"), + check.That(data.ResourceName).Key("actions.0").HasValue("repositories/testrepo/content/read"), + check.That(data.ResourceName).Key("actions.1").HasValue("repositories/testrepo/content/delete"), + ), + }, + data.ImportStep(), + }) +} + +func (ContainerRegistryScopeMapResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.ContainerRegistryScopeMapID(state.ID) + + if err != nil { + return nil, err + } + + resp, err := clients.Containers.ScopeMapsClient.Get(ctx, id.ResourceGroup, id.RegistryName, id.ScopeMapName) + if err != nil { + return nil, fmt.Errorf("reading Container Registry Scope Map (%s): %+v", id, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (ContainerRegistryScopeMapResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-acr-%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 = "Premium" +} + +resource "azurerm_container_registry_scope_map" "test" { + name = "testscopemap%d" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + actions = ["repositories/testrepo/content/read"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r ContainerRegistryScopeMapResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_scope_map" "import" { + name = azurerm_container_registry_scope_map.test.name + resource_group_name = azurerm_container_registry_scope_map.test.resource_group_name + container_registry_name = azurerm_container_registry_scope_map.test.container_registry_name + actions = azurerm_container_registry_scope_map.test.actions +} +`, r.basic(data)) +} + +func (ContainerRegistryScopeMapResource) complete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-acr-%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 + admin_enabled = false + sku = "Premium" + + tags = { + environment = "production" + } +} + +resource "azurerm_container_registry_scope_map" "test" { + name = "testscopemap%d" + description = "An example scope map" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + actions = ["repositories/testrepo/content/read"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (ContainerRegistryScopeMapResource) completeUpdated(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-acr-%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 + admin_enabled = false + sku = "Premium" + + tags = { + environment = "production" + } +} + +resource "azurerm_container_registry_scope_map" "test" { + name = "testscopemap%d" + description = "An example scope map" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + actions = ["repositories/testrepo/content/read", "repositories/testrepo/content/delete"] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} diff --git a/azurerm/internal/services/containers/container_registry_token_data_source.go b/azurerm/internal/services/containers/container_registry_token_data_source.go new file mode 100644 index 000000000000..dd6260d2488c --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_token_data_source.go @@ -0,0 +1,87 @@ +package containers + +import ( + "fmt" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2020-11-01-preview/containerregistry" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func dataSourceContainerRegistryToken() *schema.Resource { + return &schema.Resource{ + Read: dataSourceContainerRegistryTokenRead, + + Timeouts: &schema.ResourceTimeout{ + Read: schema.DefaultTimeout(5 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ContainerRegistryName, + }, + + "container_registry_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ContainerRegistryName, + }, + + "resource_group_name": azure.SchemaResourceGroupNameForDataSource(), + + "scope_map_id": { + Type: schema.TypeString, + Computed: true, + }, + + "enabled": { + Type: schema.TypeBool, + Computed: true, + }, + }, + } +} + +func dataSourceContainerRegistryTokenRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.TokensClient + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + resourceGroup := d.Get("resource_group_name").(string) + containerRegistryName := d.Get("container_registry_name").(string) + name := d.Get("name").(string) + + resp, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + return fmt.Errorf("Container Registry token %q was not found in Resource Group %q", name, resourceGroup) + } + + return fmt.Errorf("Error making Read request on token %q (Azure Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if resp.ID == nil || *resp.ID == "" { + return fmt.Errorf("retrieving Container Registry Token %q (Azure Container Registry %q, Resource Group %q): `id` was nil", name, containerRegistryName, resourceGroup) + } + + status := true + if resp.Status == containerregistry.TokenStatusDisabled { + status = false + } + + d.SetId(*resp.ID) + d.Set("name", resp.Name) + d.Set("resource_group_name", resourceGroup) + d.Set("container_registry_name", containerRegistryName) + d.Set("scope_map_id", resp.ScopeMapID) + d.Set("enabled", status) + + return nil +} diff --git a/azurerm/internal/services/containers/container_registry_token_data_source_test.go b/azurerm/internal/services/containers/container_registry_token_data_source_test.go new file mode 100644 index 000000000000..4831715fb42d --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_token_data_source_test.go @@ -0,0 +1,57 @@ +package containers_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" +) + +type ContainerRegistryTokenDataSource struct { +} + +func TestAccDataSourceContainerRegistryToken_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_container_registry_token", "test") + r := ContainerRegistryTokenDataSource{} + + data.DataSourceTest(t, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).Key("name").Exists(), + check.That(data.ResourceName).Key("resource_group_name").Exists(), + check.That(data.ResourceName).Key("container_registry_name").Exists(), + check.That(data.ResourceName).Key("scope_map_id").Exists(), + check.That(data.ResourceName).Key("enabled").HasValue("true"), + ), + }, + }) +} + +func (ContainerRegistryTokenDataSource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +data "azurerm_container_registry_scope_map" "pull_repos" { + name = "_repositories_pull" + container_registry_name = azurerm_container_registry.test.name + resource_group_name = azurerm_container_registry.test.resource_group_name +} + +resource "azurerm_container_registry_token" "test" { + name = "testtoken%d" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + scope_map_id = data.azurerm_container_registry_scope_map.pull_repos.id + enabled = true +} + +data "azurerm_container_registry_token" "test" { + name = azurerm_container_registry_token.test.name + container_registry_name = azurerm_container_registry.test.name + resource_group_name = azurerm_container_registry.test.resource_group_name +} + `, ContainerRegistryResource{}.basicManaged(data, "Premium"), data.RandomInteger) +} diff --git a/azurerm/internal/services/containers/container_registry_token_resource.go b/azurerm/internal/services/containers/container_registry_token_resource.go new file mode 100644 index 000000000000..c7ea213d7f9c --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_token_resource.go @@ -0,0 +1,239 @@ +package containers + +import ( + "fmt" + "log" + "time" + + "github.com/Azure/azure-sdk-for-go/services/preview/containerregistry/mgmt/2020-11-01-preview/containerregistry" + "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/tf" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/validate" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/timeouts" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +func resourceContainerRegistryToken() *schema.Resource { + return &schema.Resource{ + Create: resourceContainerRegistryTokenCreate, + Read: resourceContainerRegistryTokenRead, + Update: resourceContainerRegistryTokenUpdate, + Delete: resourceContainerRegistryTokenDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Read: schema.DefaultTimeout(5 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ContainerRegistryName, + }, + + "resource_group_name": azure.SchemaResourceGroupName(), + + "container_registry_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validate.ContainerRegistryName, + }, + + "scope_map_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.ContainerRegistryScopeMapID, + }, + + "enabled": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + }, + } +} + +func resourceContainerRegistryTokenCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.TokensClient + + ctx, cancel := timeouts.ForCreate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for AzureRM Container Registry token creation.") + resourceGroup := d.Get("resource_group_name").(string) + containerRegistryName := d.Get("container_registry_name").(string) + name := d.Get("name").(string) + + if d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + if !utils.ResponseWasNotFound(existing.Response) { + return fmt.Errorf("Error checking for presence of existing token %q in Container Registry %q (Resource Group %q): %s", name, containerRegistryName, resourceGroup, err) + } + } + + if existing.ID != nil && *existing.ID != "" { + return tf.ImportAsExistsError("azurerm_container_registry_token", *existing.ID) + } + } + + scopeMapID := d.Get("scope_map_id").(string) + enabled := d.Get("enabled").(bool) + status := containerregistry.TokenStatusEnabled + + if !enabled { + status = containerregistry.TokenStatusDisabled + } + + parameters := containerregistry.Token{ + TokenProperties: &containerregistry.TokenProperties{ + ScopeMapID: utils.String(scopeMapID), + Status: status, + }, + } + + future, err := client.Create(ctx, resourceGroup, containerRegistryName, name, parameters) + if err != nil { + return fmt.Errorf("Error creating token %q in Container Registry %q (Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for creation of token %q (Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + return fmt.Errorf("Error retrieving token %q for Container Registry %q (Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if read.ID == nil { + return fmt.Errorf("Cannot read token %q for Container Registry %q (resource group %q) ID", name, containerRegistryName, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceContainerRegistryTokenRead(d, meta) +} +func resourceContainerRegistryTokenUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.TokensClient + ctx, cancel := timeouts.ForUpdate(meta.(*clients.Client).StopContext, d) + defer cancel() + + log.Printf("[INFO] preparing arguments for AzureRM Container Registry token update.") + resourceGroup := d.Get("resource_group_name").(string) + containerRegistryName := d.Get("container_registry_name").(string) + name := d.Get("name").(string) + scopeMapID := d.Get("scope_map_id").(string) + enabled := d.Get("enabled").(bool) + status := containerregistry.TokenStatusEnabled + + if !enabled { + status = containerregistry.TokenStatusDisabled + } + + parameters := containerregistry.TokenUpdateParameters{ + TokenUpdateProperties: &containerregistry.TokenUpdateProperties{ + ScopeMapID: utils.String(scopeMapID), + Status: status, + }, + } + + future, err := client.Update(ctx, resourceGroup, containerRegistryName, name, parameters) + if err != nil { + return fmt.Errorf("Error updating token %q for Container Registry %q (Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("Error waiting for update of token %q (Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + read, err := client.Get(ctx, resourceGroup, containerRegistryName, name) + if err != nil { + return fmt.Errorf("Error retrieving token %q (Container Registry %q, Resource Group %q): %+v", name, containerRegistryName, resourceGroup, err) + } + + if read.ID == nil { + return fmt.Errorf("Cannot read token %q (Container Registry %q, resource group %q) ID", name, containerRegistryName, resourceGroup) + } + + d.SetId(*read.ID) + + return resourceContainerRegistryTokenRead(d, meta) +} + +func resourceContainerRegistryTokenRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.TokensClient + ctx, cancel := timeouts.ForRead(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ContainerRegistryTokenID(d.Id()) + if err != nil { + return err + } + + resp, err := client.Get(ctx, id.ResourceGroup, id.RegistryName, id.TokenName) + + if err != nil { + if utils.ResponseWasNotFound(resp.Response) { + log.Printf("[DEBUG] Token %q was not found in Container Registry %q in Resource Group %q", id.TokenName, id.RegistryName, id.ResourceGroup) + d.SetId("") + return nil + } + + return fmt.Errorf("Error making Read request on token %q in Azure Container Registry %q (Resource Group %q): %+v", id.TokenName, id.RegistryName, id.ResourceGroup, err) + } + + status := true + if resp.Status == containerregistry.TokenStatusDisabled { + status = false + } + + d.Set("name", resp.Name) + d.Set("container_registry_name", id.RegistryName) + d.Set("enabled", status) + d.Set("resource_group_name", id.ResourceGroup) + d.Set("scope_map_id", resp.ScopeMapID) + + return nil +} + +func resourceContainerRegistryTokenDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*clients.Client).Containers.TokensClient + ctx, cancel := timeouts.ForDelete(meta.(*clients.Client).StopContext, d) + defer cancel() + + id, err := parse.ContainerRegistryTokenID(d.Id()) + if err != nil { + return err + } + + future, err := client.Delete(ctx, id.ResourceGroup, id.RegistryName, id.TokenName) + if err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error issuing Azure ARM delete request of Container Registry token '%s': %+v", id.TokenName, err) + } + + if err = future.WaitForCompletionRef(ctx, client.Client); err != nil { + if response.WasNotFound(future.Response()) { + return nil + } + return fmt.Errorf("Error issuing Azure ARM delete request of Container Registry token '%s': %+v", id.TokenName, err) + } + + return nil +} diff --git a/azurerm/internal/services/containers/container_registry_token_resource_test.go b/azurerm/internal/services/containers/container_registry_token_resource_test.go new file mode 100644 index 000000000000..d26250ab9b44 --- /dev/null +++ b/azurerm/internal/services/containers/container_registry_token_resource_test.go @@ -0,0 +1,192 @@ +package containers_test + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/acceptance/check" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/clients" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" +) + +type ContainerRegistryTokenResource struct{} + +func TestAccContainerRegistryToken_basic(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_token", "test") + r := ContainerRegistryTokenResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + +func TestAccContainerRegistryToken_requiresImport(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_token", "test") + r := ContainerRegistryTokenResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.basic(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + { + Config: r.requiresImport(data), + ExpectError: acceptance.RequiresImportError("azurerm_container_registry_token"), + }, + }) +} + +func TestAccContainerRegistryToken_complete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_token", "test") + r := ContainerRegistryTokenResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data, true), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enabled").HasValue("true"), + ), + }, + data.ImportStep(), + }) +} + +func TestAccContainerRegistryToken_update(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_container_registry_token", "test") + r := ContainerRegistryTokenResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.complete(data, true), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enabled").HasValue("true"), + ), + }, + data.ImportStep(), + { + Config: r.complete(data, false), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("enabled").HasValue("false"), + ), + }, + data.ImportStep(), + }) +} + +func (t ContainerRegistryTokenResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { + id, err := parse.ContainerRegistryTokenID(state.ID) + + if err != nil { + return nil, err + } + + resp, err := clients.Containers.TokensClient.Get(ctx, id.ResourceGroup, id.RegistryName, id.TokenName) + if err != nil { + return nil, fmt.Errorf("reading Container Registry Token (%s): %+v", id, err) + } + + return utils.Bool(resp.ID != nil), nil +} + +func (r ContainerRegistryTokenResource) basic(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-acr-%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 = "Premium" +} + +# use system wide scope map for tests +data "azurerm_container_registry_scope_map" "pull_repos" { + name = "_repositories_pull" + container_registry_name = azurerm_container_registry.test.name + resource_group_name = azurerm_container_registry.test.resource_group_name +} + +resource "azurerm_container_registry_token" "test" { + name = "testtoken%d" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + scope_map_id = data.azurerm_container_registry_scope_map.pull_repos.id +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func (r ContainerRegistryTokenResource) requiresImport(data acceptance.TestData) string { + return fmt.Sprintf(` +%s + +resource "azurerm_container_registry_token" "import" { + name = azurerm_container_registry_token.test.name + resource_group_name = azurerm_container_registry_token.test.resource_group_name + container_registry_name = azurerm_container_registry_token.test.container_registry_name + scope_map_id = azurerm_container_registry_token.test.scope_map_id +} +`, r.basic(data)) +} + +func (r ContainerRegistryTokenResource) complete(data acceptance.TestData, status bool) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-acr-%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 + admin_enabled = false + sku = "Premium" + + tags = { + environment = "production" + } +} + +# use system wide scope map for tests +data "azurerm_container_registry_scope_map" "pull_repos" { + name = "_repositories_pull" + container_registry_name = azurerm_container_registry.test.name + resource_group_name = azurerm_container_registry.test.resource_group_name +} + +resource "azurerm_container_registry_token" "test" { + name = "testtoken%d" + resource_group_name = azurerm_resource_group.test.name + container_registry_name = azurerm_container_registry.test.name + scope_map_id = data.azurerm_container_registry_scope_map.pull_repos.id + enabled = %t +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, status) +} diff --git a/azurerm/internal/services/containers/parse/container_registry_scope_map.go b/azurerm/internal/services/containers/parse/container_registry_scope_map.go new file mode 100644 index 000000000000..8fafece12e51 --- /dev/null +++ b/azurerm/internal/services/containers/parse/container_registry_scope_map.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type ContainerRegistryScopeMapId struct { + SubscriptionId string + ResourceGroup string + RegistryName string + ScopeMapName string +} + +func NewContainerRegistryScopeMapID(subscriptionId, resourceGroup, registryName, scopeMapName string) ContainerRegistryScopeMapId { + return ContainerRegistryScopeMapId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + RegistryName: registryName, + ScopeMapName: scopeMapName, + } +} + +func (id ContainerRegistryScopeMapId) String() string { + segments := []string{ + fmt.Sprintf("Scope Map Name %q", id.ScopeMapName), + fmt.Sprintf("Registry Name %q", id.RegistryName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Container Registry Scope Map", segmentsStr) +} + +func (id ContainerRegistryScopeMapId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerRegistry/registries/%s/scopeMaps/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.RegistryName, id.ScopeMapName) +} + +// ContainerRegistryScopeMapID parses a ContainerRegistryScopeMap ID into an ContainerRegistryScopeMapId struct +func ContainerRegistryScopeMapID(input string) (*ContainerRegistryScopeMapId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ContainerRegistryScopeMapId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.RegistryName, err = id.PopSegment("registries"); err != nil { + return nil, err + } + if resourceId.ScopeMapName, err = id.PopSegment("scopeMaps"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/containers/parse/container_registry_scope_map_test.go b/azurerm/internal/services/containers/parse/container_registry_scope_map_test.go new file mode 100644 index 000000000000..d204beb01211 --- /dev/null +++ b/azurerm/internal/services/containers/parse/container_registry_scope_map_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = ContainerRegistryScopeMapId{} + +func TestContainerRegistryScopeMapIDFormatter(t *testing.T) { + actual := NewContainerRegistryScopeMapID("12345678-1234-9876-4563-123456789012", "resGroup1", "registry1", "scopeMap1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/scopeMap1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestContainerRegistryScopeMapID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ContainerRegistryScopeMapId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/", + Error: true, + }, + + { + // missing value for RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/", + Error: true, + }, + + { + // missing ScopeMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/", + Error: true, + }, + + { + // missing value for ScopeMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/scopeMap1", + Expected: &ContainerRegistryScopeMapId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + RegistryName: "registry1", + ScopeMapName: "scopeMap1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CONTAINERREGISTRY/REGISTRIES/REGISTRY1/SCOPEMAPS/SCOPEMAP1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ContainerRegistryScopeMapID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.RegistryName != v.Expected.RegistryName { + t.Fatalf("Expected %q but got %q for RegistryName", v.Expected.RegistryName, actual.RegistryName) + } + if actual.ScopeMapName != v.Expected.ScopeMapName { + t.Fatalf("Expected %q but got %q for ScopeMapName", v.Expected.ScopeMapName, actual.ScopeMapName) + } + } +} diff --git a/azurerm/internal/services/containers/parse/container_registry_token.go b/azurerm/internal/services/containers/parse/container_registry_token.go new file mode 100644 index 000000000000..08fee846f4ae --- /dev/null +++ b/azurerm/internal/services/containers/parse/container_registry_token.go @@ -0,0 +1,75 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + "strings" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/helpers/azure" +) + +type ContainerRegistryTokenId struct { + SubscriptionId string + ResourceGroup string + RegistryName string + TokenName string +} + +func NewContainerRegistryTokenID(subscriptionId, resourceGroup, registryName, tokenName string) ContainerRegistryTokenId { + return ContainerRegistryTokenId{ + SubscriptionId: subscriptionId, + ResourceGroup: resourceGroup, + RegistryName: registryName, + TokenName: tokenName, + } +} + +func (id ContainerRegistryTokenId) String() string { + segments := []string{ + fmt.Sprintf("Token Name %q", id.TokenName), + fmt.Sprintf("Registry Name %q", id.RegistryName), + fmt.Sprintf("Resource Group %q", id.ResourceGroup), + } + segmentsStr := strings.Join(segments, " / ") + return fmt.Sprintf("%s: (%s)", "Container Registry Token", segmentsStr) +} + +func (id ContainerRegistryTokenId) ID() string { + fmtString := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.ContainerRegistry/registries/%s/tokens/%s" + return fmt.Sprintf(fmtString, id.SubscriptionId, id.ResourceGroup, id.RegistryName, id.TokenName) +} + +// ContainerRegistryTokenID parses a ContainerRegistryToken ID into an ContainerRegistryTokenId struct +func ContainerRegistryTokenID(input string) (*ContainerRegistryTokenId, error) { + id, err := azure.ParseAzureResourceID(input) + if err != nil { + return nil, err + } + + resourceId := ContainerRegistryTokenId{ + SubscriptionId: id.SubscriptionID, + ResourceGroup: id.ResourceGroup, + } + + if resourceId.SubscriptionId == "" { + return nil, fmt.Errorf("ID was missing the 'subscriptions' element") + } + + if resourceId.ResourceGroup == "" { + return nil, fmt.Errorf("ID was missing the 'resourceGroups' element") + } + + if resourceId.RegistryName, err = id.PopSegment("registries"); err != nil { + return nil, err + } + if resourceId.TokenName, err = id.PopSegment("tokens"); err != nil { + return nil, err + } + + if err := id.ValidateNoEmptySegments(input); err != nil { + return nil, err + } + + return &resourceId, nil +} diff --git a/azurerm/internal/services/containers/parse/container_registry_token_test.go b/azurerm/internal/services/containers/parse/container_registry_token_test.go new file mode 100644 index 000000000000..04dac02f8a5b --- /dev/null +++ b/azurerm/internal/services/containers/parse/container_registry_token_test.go @@ -0,0 +1,128 @@ +package parse + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "testing" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/resourceid" +) + +var _ resourceid.Formatter = ContainerRegistryTokenId{} + +func TestContainerRegistryTokenIDFormatter(t *testing.T) { + actual := NewContainerRegistryTokenID("12345678-1234-9876-4563-123456789012", "resGroup1", "registry1", "token1").ID() + expected := "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/token1" + if actual != expected { + t.Fatalf("Expected %q but got %q", expected, actual) + } +} + +func TestContainerRegistryTokenID(t *testing.T) { + testData := []struct { + Input string + Error bool + Expected *ContainerRegistryTokenId + }{ + + { + // empty + Input: "", + Error: true, + }, + + { + // missing SubscriptionId + Input: "/", + Error: true, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Error: true, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Error: true, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Error: true, + }, + + { + // missing RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/", + Error: true, + }, + + { + // missing value for RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/", + Error: true, + }, + + { + // missing TokenName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/", + Error: true, + }, + + { + // missing value for TokenName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/", + Error: true, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/token1", + Expected: &ContainerRegistryTokenId{ + SubscriptionId: "12345678-1234-9876-4563-123456789012", + ResourceGroup: "resGroup1", + RegistryName: "registry1", + TokenName: "token1", + }, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CONTAINERREGISTRY/REGISTRIES/REGISTRY1/TOKENS/TOKEN1", + Error: true, + }, + } + + for _, v := range testData { + t.Logf("[DEBUG] Testing %q", v.Input) + + actual, err := ContainerRegistryTokenID(v.Input) + if err != nil { + if v.Error { + continue + } + + t.Fatalf("Expect a value but got an error: %s", err) + } + if v.Error { + t.Fatal("Expect an error but didn't get one") + } + + if actual.SubscriptionId != v.Expected.SubscriptionId { + t.Fatalf("Expected %q but got %q for SubscriptionId", v.Expected.SubscriptionId, actual.SubscriptionId) + } + if actual.ResourceGroup != v.Expected.ResourceGroup { + t.Fatalf("Expected %q but got %q for ResourceGroup", v.Expected.ResourceGroup, actual.ResourceGroup) + } + if actual.RegistryName != v.Expected.RegistryName { + t.Fatalf("Expected %q but got %q for RegistryName", v.Expected.RegistryName, actual.RegistryName) + } + if actual.TokenName != v.Expected.TokenName { + t.Fatalf("Expected %q but got %q for TokenName", v.Expected.TokenName, actual.TokenName) + } + } +} diff --git a/azurerm/internal/services/containers/registration.go b/azurerm/internal/services/containers/registration.go index 1d162646b60e..5459e6d8dad4 100644 --- a/azurerm/internal/services/containers/registration.go +++ b/azurerm/internal/services/containers/registration.go @@ -23,6 +23,8 @@ func (r Registration) SupportedDataSources() map[string]*schema.Resource { return map[string]*schema.Resource{ "azurerm_kubernetes_service_versions": dataSourceKubernetesServiceVersions(), "azurerm_container_registry": dataSourceContainerRegistry(), + "azurerm_container_registry_token": dataSourceContainerRegistryToken(), + "azurerm_container_registry_scope_map": dataSourceContainerRegistryScopeMap(), "azurerm_kubernetes_cluster": dataSourceKubernetesCluster(), "azurerm_kubernetes_cluster_node_pool": dataSourceKubernetesClusterNodePool(), } @@ -34,6 +36,8 @@ func (r Registration) SupportedResources() map[string]*schema.Resource { "azurerm_container_group": resourceContainerGroup(), "azurerm_container_registry_webhook": resourceContainerRegistryWebhook(), "azurerm_container_registry": resourceContainerRegistry(), + "azurerm_container_registry_token": resourceContainerRegistryToken(), + "azurerm_container_registry_scope_map": resourceContainerRegistryScopeMap(), "azurerm_kubernetes_cluster": resourceKubernetesCluster(), "azurerm_kubernetes_cluster_node_pool": resourceKubernetesClusterNodePool(), } diff --git a/azurerm/internal/services/containers/resourceids.go b/azurerm/internal/services/containers/resourceids.go index 744326c5b668..e3706d3fb471 100644 --- a/azurerm/internal/services/containers/resourceids.go +++ b/azurerm/internal/services/containers/resourceids.go @@ -3,3 +3,5 @@ package containers //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=Cluster -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerService/managedClusters/cluster1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=NodePool -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerService/managedClusters/cluster1/agentPools/pool1 //go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerGroup -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerInstance/containerGroups/containerGroup1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerRegistryScopeMap -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/scopeMap1 +//go:generate go run ../../tools/generator-resource-id/main.go -path=./ -name=ContainerRegistryToken -id=/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/token1 diff --git a/azurerm/internal/services/containers/validate/container_registry_scope_map_id.go b/azurerm/internal/services/containers/validate/container_registry_scope_map_id.go new file mode 100644 index 000000000000..f3449c429206 --- /dev/null +++ b/azurerm/internal/services/containers/validate/container_registry_scope_map_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" +) + +func ContainerRegistryScopeMapID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ContainerRegistryScopeMapID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/containers/validate/container_registry_scope_map_id_test.go b/azurerm/internal/services/containers/validate/container_registry_scope_map_id_test.go new file mode 100644 index 000000000000..43ce7038a634 --- /dev/null +++ b/azurerm/internal/services/containers/validate/container_registry_scope_map_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestContainerRegistryScopeMapID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/", + Valid: false, + }, + + { + // missing value for RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/", + Valid: false, + }, + + { + // missing ScopeMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/", + Valid: false, + }, + + { + // missing value for ScopeMapName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/scopeMaps/scopeMap1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CONTAINERREGISTRY/REGISTRIES/REGISTRY1/SCOPEMAPS/SCOPEMAP1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ContainerRegistryScopeMapID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/azurerm/internal/services/containers/validate/container_registry_token_id.go b/azurerm/internal/services/containers/validate/container_registry_token_id.go new file mode 100644 index 000000000000..7a464f272cdc --- /dev/null +++ b/azurerm/internal/services/containers/validate/container_registry_token_id.go @@ -0,0 +1,23 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import ( + "fmt" + + "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/containers/parse" +) + +func ContainerRegistryTokenID(input interface{}, key string) (warnings []string, errors []error) { + v, ok := input.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected %q to be a string", key)) + return + } + + if _, err := parse.ContainerRegistryTokenID(v); err != nil { + errors = append(errors, err) + } + + return +} diff --git a/azurerm/internal/services/containers/validate/container_registry_token_id_test.go b/azurerm/internal/services/containers/validate/container_registry_token_id_test.go new file mode 100644 index 000000000000..3fe8e57715cf --- /dev/null +++ b/azurerm/internal/services/containers/validate/container_registry_token_id_test.go @@ -0,0 +1,88 @@ +package validate + +// NOTE: this file is generated via 'go:generate' - manual changes will be overwritten + +import "testing" + +func TestContainerRegistryTokenID(t *testing.T) { + cases := []struct { + Input string + Valid bool + }{ + + { + // empty + Input: "", + Valid: false, + }, + + { + // missing SubscriptionId + Input: "/", + Valid: false, + }, + + { + // missing value for SubscriptionId + Input: "/subscriptions/", + Valid: false, + }, + + { + // missing ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/", + Valid: false, + }, + + { + // missing value for ResourceGroup + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/", + Valid: false, + }, + + { + // missing RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/", + Valid: false, + }, + + { + // missing value for RegistryName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/", + Valid: false, + }, + + { + // missing TokenName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/", + Valid: false, + }, + + { + // missing value for TokenName + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/", + Valid: false, + }, + + { + // valid + Input: "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/resGroup1/providers/Microsoft.ContainerRegistry/registries/registry1/tokens/token1", + Valid: true, + }, + + { + // upper-cased + Input: "/SUBSCRIPTIONS/12345678-1234-9876-4563-123456789012/RESOURCEGROUPS/RESGROUP1/PROVIDERS/MICROSOFT.CONTAINERREGISTRY/REGISTRIES/REGISTRY1/TOKENS/TOKEN1", + Valid: false, + }, + } + for _, tc := range cases { + t.Logf("[DEBUG] Testing Value %s", tc.Input) + _, errors := ContainerRegistryTokenID(tc.Input, "test") + valid := len(errors) == 0 + + if tc.Valid != valid { + t.Fatalf("Expected %t but got %t", tc.Valid, valid) + } + } +} diff --git a/website/docs/d/container_registry_scope_map.html.markdown b/website/docs/d/container_registry_scope_map.html.markdown new file mode 100644 index 000000000000..02caefa3db65 --- /dev/null +++ b/website/docs/d/container_registry_scope_map.html.markdown @@ -0,0 +1,46 @@ +--- +subcategory: "Container" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_container_registry_scope_map" +description: |- + Get information about an existing Container Registry scope map + +--- + +# Data Source: azurerm_container_registry_scope_map + +Use this data source to access information about an existing Container Registry scope map. + +## Example Usage + +```hcl +data "azurerm_container_registry_scope_map" "example" { + name = "example-scope-map" + resource_group_name = "example-resource-group" + container_registry_name = "example-registry" +} + +output "actions" { + value = data.azurerm_container_registry_scope_map.example.actions +} +``` + +## Argument Reference + +* `name` - The name of the Container Registry token. +* `container_registry_name` - The Name of the Container Registry where the token exists. +* `resource_group_name` - The Name of the Resource Group where this Container Registry token exists. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The Container Registry scope map ID. + +* `actions` - The actions for the Scope Map. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the Container Registry scope map. diff --git a/website/docs/d/container_registry_token.html.markdown b/website/docs/d/container_registry_token.html.markdown new file mode 100644 index 000000000000..2ff6816f4335 --- /dev/null +++ b/website/docs/d/container_registry_token.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "Container" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_container_registry_token" +description: |- + Get information about an existing Container Registry token + +--- + +# Data Source: azurerm_container_registry_token + +Use this data source to access information about an existing Container Registry token. + +## Example Usage + +```hcl +data "azurerm_container_registry_token" "example" { + name = "exampletoken" + resource_group_name = "example-resource-group" + container_registry_name = "example-registry" +} + +output "scope_map_id" { + value = data.azurerm_container_registry_token.example.scope_map_id +} +``` + +## Argument Reference + +* `name` - The name of the Container Registry token. +* `container_registry_name` - The Name of the Container Registry where the token exists. +* `resource_group_name` - The Name of the Resource Group where this Container Registry token exists. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The Container Registry token ID. + +* `scope_map_id` - The Scope Map ID used by the token. + +* `enabled` - Whether this Token is enabled. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `read` - (Defaults to 5 minutes) Used when retrieving the Container Registry token. diff --git a/website/docs/r/container_registry_scope_map.html.markdown b/website/docs/r/container_registry_scope_map.html.markdown new file mode 100644 index 000000000000..e853289380dd --- /dev/null +++ b/website/docs/r/container_registry_scope_map.html.markdown @@ -0,0 +1,75 @@ +--- +subcategory: "Container" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_container_registry_scope_map" +description: |- + Manages an Azure Container Registry scope map. + +--- + +# azurerm_container_registry_scope_map + +Manages an Azure Container Registry scope map. Scope Maps are a preview feature only available in Premium SKU Container registries. + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resource-group" + location = "West Europe" +} + +resource "azurerm_container_registry" "example" { + name = "example-registry" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + sku = "Premium" + admin_enabled = false + georeplication_locations = ["East US", "West Europe"] +} + +resource "azurerm_container_registry_scope_map" "example" { + name = "example-scope-map" + container_registry_name = azurerm_container_registry.acr.name + resource_group_name = azurerm_resource_group.rg.name + actions = [ + "repositories/repo1/content/read", + "repositories/repo1/content/create" + ] +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - (Required) Specifies the name of the scope map. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which to create the Container Registry token. Changing this forces a new resource to be created. + +* `container_registry_name` - (Required) The name of the Container Registry. Changing this forces a new resource to be created. + +* `actions` - (Required) A list of actions to attach to the scope map (e.g. `repo/content/read`, `repo2/content/delete`). + +--- +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Container Registry scope map. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Container Registry scope map. +* `update` - (Defaults to 30 minutes) Used when updating the Container Registry scope map. +* `read` - (Defaults to 5 minutes) Used when retrieving the Container Registry scope map. +* `delete` - (Defaults to 30 minutes) Used when deleting the Container Registry scope map. + +## Import + +Container Registries can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_container_registry_scope_map.example /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/mygroup1/providers/Microsoft.ContainerRegistry/registries/myregistry1/scopeMaps/scopemap1 +``` diff --git a/website/docs/r/container_registry_token.html.markdown b/website/docs/r/container_registry_token.html.markdown new file mode 100644 index 000000000000..b3592152f8a0 --- /dev/null +++ b/website/docs/r/container_registry_token.html.markdown @@ -0,0 +1,84 @@ +--- +subcategory: "Container" +layout: "azurerm" +page_title: "Azure Resource Manager: azurerm_container_registry_token" +description: |- + Manages an Azure Container Registry token. + +--- + +# azurerm_container_registry_token + +Manages an Azure Container Registry token. Tokens are a preview feature only available in Premium SKU Container registries. + +```hcl +resource "azurerm_resource_group" "example" { + name = "example-resource-group" + location = "West Europe" +} + +resource "azurerm_container_registry" "example" { + name = "example-registry" + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + sku = "Premium" + admin_enabled = false + georeplication_locations = ["East US", "West Europe"] +} + +resource "azurerm_container_registry_scope_map" "example" { + name = "example-scope-map" + container_registry_name = azurerm_container_registry.acr.name + resource_group_name = azurerm_resource_group.rg.name + actions = [ + "repositories/repo1/content/read", + "repositories/repo1/content/create" + ] +} + +resource "azurerm_container_registry_token" "example" { + name = "exampletoken" + container_registry_name = azurerm_container_registry.acr.name + resource_group_name = azurerm_resource_group.rg.name + scope_map_id = azurerm_container_registry_scope_map.map.id +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `name` - (Required) Specifies the name of the token. Changing this forces a new resource to be created. + +* `resource_group_name` - (Required) The name of the resource group in which to create the Container Registry token. Changing this forces a new resource to be created. + +* `container_registry_name` - (Required) The name of the Container Registry. Changing this forces a new resource to be created. + +* `scope_map_id` - (Required) The ID of the Container Registry Scope Map associated with the token. + +* `enabled` - (Optional) Should the Container Registry token be enabled? Defaults to `true`. + +--- +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the Container Registry token. + +## Timeouts + +The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: + +* `create` - (Defaults to 30 minutes) Used when creating the Container Registry token. +* `update` - (Defaults to 30 minutes) Used when updating the Container Registry token. +* `read` - (Defaults to 5 minutes) Used when retrieving the Container Registry token. +* `delete` - (Defaults to 30 minutes) Used when deleting the Container Registry token. + +## Import + +Container Registries can be imported using the `resource id`, e.g. + +```shell +terraform import azurerm_container_registry_token.example /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/mygroup1/providers/Microsoft.ContainerRegistry/registries/myregistry1/tokens/token1 +```