Skip to content

Commit 874ec8b

Browse files
tombuildsstuffstack72
authored andcommitted
provider/azurerm: Container Registry (hashicorp#10973)
* 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
1 parent de414ee commit 874ec8b

13 files changed

Lines changed: 1538 additions & 8 deletions

File tree

builtin/providers/azurerm/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/Azure/azure-sdk-for-go/arm/cdn"
1111
"github.com/Azure/azure-sdk-for-go/arm/compute"
12+
"github.com/Azure/azure-sdk-for-go/arm/containerregistry"
1213
"github.com/Azure/azure-sdk-for-go/arm/eventhub"
1314
"github.com/Azure/azure-sdk-for-go/arm/keyvault"
1415
"github.com/Azure/azure-sdk-for-go/arm/network"
@@ -63,6 +64,8 @@ type ArmClient struct {
6364
cdnProfilesClient cdn.ProfilesClient
6465
cdnEndpointsClient cdn.EndpointsClient
6566

67+
containerRegistryClient containerregistry.RegistriesClient
68+
6669
eventHubClient eventhub.EventHubsClient
6770
eventHubConsumerGroupClient eventhub.ConsumerGroupsClient
6871
eventHubNamespacesClient eventhub.NamespacesClient
@@ -221,6 +224,12 @@ func (c *Config) getArmClient() (*ArmClient, error) {
221224
agc.Sender = autorest.CreateSender(withRequestLogging())
222225
client.appGatewayClient = agc
223226

227+
crc := containerregistry.NewRegistriesClient(c.SubscriptionID)
228+
setUserAgent(&crc.Client)
229+
crc.Authorizer = spt
230+
crc.Sender = autorest.CreateSender(withRequestLogging())
231+
client.containerRegistryClient = crc
232+
224233
ehc := eventhub.NewEventHubsClient(c.SubscriptionID)
225234
setUserAgent(&ehc.Client)
226235
ehc.Authorizer = spt
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package azurerm
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform/helper/acctest"
8+
"github.com/hashicorp/terraform/helper/resource"
9+
)
10+
11+
func TestAccAzureRMContainerRegistry_importBasic(t *testing.T) {
12+
resourceName := "azurerm_container_registry.test"
13+
14+
ri := acctest.RandInt()
15+
rs := acctest.RandString(4)
16+
config := fmt.Sprintf(testAccAzureRMContainerRegistry_basic, ri, rs, ri)
17+
18+
resource.Test(t, resource.TestCase{
19+
PreCheck: func() { testAccPreCheck(t) },
20+
Providers: testAccProviders,
21+
CheckDestroy: testCheckAzureRMContainerRegistryDestroy,
22+
Steps: []resource.TestStep{
23+
{
24+
Config: config,
25+
},
26+
27+
{
28+
ResourceName: resourceName,
29+
ImportState: true,
30+
ImportStateVerify: true,
31+
ImportStateVerifyIgnore: []string{"storage_account"},
32+
},
33+
},
34+
})
35+
}
36+
37+
func TestAccAzureRMContainerRegistry_importComplete(t *testing.T) {
38+
resourceName := "azurerm_container_registry.test"
39+
40+
ri := acctest.RandInt()
41+
rs := acctest.RandString(4)
42+
config := fmt.Sprintf(testAccAzureRMContainerRegistry_complete, ri, rs, ri)
43+
44+
resource.Test(t, resource.TestCase{
45+
PreCheck: func() { testAccPreCheck(t) },
46+
Providers: testAccProviders,
47+
CheckDestroy: testCheckAzureRMContainerRegistryDestroy,
48+
Steps: []resource.TestStep{
49+
{
50+
Config: config,
51+
},
52+
53+
{
54+
ResourceName: resourceName,
55+
ImportState: true,
56+
ImportStateVerify: true,
57+
ImportStateVerifyIgnore: []string{"storage_account"},
58+
},
59+
},
60+
})
61+
}

builtin/providers/azurerm/provider.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ func Provider() terraform.ResourceProvider {
5151

5252
ResourcesMap: map[string]*schema.Resource{
5353
// These resources use the Azure ARM SDK
54-
"azurerm_availability_set": resourceArmAvailabilitySet(),
55-
"azurerm_cdn_endpoint": resourceArmCdnEndpoint(),
56-
"azurerm_cdn_profile": resourceArmCdnProfile(),
54+
"azurerm_availability_set": resourceArmAvailabilitySet(),
55+
"azurerm_cdn_endpoint": resourceArmCdnEndpoint(),
56+
"azurerm_cdn_profile": resourceArmCdnProfile(),
57+
"azurerm_container_registry": resourceArmContainerRegistry(),
5758

5859
"azurerm_eventhub": resourceArmEventHub(),
5960
"azurerm_eventhub_consumer_group": resourceArmEventHubConsumerGroup(),
@@ -209,6 +210,7 @@ func registerAzureResourceProvidersWithSubscription(client *riviera.Client) erro
209210
// We register Microsoft.Compute during client initialization
210211
providers := []string{
211212
"Microsoft.Cache",
213+
"Microsoft.ContainerRegistry",
212214
"Microsoft.Network",
213215
"Microsoft.Cdn",
214216
"Microsoft.Storage",
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package azurerm
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"net/http"
8+
9+
"regexp"
10+
11+
"github.com/Azure/azure-sdk-for-go/arm/containerregistry"
12+
"github.com/hashicorp/terraform/helper/hashcode"
13+
"github.com/hashicorp/terraform/helper/schema"
14+
"github.com/jen20/riviera/azure"
15+
)
16+
17+
func resourceArmContainerRegistry() *schema.Resource {
18+
return &schema.Resource{
19+
Create: resourceArmContainerRegistryCreate,
20+
Read: resourceArmContainerRegistryRead,
21+
Update: resourceArmContainerRegistryCreate,
22+
Delete: resourceArmContainerRegistryDelete,
23+
Importer: &schema.ResourceImporter{
24+
State: schema.ImportStatePassthrough,
25+
},
26+
27+
Schema: map[string]*schema.Schema{
28+
"name": {
29+
Type: schema.TypeString,
30+
Required: true,
31+
ForceNew: true,
32+
ValidateFunc: validateAzureRMContainerRegistryName,
33+
},
34+
35+
"resource_group_name": {
36+
Type: schema.TypeString,
37+
Required: true,
38+
ForceNew: true,
39+
},
40+
41+
"location": locationSchema(),
42+
43+
"admin_enabled": {
44+
Type: schema.TypeBool,
45+
Optional: true,
46+
Default: false,
47+
},
48+
49+
"storage_account": {
50+
Type: schema.TypeSet,
51+
Required: true,
52+
MaxItems: 1,
53+
Elem: &schema.Resource{
54+
Schema: map[string]*schema.Schema{
55+
"name": {
56+
Type: schema.TypeString,
57+
Required: true,
58+
},
59+
60+
"access_key": {
61+
Type: schema.TypeString,
62+
Required: true,
63+
Sensitive: true,
64+
},
65+
},
66+
},
67+
},
68+
69+
"login_server": {
70+
Type: schema.TypeString,
71+
Computed: true,
72+
},
73+
74+
"admin_username": {
75+
Type: schema.TypeString,
76+
Computed: true,
77+
},
78+
79+
"admin_password": {
80+
Type: schema.TypeString,
81+
Computed: true,
82+
},
83+
84+
"tags": tagsSchema(),
85+
},
86+
}
87+
}
88+
89+
func resourceArmContainerRegistryCreate(d *schema.ResourceData, meta interface{}) error {
90+
client := meta.(*ArmClient).containerRegistryClient
91+
log.Printf("[INFO] preparing arguments for AzureRM Container Registry creation.")
92+
93+
resourceGroup := d.Get("resource_group_name").(string)
94+
name := d.Get("name").(string)
95+
location := d.Get("location").(string)
96+
97+
adminUserEnabled := d.Get("admin_enabled").(bool)
98+
tags := d.Get("tags").(map[string]interface{})
99+
100+
parameters := containerregistry.Registry{
101+
Location: &location,
102+
RegistryProperties: &containerregistry.RegistryProperties{
103+
AdminUserEnabled: &adminUserEnabled,
104+
},
105+
Tags: expandTags(tags),
106+
}
107+
108+
accounts := d.Get("storage_account").(*schema.Set).List()
109+
account := accounts[0].(map[string]interface{})
110+
storageAccountName := account["name"].(string)
111+
storageAccountAccessKey := account["access_key"].(string)
112+
parameters.RegistryProperties.StorageAccount = &containerregistry.StorageAccountProperties{
113+
Name: azure.String(storageAccountName),
114+
AccessKey: azure.String(storageAccountAccessKey),
115+
}
116+
117+
_, err := client.CreateOrUpdate(resourceGroup, name, parameters)
118+
if err != nil {
119+
return err
120+
}
121+
122+
read, err := client.GetProperties(resourceGroup, name)
123+
if err != nil {
124+
return err
125+
}
126+
127+
if read.ID == nil {
128+
return fmt.Errorf("Cannot read Container Registry %s (resource group %s) ID", name, resourceGroup)
129+
}
130+
131+
d.SetId(*read.ID)
132+
133+
return resourceArmContainerRegistryRead(d, meta)
134+
}
135+
136+
func resourceArmContainerRegistryRead(d *schema.ResourceData, meta interface{}) error {
137+
client := meta.(*ArmClient).containerRegistryClient
138+
139+
id, err := parseAzureResourceID(d.Id())
140+
if err != nil {
141+
return err
142+
}
143+
resourceGroup := id.ResourceGroup
144+
name := id.Path["registries"]
145+
146+
resp, err := client.GetProperties(resourceGroup, name)
147+
if err != nil {
148+
return fmt.Errorf("Error making Read request on Azure Container Registry %s: %s", name, err)
149+
}
150+
if resp.StatusCode == http.StatusNotFound {
151+
d.SetId("")
152+
return nil
153+
}
154+
155+
d.Set("name", resp.Name)
156+
d.Set("resource_group_name", resourceGroup)
157+
d.Set("location", azureRMNormalizeLocation(*resp.Location))
158+
d.Set("admin_enabled", resp.AdminUserEnabled)
159+
d.Set("login_server", resp.LoginServer)
160+
161+
if resp.StorageAccount != nil {
162+
flattenArmContainerRegistryStorageAccount(d, resp.StorageAccount)
163+
}
164+
165+
if *resp.AdminUserEnabled {
166+
credsResp, err := client.GetCredentials(resourceGroup, name)
167+
if err != nil {
168+
return fmt.Errorf("Error making Read request on Azure Container Registry %s for Credentials: %s", name, err)
169+
}
170+
171+
d.Set("admin_username", credsResp.Username)
172+
d.Set("admin_password", credsResp.Password)
173+
} else {
174+
d.Set("admin_username", "")
175+
d.Set("admin_password", "")
176+
}
177+
178+
flattenAndSetTags(d, resp.Tags)
179+
180+
return nil
181+
}
182+
183+
func resourceArmContainerRegistryDelete(d *schema.ResourceData, meta interface{}) error {
184+
client := meta.(*ArmClient).containerRegistryClient
185+
186+
id, err := parseAzureResourceID(d.Id())
187+
if err != nil {
188+
return err
189+
}
190+
resourceGroup := id.ResourceGroup
191+
name := id.Path["registries"]
192+
193+
resp, err := client.Delete(resourceGroup, name)
194+
195+
if resp.StatusCode != http.StatusOK {
196+
return fmt.Errorf("Error issuing Azure ARM delete request of Container Registry '%s': %s", name, err)
197+
}
198+
199+
return nil
200+
}
201+
202+
func flattenArmContainerRegistryStorageAccount(d *schema.ResourceData, properties *containerregistry.StorageAccountProperties) {
203+
storageAccounts := schema.Set{
204+
F: resourceAzureRMContainerRegistryStorageAccountHash,
205+
}
206+
207+
storageAccount := map[string]interface{}{}
208+
storageAccount["name"] = properties.Name
209+
storageAccounts.Add(storageAccount)
210+
211+
d.Set("storage_account", &storageAccounts)
212+
}
213+
214+
func resourceAzureRMContainerRegistryStorageAccountHash(v interface{}) int {
215+
m := v.(map[string]interface{})
216+
name := m["name"].(*string)
217+
return hashcode.String(*name)
218+
}
219+
220+
func validateAzureRMContainerRegistryName(v interface{}, k string) (ws []string, errors []error) {
221+
value := v.(string)
222+
if !regexp.MustCompile(`^[a-zA-Z0-9]+$`).MatchString(value) {
223+
errors = append(errors, fmt.Errorf(
224+
"alpha numeric characters only are allowed in %q: %q", k, value))
225+
}
226+
227+
if 5 > len(value) {
228+
errors = append(errors, fmt.Errorf("%q cannot be less than 5 characters: %q", k, value))
229+
}
230+
231+
if len(value) >= 50 {
232+
errors = append(errors, fmt.Errorf("%q cannot be longer than 50 characters: %q %d", k, value, len(value)))
233+
}
234+
235+
return
236+
}

0 commit comments

Comments
 (0)