From f374ca77e7d2615710686f52e9ef3e90a7b0cad0 Mon Sep 17 00:00:00 2001 From: James Nugent Date: Mon, 18 Jan 2016 11:32:39 -0500 Subject: [PATCH 1/2] provider/azurerm: Add scaffolding to tags --- builtin/providers/azurerm/config.go | 6 +- .../azurerm/resource_arm_availability_set.go | 16 ++-- builtin/providers/azurerm/tags.go | 76 +++++++++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 builtin/providers/azurerm/tags.go diff --git a/builtin/providers/azurerm/config.go b/builtin/providers/azurerm/config.go index 43655b6cf..e25cd96fe 100644 --- a/builtin/providers/azurerm/config.go +++ b/builtin/providers/azurerm/config.go @@ -56,7 +56,11 @@ func withRequestLogging() autorest.SendDecorator { return autorest.SenderFunc(func(r *http.Request) (*http.Response, error) { log.Printf("[DEBUG] Sending Azure RM Request %s to %s\n", r.Method, r.URL) resp, err := s.Do(r) - log.Printf("[DEBUG] Received Azure RM Request status code %s for %s\n", resp.Status, r.URL) + if resp != nil { + log.Printf("[DEBUG] Received Azure RM Request status code %s for %s\n", resp.Status, r.URL) + } else { + log.Printf("[DEBUG] Request to %s completed with no response", r.URL) + } return resp, err }) } diff --git a/builtin/providers/azurerm/resource_arm_availability_set.go b/builtin/providers/azurerm/resource_arm_availability_set.go index 3eb7c8506..74efc886d 100644 --- a/builtin/providers/azurerm/resource_arm_availability_set.go +++ b/builtin/providers/azurerm/resource_arm_availability_set.go @@ -23,6 +23,12 @@ func resourceArmAvailabilitySet() *schema.Resource { ForceNew: true, }, + "resource_group_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "location": &schema.Schema{ Type: schema.TypeString, Required: true, @@ -58,11 +64,7 @@ func resourceArmAvailabilitySet() *schema.Resource { }, }, - "resource_group_name": &schema.Schema{ - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, + "tags": tagsSchema(), }, } } @@ -78,6 +80,7 @@ func resourceArmAvailabilitySetCreate(d *schema.ResourceData, meta interface{}) resGroup := d.Get("resource_group_name").(string) updateDomainCount := d.Get("platform_update_domain_count").(int) faultDomainCount := d.Get("platform_fault_domain_count").(int) + tags := d.Get("tags").(map[string]interface{}) availSet := compute.AvailabilitySet{ Name: &name, @@ -86,6 +89,7 @@ func resourceArmAvailabilitySetCreate(d *schema.ResourceData, meta interface{}) PlatformFaultDomainCount: &faultDomainCount, PlatformUpdateDomainCount: &updateDomainCount, }, + Tags: expandTags(tags), } resp, err := availSetClient.CreateOrUpdate(resGroup, name, availSet) @@ -121,6 +125,8 @@ func resourceArmAvailabilitySetRead(d *schema.ResourceData, meta interface{}) er d.Set("platform_update_domain_count", availSet.PlatformUpdateDomainCount) d.Set("platform_fault_domain_count", availSet.PlatformFaultDomainCount) + flattenAndSetTags(d, resp.Tags) + return nil } diff --git a/builtin/providers/azurerm/tags.go b/builtin/providers/azurerm/tags.go new file mode 100644 index 000000000..60255a323 --- /dev/null +++ b/builtin/providers/azurerm/tags.go @@ -0,0 +1,76 @@ +package azurerm + +import ( + "errors" + "fmt" + + "github.com/hashicorp/terraform/helper/schema" +) + +func tagsSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeMap, + Optional: true, + ValidateFunc: validateAzureRMTags, + } +} + +func tagValueToString(v interface{}) (string, error) { + switch value := v.(type) { + case string: + return value, nil + case int: + return fmt.Sprintf("%d", value), nil + default: + return "", fmt.Errorf("unknown tag type %T in tag value", value) + } +} + +func validateAzureRMTags(v interface{}, k string) (ws []string, es []error) { + tagsMap := v.(map[string]interface{}) + + if len(tagsMap) > 15 { + es = append(es, errors.New("a maximum of 15 tags can be applied to each ARM resource")) + } + + for k, v := range tagsMap { + if len(k) > 512 { + es = append(es, fmt.Errorf("the maximum length for a tag key is 512 characters: %q is %d characters", k, len(k))) + } + + value, err := tagValueToString(v) + if err != nil { + es = append(es, err) + } else if len(value) > 256 { + es = append(es, fmt.Errorf("the maximum length for a tag value is 256 characters: the value for %q is %d characters", k, len(value))) + } + } + + return +} + +func expandTags(tagsMap map[string]interface{}) *map[string]*string { + output := make(map[string]*string, len(tagsMap)) + + for i, v := range tagsMap { + //Validate should have ignored this error already + value, _ := tagValueToString(v) + output[i] = &value + } + + return &output +} + +func flattenAndSetTags(d *schema.ResourceData, tagsMap *map[string]*string) { + if tagsMap == nil { + return + } + + output := make(map[string]interface{}, len(*tagsMap)) + + for i, v := range *tagsMap { + output[i] = *v + } + + d.Set("tags", output) +} From a640ef9f1661c49aa56b651029b34d73dbc028a4 Mon Sep 17 00:00:00 2001 From: James Nugent Date: Mon, 18 Jan 2016 12:28:04 -0500 Subject: [PATCH 2/2] provider/azurerm: Add tests for tag scaffolding --- builtin/providers/azurerm/tags_test.go | 97 ++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 builtin/providers/azurerm/tags_test.go diff --git a/builtin/providers/azurerm/tags_test.go b/builtin/providers/azurerm/tags_test.go new file mode 100644 index 000000000..fb75c04f0 --- /dev/null +++ b/builtin/providers/azurerm/tags_test.go @@ -0,0 +1,97 @@ +package azurerm + +import ( + "fmt" + "strings" + "testing" +) + +func TestValidateMaximumNumberOfARMTags(t *testing.T) { + tagsMap := make(map[string]interface{}) + for i := 0; i < 16; i++ { + tagsMap[fmt.Sprintf("key%d", i)] = fmt.Sprintf("value%d", i) + } + + _, es := validateAzureRMTags(tagsMap, "tags") + + if len(es) != 1 { + t.Fatal("Expected one validation error for too many tags") + } + + if !strings.Contains(es[0].Error(), "a maximum of 15 tags") { + t.Fatal("Wrong validation error message for too many tags") + } +} + +func TestValidateARMTagMaxKeyLength(t *testing.T) { + tooLongKey := strings.Repeat("long", 128) + "a" + tagsMap := make(map[string]interface{}) + tagsMap[tooLongKey] = "value" + + _, es := validateAzureRMTags(tagsMap, "tags") + if len(es) != 1 { + t.Fatal("Expected one validation error for a key which is > 512 chars") + } + + if !strings.Contains(es[0].Error(), "maximum length for a tag key") { + t.Fatal("Wrong validation error message maximum tag key length") + } + + if !strings.Contains(es[0].Error(), tooLongKey) { + t.Fatal("Expected validated error to contain the key name") + } + + if !strings.Contains(es[0].Error(), "513") { + t.Fatal("Expected the length in the validation error for tag key") + } +} + +func TestValidateARMTagMaxValueLength(t *testing.T) { + tagsMap := make(map[string]interface{}) + tagsMap["toolong"] = strings.Repeat("long", 64) + "a" + + _, es := validateAzureRMTags(tagsMap, "tags") + if len(es) != 1 { + t.Fatal("Expected one validation error for a value which is > 256 chars") + } + + if !strings.Contains(es[0].Error(), "maximum length for a tag value") { + t.Fatal("Wrong validation error message for maximum tag value length") + } + + if !strings.Contains(es[0].Error(), "toolong") { + t.Fatal("Expected validated error to contain the key name") + } + + if !strings.Contains(es[0].Error(), "257") { + t.Fatal("Expected the length in the validation error for value") + } +} + +func TestExpandARMTags(t *testing.T) { + testData := make(map[string]interface{}) + testData["key1"] = "value1" + testData["key2"] = 21 + testData["key3"] = "value3" + + tempExpanded := expandTags(testData) + expanded := *tempExpanded + + if len(expanded) != 3 { + t.Fatalf("Expected 3 results in expanded tag map, got %d", len(expanded)) + } + + for k, v := range testData { + var strVal string + switch v.(type) { + case string: + strVal = v.(string) + case int: + strVal = fmt.Sprintf("%d", v.(int)) + } + + if *expanded[k] != strVal { + t.Fatalf("Expanded value %q incorrect: expected %q, got %q", k, strVal, expanded[k]) + } + } +}