github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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  		// Check key/value for empty strings.
    57  		if key == "" || value == "" {
    58  			return nil, fmt.Errorf("Key/Value cannot be empty strings. Key: '%s', Value: '%s'", key, value)
    59  		}
    60  
    61  		// Catch the subscriptionID before it can be overwritten by another "subscriptions"
    62  		// value in the ID which is the case for the Service Bus subscription resource
    63  		if key == "subscriptions" && subscriptionID == "" {
    64  			subscriptionID = value
    65  		} else {
    66  			componentMap[key] = value
    67  		}
    68  	}
    69  
    70  	// Build up a ResourceID from the map
    71  	idObj := &ResourceID{}
    72  	idObj.Path = componentMap
    73  
    74  	if subscriptionID != "" {
    75  		idObj.SubscriptionID = subscriptionID
    76  	} else {
    77  		return nil, fmt.Errorf("No subscription ID found in: %q", path)
    78  	}
    79  
    80  	if resourceGroup, ok := componentMap["resourceGroups"]; ok {
    81  		idObj.ResourceGroup = resourceGroup
    82  		delete(componentMap, "resourceGroups")
    83  	} else {
    84  		// Some Azure APIs are weird and provide things in lower case...
    85  		// However it's not clear whether the casing of other elements in the URI
    86  		// matter, so we explicitly look for that case here.
    87  		if resourceGroup, ok := componentMap["resourcegroups"]; ok {
    88  			idObj.ResourceGroup = resourceGroup
    89  			delete(componentMap, "resourcegroups")
    90  		} else {
    91  			return nil, fmt.Errorf("No resource group name found in: %q", path)
    92  		}
    93  	}
    94  
    95  	// It is OK not to have a provider in the case of a resource group
    96  	if provider, ok := componentMap["providers"]; ok {
    97  		idObj.Provider = provider
    98  		delete(componentMap, "providers")
    99  	}
   100  
   101  	return idObj, nil
   102  }
   103  
   104  func parseNetworkSecurityGroupName(networkSecurityGroupId string) (string, error) {
   105  	id, err := parseAzureResourceID(networkSecurityGroupId)
   106  	if err != nil {
   107  		return "", fmt.Errorf("[ERROR] Unable to Parse Network Security Group ID '%s': %+v", networkSecurityGroupId, err)
   108  	}
   109  
   110  	return id.Path["networkSecurityGroups"], nil
   111  }
   112  
   113  func parseRouteTableName(routeTableId string) (string, error) {
   114  	id, err := parseAzureResourceID(routeTableId)
   115  	if err != nil {
   116  		return "", fmt.Errorf("[ERROR] Unable to parse Route Table ID '%s': %+v", routeTableId, err)
   117  	}
   118  
   119  	return id.Path["routeTables"], nil
   120  }