Merge pull request #5204 from hashicorp/f-riviera-resource-groups

provider/azurerm: Use Riviera for Resource Groups
This commit is contained in:
Paul Stack 2016-02-19 00:04:44 +00:00
commit 27d82a2397
6 changed files with 142 additions and 122 deletions

6
Godeps/Godeps.json generated
View File

@ -536,15 +536,15 @@
}, },
{ {
"ImportPath": "github.com/jen20/riviera/azure", "ImportPath": "github.com/jen20/riviera/azure",
"Rev": "5bae671a2903c37b4d580f24d9ab74ada633813f" "Rev": "31f4644de1f4931e43271240069bf2b896f47005"
}, },
{ {
"ImportPath": "github.com/jen20/riviera/dns", "ImportPath": "github.com/jen20/riviera/dns",
"Rev": "5bae671a2903c37b4d580f24d9ab74ada633813f" "Rev": "31f4644de1f4931e43271240069bf2b896f47005"
}, },
{ {
"ImportPath": "github.com/jen20/riviera/sql", "ImportPath": "github.com/jen20/riviera/sql",
"Rev": "5bae671a2903c37b4d580f24d9ab74ada633813f" "Rev": "31f4644de1f4931e43271240069bf2b896f47005"
}, },
{ {
"ImportPath": "github.com/jmespath/go-jmespath", "ImportPath": "github.com/jmespath/go-jmespath",

View File

@ -3,14 +3,11 @@ package azurerm
import ( import (
"fmt" "fmt"
"log" "log"
"net/http"
"regexp" "regexp"
"strings" "strings"
"time"
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/jen20/riviera/azure"
) )
func resourceArmResourceGroup() *schema.Resource { func resourceArmResourceGroup() *schema.Resource {
@ -60,20 +57,27 @@ func validateArmResourceGroupName(v interface{}, k string) (ws []string, es []er
func resourceArmResourceGroupUpdate(d *schema.ResourceData, meta interface{}) error { func resourceArmResourceGroupUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient) client := meta.(*ArmClient)
resGroupClient := client.resourceGroupClient rivieraClient := client.rivieraClient
if !d.HasChange("tags") { if !d.HasChange("tags") {
return nil return nil
} }
name := d.Get("name").(string) name := d.Get("name").(string)
newTags := d.Get("tags").(map[string]interface{}) newTags := d.Get("tags").(map[string]interface{})
_, err := resGroupClient.Patch(name, resources.ResourceGroup{
Tags: expandTags(newTags), updateRequest := rivieraClient.NewRequestForURI(d.Id())
}) updateRequest.Command = &azure.UpdateResourceGroup{
Name: name,
Tags: *expandTags(newTags),
}
updateResponse, err := updateRequest.Execute()
if err != nil { if err != nil {
return fmt.Errorf("Error issuing Azure ARM create request to update resource group %q: %s", name, err) return fmt.Errorf("Error updating resource group: %s", err)
}
if !updateResponse.IsSuccessful() {
return fmt.Errorf("Error updating resource group: %s", updateResponse.Error)
} }
return resourceArmResourceGroupRead(d, meta) return resourceArmResourceGroupRead(d, meta)
@ -81,110 +85,100 @@ func resourceArmResourceGroupUpdate(d *schema.ResourceData, meta interface{}) er
func resourceArmResourceGroupCreate(d *schema.ResourceData, meta interface{}) error { func resourceArmResourceGroupCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*ArmClient) client := meta.(*ArmClient)
resGroupClient := client.resourceGroupClient rivieraClient := client.rivieraClient
name := d.Get("name").(string) createRequest := rivieraClient.NewRequest()
location := d.Get("location").(string) createRequest.Command = &azure.CreateResourceGroup{
tags := d.Get("tags").(map[string]interface{}) Name: d.Get("name").(string),
Location: d.Get("location").(string),
rg := resources.ResourceGroup{ Tags: *expandTags(d.Get("tags").(map[string]interface{})),
Name: &name,
Location: &location,
Tags: expandTags(tags),
} }
resp, err := resGroupClient.CreateOrUpdate(name, rg) createResponse, err := createRequest.Execute()
if err != nil { if err != nil {
return fmt.Errorf("Error issuing Azure ARM create request for resource group '%s': %s", name, err) return fmt.Errorf("Error creating resource group: %s", err)
}
if !createResponse.IsSuccessful() {
return fmt.Errorf("Error creating resource group: %s", createResponse.Error)
} }
resp := createResponse.Parsed.(*azure.CreateResourceGroupResponse)
d.SetId(*resp.ID) d.SetId(*resp.ID)
log.Printf("[DEBUG] Waiting for Resource Group (%s) to become available", name) // TODO(jen20): Decide whether we need this or not and migrate to use @stack72's work if so
stateConf := &resource.StateChangeConf{ // log.Printf("[DEBUG] Waiting for Resource Group (%s) to become available", name)
Pending: []string{"Accepted"}, // stateConf := &resource.StateChangeConf{
Target: []string{"Succeeded"}, // Pending: []string{"Accepted"},
Refresh: resourceGroupStateRefreshFunc(client, name), // Target: []string{"Succeeded"},
Timeout: 10 * time.Minute, // Refresh: resourceGroupStateRefreshFunc(client, name),
} // Timeout: 10 * time.Minute,
if _, err := stateConf.WaitForState(); err != nil { // }
return fmt.Errorf("Error waiting for Resource Group (%s) to become available: %s", name, err) // if _, err := stateConf.WaitForState(); err != nil {
} // return fmt.Errorf("Error waiting for Resource Group (%s) to become available: %s", name, err)
// }
return resourceArmResourceGroupRead(d, meta) return resourceArmResourceGroupRead(d, meta)
} }
func resourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) error { func resourceArmResourceGroupRead(d *schema.ResourceData, meta interface{}) error {
resGroupClient := meta.(*ArmClient).resourceGroupClient client := meta.(*ArmClient)
rivieraClient := client.rivieraClient
id, err := parseAzureResourceID(d.Id()) readRequest := rivieraClient.NewRequestForURI(d.Id())
readRequest.Command = &azure.GetResourceGroup{}
readResponse, err := readRequest.Execute()
if err != nil { if err != nil {
return err return fmt.Errorf("Error reading resource group: %s", err)
} }
name := id.ResourceGroup if !readResponse.IsSuccessful() {
log.Printf("[INFO] Error reading resource group %q - removing from state", d.Id())
res, err := resGroupClient.Get(name)
if err != nil {
if res.StatusCode == http.StatusNotFound {
d.SetId("") d.SetId("")
return nil return fmt.Errorf("Error reading resource group: %s", readResponse.Error)
}
return fmt.Errorf("Error issuing read request to Azure ARM for resource group '%s': %s", name, err)
} }
d.Set("name", res.Name) resp := readResponse.Parsed.(*azure.GetResourceGroupResponse)
d.Set("location", res.Location)
flattenAndSetTags(d, res.Tags) d.Set("name", resp.Name)
d.Set("location", resp.Location)
flattenAndSetTags(d, resp.Tags)
return nil return nil
} }
func resourceArmResourceGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) { func resourceArmResourceGroupExists(d *schema.ResourceData, meta interface{}) (bool, error) {
resGroupClient := meta.(*ArmClient).resourceGroupClient client := meta.(*ArmClient)
rivieraClient := client.rivieraClient
id, err := parseAzureResourceID(d.Id()) readRequest := rivieraClient.NewRequestForURI(d.Id())
readRequest.Command = &azure.GetResourceGroup{}
readResponse, err := readRequest.Execute()
if err != nil { if err != nil {
return false, err return false, fmt.Errorf("Error reading resource group: %s", err)
} }
name := id.ResourceGroup if readResponse.IsSuccessful() {
resp, err := resGroupClient.CheckExistence(name)
if err != nil {
if resp.StatusCode != 200 {
return false, err
}
return true, nil return true, nil
} }
return true, nil return false, nil
} }
func resourceArmResourceGroupDelete(d *schema.ResourceData, meta interface{}) error { func resourceArmResourceGroupDelete(d *schema.ResourceData, meta interface{}) error {
resGroupClient := meta.(*ArmClient).resourceGroupClient client := meta.(*ArmClient)
rivieraClient := client.rivieraClient
id, err := parseAzureResourceID(d.Id()) deleteRequest := rivieraClient.NewRequestForURI(d.Id())
deleteRequest.Command = &azure.DeleteResourceGroup{}
deleteResponse, err := deleteRequest.Execute()
if err != nil { if err != nil {
return err return fmt.Errorf("Error deleting resource group: %s", err)
} }
name := id.ResourceGroup if !deleteResponse.IsSuccessful() {
return fmt.Errorf("Error deleting resource group: %s", deleteResponse.Error)
_, err = resGroupClient.Delete(name)
if err != nil {
return err
} }
return nil return nil
}
func resourceGroupStateRefreshFunc(client *ArmClient, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
res, err := client.resourceGroupClient.Get(id)
if err != nil {
return nil, "", fmt.Errorf("Error issuing read request in resourceGroupStateRefreshFunc to Azure ARM for resource group '%s': %s", id, err)
}
return res, *res.Properties.ProvisioningState, nil
}
} }

