github.com/danrjohnson/terraform@v0.7.0-rc2.0.20160627135212-d0fc1fa086ff/builtin/providers/azurerm/resourceid.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"strings"
     7  )
     8  
     9  // ResourceID represents a parsed long-form Azure Resource Manager ID
    10  // with the Subscription ID, Resource Group and the Provider as top-
    11  // level fields, and other key-value pairs available via a map in the
    12  // Path field.
    13  type ResourceID struct {
    14  	SubscriptionID string
    15  	ResourceGroup  string
    16  	Provider       string
    17  	Path           map[string]string
    18  }
    19  
    20  // parseAzureResourceID converts a long-form Azure Resource Manager ID
    21  // into a ResourceID. We make assumptions about the structure of URLs,
    22  // which is obviously not good, but the best thing available given the
    23  // SDK.
    24  func parseAzureResourceID(id string) (*ResourceID, error) {
    25  	idURL, err := url.ParseRequestURI(id)
    26  	if err != nil {
    27  		return nil, fmt.Errorf("Cannot parse Azure Id: %s", err)
    28  	}
    29  
    30  	path := idURL.Path
    31  
    32  	path = strings.TrimSpace(path)
    33  	if strings.HasPrefix(path, "/") {
    34  		path = path[1:]
    35  	}
    36  
    37  	if strings.HasSuffix(path, "/") {
    38  		path = path[:len(path)-1]
    39  	}
    40  
    41  	components := strings.Split(path, "/")
    42  
    43  	// We should have an even number of key-value pairs.
    44  	if len(components)%2 != 0 {
    45  		return nil, fmt.Errorf("The number of path segments is not divisible by 2 in %q", path)
    46  	}
    47  
    48  	// Put the constituent key-value pairs into a map
    49  	componentMap := make(map[string]string, len(components)/2)
    50  	for current := 0; current < len(components); current += 2 {
    51  		key := components[current]
    52  		value := components[current+1]
    53  
    54  		componentMap[key] = value
    55  	}
    56  
    57  	// Build up a ResourceID from the map
    58  	idObj := &ResourceID{}
    59  	idObj.Path = componentMap
    60  
    61  	if subscription, ok := componentMap["subscriptions"]; ok {
    62  		idObj.SubscriptionID = subscription
    63  		delete(componentMap, "subscriptions")
    64  	} else {
    65  		return nil, fmt.Errorf("No subscription ID found in: %q", path)
    66  	}
    67  
    68  	if resourceGroup, ok := componentMap["resourceGroups"]; ok {
    69  		idObj.ResourceGroup = resourceGroup
    70  		delete(componentMap, "resourceGroups")
    71  	} else {
    72  		// Some Azure APIs are weird and provide things in lower case...
    73  		// However it's not clear whether the casing of other elements in the URI
    74  		// matter, so we explicitly look for that case here.
    75  		if resourceGroup, ok := componentMap["resourcegroups"]; ok {
    76  			idObj.ResourceGroup = resourceGroup
    77  			delete(componentMap, "resourcegroups")
    78  		} else {
    79  			return nil, fmt.Errorf("No resource group name found in: %q", path)
    80  		}
    81  	}
    82  
    83  	// It is OK not to have a provider in the case of a resource group
    84  	if provider, ok := componentMap["providers"]; ok {
    85  		idObj.Provider = provider
    86  		delete(componentMap, "providers")
    87  	}
    88  
    89  	return idObj, nil
    90  }