Skip to content

Commit

Permalink
provider/azurerm: Container Registry (#10973)
Browse files Browse the repository at this point in the history
* Fixing the indentation

* Adding the Container Registry SDK

* Implementing the container registry

* Enabling the provider / registering the Resource Provider

* Acceptance Tests

* Documentation for Container Registry

* Fixing the name validation

* Validation for the Container Registry Name

* Added Import support for Containr Registry

* Storage Account is no longer optional

* Updating the docs

* Forcing a re-run in Travis
  • Loading branch information
tombuildsstuff authored and stack72 committed Jan 2, 2017
1 parent de414ee commit 874ec8b
Show file tree
Hide file tree
Showing 13 changed files with 1,538 additions and 8 deletions.
9 changes: 9 additions & 0 deletions builtin/providers/azurerm/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/Azure/azure-sdk-for-go/arm/cdn"
"github.com/Azure/azure-sdk-for-go/arm/compute"
"github.com/Azure/azure-sdk-for-go/arm/containerregistry"
"github.com/Azure/azure-sdk-for-go/arm/eventhub"
"github.com/Azure/azure-sdk-for-go/arm/keyvault"
"github.com/Azure/azure-sdk-for-go/arm/network"
Expand Down Expand Up @@ -63,6 +64,8 @@ type ArmClient struct {
cdnProfilesClient cdn.ProfilesClient
cdnEndpointsClient cdn.EndpointsClient

containerRegistryClient containerregistry.RegistriesClient

eventHubClient eventhub.EventHubsClient
eventHubConsumerGroupClient eventhub.ConsumerGroupsClient
eventHubNamespacesClient eventhub.NamespacesClient
Expand Down Expand Up @@ -221,6 +224,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
agc.Sender = autorest.CreateSender(withRequestLogging())
client.appGatewayClient = agc

crc := containerregistry.NewRegistriesClient(c.SubscriptionID)
setUserAgent(&crc.Client)
crc.Authorizer = spt
crc.Sender = autorest.CreateSender(withRequestLogging())
client.containerRegistryClient = crc

ehc := eventhub.NewEventHubsClient(c.SubscriptionID)
setUserAgent(&ehc.Client)
ehc.Authorizer = spt
Expand Down
61 changes: 61 additions & 0 deletions builtin/providers/azurerm/import_arm_container_registry_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package azurerm

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)

func TestAccAzureRMContainerRegistry_importBasic(t *testing.T) {
resourceName := "azurerm_container_registry.test"

ri := acctest.RandInt()
rs := acctest.RandString(4)
config := fmt.Sprintf(testAccAzureRMContainerRegistry_basic, ri, rs, ri)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMContainerRegistryDestroy,
Steps: []resource.TestStep{
{
Config: config,
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"storage_account"},
},
},
})
}

func TestAccAzureRMContainerRegistry_importComplete(t *testing.T) {
resourceName := "azurerm_container_registry.test"

ri := acctest.RandInt()
rs := acctest.RandString(4)
config := fmt.Sprintf(testAccAzureRMContainerRegistry_complete, ri, rs, ri)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testCheckAzureRMContainerRegistryDestroy,
Steps: []resource.TestStep{
{
Config: config,
},

{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"storage_account"},
},
},
})
}
8 changes: 5 additions & 3 deletions builtin/providers/azurerm/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ func Provider() terraform.ResourceProvider {

ResourcesMap: map[string]*schema.Resource{
// These resources use the Azure ARM SDK
"azurerm_availability_set": resourceArmAvailabilitySet(),
"azurerm_cdn_endpoint": resourceArmCdnEndpoint(),
"azurerm_cdn_profile": resourceArmCdnProfile(),
"azurerm_availability_set": resourceArmAvailabilitySet(),
"azurerm_cdn_endpoint": resourceArmCdnEndpoint(),
"azurerm_cdn_profile": resourceArmCdnProfile(),
"azurerm_container_registry": resourceArmContainerRegistry(),

"azurerm_eventhub": resourceArmEventHub(),
"azurerm_eventhub_consumer_group": resourceArmEventHubConsumerGroup(),
Expand Down Expand Up @@ -209,6 +210,7 @@ func registerAzureResourceProvidersWithSubscription(client *riviera.Client) erro
// We register Microsoft.Compute during client initialization
providers := []string{
"Microsoft.Cache",
"Microsoft.ContainerRegistry",
"Microsoft.Network",
"Microsoft.Cdn",
"Microsoft.Storage",
Expand Down
236 changes: 236 additions & 0 deletions builtin/providers/azurerm/resource_arm_container_registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
package azurerm

import (
"fmt"
"log"

"net/http"

"regexp"

"github.com/Azure/azure-sdk-for-go/arm/containerregistry"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
"github.com/jen20/riviera/azure"
)

func resourceArmContainerRegistry() *schema.Resource {
return &schema.Resource{
Create: resourceArmContainerRegistryCreate,
Read: resourceArmContainerRegistryRead,
Update: resourceArmContainerRegistryCreate,
Delete: resourceArmContainerRegistryDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateAzureRMContainerRegistryName,
},

"resource_group_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"location": locationSchema(),

"admin_enabled": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},

"storage_account": {
Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},

"access_key": {
Type: schema.TypeString,
Required: true,
Sensitive: true,
},
},
},
},