View File

@ -0,0 +1,24 @@
package azure
type GetResourceGroupResponse struct {
ID *string `mapstructure:"id"`
Name *string `mapstructure:"name"`
Location *string `mapstructure:"location"`
ProvisioningState *string `mapstructure:"provisioningState"`
Tags *map[string]*string `mapstructure:"tags"`
}
type GetResourceGroup struct {
Name string `json:"-"`
}
func (command GetResourceGroup) APIInfo() APIInfo {
return APIInfo{
APIVersion: resourceGroupAPIVersion,
Method: "GET",
URLPathFunc: resourceGroupDefaultURLFunc(command.Name),
ResponseTypeFunc: func() interface{} {
return &GetResourceGroupResponse{}
},
}
}

View File

@ -26,39 +26,24 @@ type Request struct {
client *Client client *Client
} }
func readLocation(req interface{}) (string, bool) { func readTaggedFields(command interface{}) map[string]interface{} {
var value reflect.Value var value reflect.Value
if reflect.ValueOf(req).Kind() == reflect.Ptr { if reflect.ValueOf(command).Kind() == reflect.Ptr {
value = reflect.ValueOf(req).Elem() value = reflect.ValueOf(command).Elem()
} else { } else {
value = reflect.ValueOf(req) value = reflect.ValueOf(command)
} }
result := make(map[string]interface{})
for i := 0; i < value.NumField(); i++ { // iterates through every struct type field for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
tag := value.Type().Field(i).Tag // returns the tag string tag := value.Type().Field(i).Tag // returns the tag string
if tag.Get("riviera") == "location" { tagValue := tag.Get("riviera")
return value.Field(i).String(), true if tagValue != "" {
result[tagValue] = value.Field(i).Interface()
} }
} }
return "", false return result
}
func readTags(req interface{}) (map[string]*string, bool) {
var value reflect.Value
if reflect.ValueOf(req).Kind() == reflect.Ptr {
value = reflect.ValueOf(req).Elem()
} else {
value = reflect.ValueOf(req)
}
for i := 0; i < value.NumField(); i++ { // iterates through every struct type field
tag := value.Type().Field(i).Tag // returns the tag string
if tag.Get("riviera") == "tags" {
tags := value.Field(i)
return tags.Interface().(map[string]*string), true
}
}
return make(map[string]*string), false
} }
func (request *Request) pollForAsynchronousResponse(acceptedResponse *http.Response) (*http.Response, error) { func (request *Request) pollForAsynchronousResponse(acceptedResponse *http.Response) (*http.Response, error) {
@ -108,24 +93,15 @@ func (request *Request) pollForAsynchronousResponse(acceptedResponse *http.Respo
} }
func defaultARMRequestStruct(request *Request, properties interface{}) interface{} { func defaultARMRequestStruct(request *Request, properties interface{}) interface{} {
bodyStruct := struct { body := make(map[string]interface{})
Location *string `json:"location,omitempty"`
Tags *map[string]*string `json:"tags,omitempty"` envelopeFields := readTaggedFields(properties)
Properties interface{} `json:"properties"` for k, v := range envelopeFields {
}{ body[k] = v
Properties: properties,
} }
if location, hasLocation := readLocation(request.Command); hasLocation { body["properties"] = properties
bodyStruct.Location = &location return body
}
if tags, hasTags := readTags(request.Command); hasTags {
if len(tags) > 0 {
bodyStruct.Tags = &tags
}
}
return bodyStruct
} }
func defaultARMRequestSerialize(body interface{}) (io.ReadSeeker, error) { func defaultARMRequestSerialize(body interface{}) (io.ReadSeeker, error) {
@ -162,6 +138,7 @@ func (request *Request) Execute() (*Response, error) {
} else { } else {
bodyStruct = defaultARMRequestStruct(request, request.Command) bodyStruct = defaultARMRequestStruct(request, request.Command)
} }
serialized, err := defaultARMRequestSerialize(bodyStruct) serialized, err := defaultARMRequestSerialize(bodyStruct)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -0,0 +1,25 @@
package azure
type UpdateResourceGroupResponse struct {
ID *string `mapstructure:"id"`
Name *string `mapstructure:"name"`
Location *string `mapstructure:"location"`
ProvisioningState *string `mapstructure:"provisioningState"`
Tags *map[string]*string `mapstructure:"tags"`
}
type UpdateResourceGroup struct {
Name string `json:"-"`
Tags map[string]*string `json:"-" riviera:"tags"`
}
func (command UpdateResourceGroup) APIInfo() APIInfo {
return APIInfo{
APIVersion: resourceGroupAPIVersion,
Method: "PATCH",
URLPathFunc: resourceGroupDefaultURLFunc(command.Name),
ResponseTypeFunc: func() interface{} {
return &UpdateResourceGroupResponse{}
},
}
}