2015-12-09 02:25:05 +01:00
|
|
|
package azurerm
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ResourceID represents a parsed long-form Azure Resource Manager ID
|
|
|
|
// with the Subscription ID, Resource Group and the Provider as top-
|
|
|
|
// level fields, and other key-value pairs available via a map in the
|
|
|
|
// Path field.
|
|
|
|
type ResourceID struct {
|
|
|
|
SubscriptionID string
|
|
|
|
ResourceGroup string
|
|
|
|
Provider string
|
|
|
|
Path map[string]string
|
|
|
|
}
|
|
|
|
|
|
|
|
// parseAzureResourceID converts a long-form Azure Resource Manager ID
|
|
|
|
// into a ResourceID. We make assumptions about the structure of URLs,
|
|
|
|
// which is obviously not good, but the best thing available given the
|
|
|
|
// SDK.
|
|
|
|
func parseAzureResourceID(id string) (*ResourceID, error) {
|
|
|
|
idURL, err := url.ParseRequestURI(id)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Cannot parse Azure Id: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
path := idURL.Path
|
|
|
|
|
|
|
|
path = strings.TrimSpace(path)
|
|
|
|
if strings.HasPrefix(path, "/") {
|
|
|
|
path = path[1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasSuffix(path, "/") {
|
|
|
|
path = path[:len(path)-1]
|
|
|
|
}
|
|
|
|
|
|
|
|
components := strings.Split(path, "/")
|
|
|
|
|
|
|
|
// We should have an even number of key-value pairs.
|
|
|
|
if len(components)%2 != 0 {
|
|
|
|
return nil, fmt.Errorf("The number of path segments is not divisible by 2 in %q", path)
|
|
|
|
}
|
|
|
|
|
2016-10-01 18:47:19 +02:00
|
|
|
var subscriptionID string
|
|
|
|
|
2015-12-09 02:25:05 +01:00
|
|
|
// Put the constituent key-value pairs into a map
|
|
|
|
componentMap := make(map[string]string, len(components)/2)
|
|
|
|
for current := 0; current < len(components); current += 2 {
|
|
|
|
key := components[current]
|
|
|
|
value := components[current+1]
|
|
|
|
|
2016-10-01 18:47:19 +02:00
|
|
|
// Catch the subscriptionID before it can be overwritten by another "subscriptions"
|
|
|
|
// value in the ID which is the case for the Service Bus subscription resource
|
|
|
|
if key == "subscriptions" && subscriptionID == "" {
|
|
|
|
subscriptionID = value
|
|
|
|
} else {
|
|
|
|
componentMap[key] = value
|
|
|
|
}
|
2015-12-09 02:25:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build up a ResourceID from the map
|
|
|
|
idObj := &ResourceID{}
|
|
|
|
idObj.Path = componentMap
|
|
|
|
|
2016-10-01 18:47:19 +02:00
|
|
|
if subscriptionID != "" {
|
|
|
|
idObj.SubscriptionID = subscriptionID
|
2015-12-09 02:25:05 +01:00
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("No subscription ID found in: %q", path)
|
|
|
|
}
|
|
|
|
|
|
|
|
if resourceGroup, ok := componentMap["resourceGroups"]; ok {
|
|
|
|
idObj.ResourceGroup = resourceGroup
|
|
|
|
delete(componentMap, "resourceGroups")
|
|
|
|
} else {
|
2016-01-19 17:32:16 +01:00
|
|
|
// Some Azure APIs are weird and provide things in lower case...
|
|
|
|
// However it's not clear whether the casing of other elements in the URI
|
|
|
|
// matter, so we explicitly look for that case here.
|
|
|
|
if resourceGroup, ok := componentMap["resourcegroups"]; ok {
|
|
|
|
idObj.ResourceGroup = resourceGroup
|
|
|
|
delete(componentMap, "resourcegroups")
|
|
|
|
} else {
|
|
|
|
return nil, fmt.Errorf("No resource group name found in: %q", path)
|
|
|
|
}
|
2015-12-09 02:25:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// It is OK not to have a provider in the case of a resource group
|
|
|
|
if provider, ok := componentMap["providers"]; ok {
|
|
|
|
idObj.Provider = provider
|
|
|
|
delete(componentMap, "providers")
|
|
|
|
}
|
|
|
|
|
|
|
|
return idObj, nil
|
|
|
|
}
|