github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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  	var subscriptionID string
    49  
    50  	// Put the constituent key-value pairs into a map
    51  	componentMap := make(map[string]string, len(components)/2)
    52  	for current := 0; current < len(components); current += 2 {
    53  		key := components[current]
    54  		value := components[current+1]
    55  
    56  		// Catch the subscriptionID before it can be overwritten by another "subscriptions"
    57  		// value in the ID which is the case for the Service Bus subscription resource
    58  		if key == "subscriptions" && subscriptionID == "" {
    59  			subscriptionID = value
    60  		} else {
    61  			componentMap[key] = value
    62  		}
    63  	}
    64  
    65  	// Build up a ResourceID from the map
    66  	idObj := &ResourceID{}
    67  	idObj.Path = componentMap
    68  
    69  	if subscriptionID != "" {
    70  		idObj.SubscriptionID = subscriptionID
    71  	} else {
    72  		return nil, fmt.Errorf("No subscription ID found in: %q", path)
    73  	}
    74  
    75  	if resourceGroup, ok := componentMap["resourceGroups"]; ok {
    76  		idObj.ResourceGroup = resourceGroup
    77  		delete(componentMap, "resourceGroups")
    78  	} else {
    79  		// Some Azure APIs are weird and provide things in lower case...
    80  		// However it's not clear whether the casing of other elements in the URI
    81  		// matter, so we explicitly look for that case here.
    82  		if resourceGroup, ok := componentMap["resourcegroups"]; ok {
    83  			idObj.ResourceGroup = resourceGroup
    84  			delete(componentMap, "resourcegroups")
    85  		} else {
    86  			return nil, fmt.Errorf("No resource group name found in: %q", path)
    87  		}
    88  	}
    89  
    90  	// It is OK not to have a provider in the case of a resource group
    91  	if provider, ok := componentMap["providers"]; ok {
    92  		idObj.Provider = provider
    93  		delete(componentMap, "providers")
    94  	}
    95  
    96  	return idObj, nil
    97  }