"login_server": {
Type: schema.TypeString,
Computed: true,
},

"admin_username": {
Type: schema.TypeString,
Computed: true,
},

"admin_password": {
Type: schema.TypeString,
Computed: true,
},

"tags": tagsSchema(),
},
}
}

func resourceArmContainerRegistryCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).containerRegistryClient
log.Printf("[INFO] preparing arguments for AzureRM Container Registry creation.")

resourceGroup := d.Get("resource_group_name").(string)
name := d.Get("name").(string)
location := d.Get("location").(string)

adminUserEnabled := d.Get("admin_enabled").(bool)
tags := d.Get("tags").(map[string]interface{})

parameters := containerregistry.Registry{
Location: &location,
RegistryProperties: &containerregistry.RegistryProperties{
AdminUserEnabled: &adminUserEnabled,
},
Tags: expandTags(tags),
}

accounts := d.Get("storage_account").(*schema.Set).List()
account := accounts[0].(map[string]interface{})
storageAccountName := account["name"].(string)
storageAccountAccessKey := account["access_key"].(string)
parameters.RegistryProperties.StorageAccount = &containerregistry.StorageAccountProperties{
Name: azure.String(storageAccountName),
AccessKey: azure.String(storageAccountAccessKey),
}

_, err := client.CreateOrUpdate(resourceGroup, name, parameters)
if err != nil {
return err
}

read, err := client.GetProperties(resourceGroup, name)
if err != nil {
return err
}

if read.ID == nil {
return fmt.Errorf("Cannot read Container Registry %s (resource group %s) ID", name, resourceGroup)
}

d.SetId(*read.ID)

return resourceArmContainerRegistryRead(d, meta)
}

func resourceArmContainerRegistryRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).containerRegistryClient

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
name := id.Path["registries"]

resp, err := client.GetProperties(resourceGroup, name)
if err != nil {
return fmt.Errorf("Error making Read request on Azure Container Registry %s: %s", name, err)
}
if resp.StatusCode == http.StatusNotFound {
d.SetId("")
return nil
}

d.Set("name", resp.Name)
d.Set("resource_group_name", resourceGroup)
d.Set("location", azureRMNormalizeLocation(*resp.Location))
d.Set("admin_enabled", resp.AdminUserEnabled)
d.Set("login_server", resp.LoginServer)

if resp.StorageAccount != nil {
flattenArmContainerRegistryStorageAccount(d, resp.StorageAccount)
}

if *resp.AdminUserEnabled {
credsResp, err := client.GetCredentials(resourceGroup, name)
if err != nil {
return fmt.Errorf("Error making Read request on Azure Container Registry %s for Credentials: %s", name, err)
}

d.Set("admin_username", credsResp.Username)
d.Set("admin_password", credsResp.Password)
} else {
d.Set("admin_username", "")
d.Set("admin_password", "")
}

flattenAndSetTags(d, resp.Tags)

return nil
}

func resourceArmContainerRegistryDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient).containerRegistryClient

id, err := parseAzureResourceID(d.Id())
if err != nil {
return err
}
resourceGroup := id.ResourceGroup
name := id.Path["registries"]

resp, err := client.Delete(resourceGroup, name)

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("Error issuing Azure ARM delete request of Container Registry '%s': %s", name, err)
}

return nil
}

func flattenArmContainerRegistryStorageAccount(d *schema.ResourceData, properties *containerregistry.StorageAccountProperties) {
storageAccounts := schema.Set{
F: resourceAzureRMContainerRegistryStorageAccountHash,
}

storageAccount := map[string]interface{}{}
storageAccount["name"] = properties.Name
storageAccounts.Add(storageAccount)

d.Set("storage_account", &storageAccounts)
}

func resourceAzureRMContainerRegistryStorageAccountHash(v interface{}) int {
m := v.(map[string]interface{})
name := m["name"].(*string)
return hashcode.String(*name)
}

func validateAzureRMContainerRegistryName(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"alpha numeric characters only are allowed in %q: %q", k, value))
}

if 5 > len(value) {
errors = append(errors, fmt.Errorf("%q cannot be less than 5 characters: %q", k, value))
}

if len(value) >= 50 {
errors = append(errors, fmt.Errorf("%q cannot be longer than 50 characters: %q %d", k, value, len(value)))
}

return
}
Loading

0 comments on commit 874ec8b

Please sign in to comment.