At this point in time the Resource ID structs which implement resourceids.ResourceID
implement two top-level Parse functions:
ParseXXXID(input string) (*XXXID, error)
ParseXXXIDInsensitively(input string) (*XXXID, error)
Whilst this works great (and is something we want to continue using), both #188 and #189 have use-cases which need to be able to parse a given Resource ID with only access to the type - and as such are unable to take advantage of these Parse functions.
Instead we can support both of these - and reduce the TLOC by introducing a new method to the ResourceID
interface:
FromParseResult(input resourceids.ParseResult) error
Which contains the assignment logic that today exists both inside the ParseXXX
and ParseXXXInsensitively
functions:
func (id *AvailabilitySetId) FromParseResult(input resourceids.ParseResult) error {
var ok bool
if id.SubscriptionId, ok = input.Parsed["subscriptionId"]; !ok {
return resourceids.NewSegmentNotSpecifiedError(id, "subscriptionId", input)
}
if id.ResourceGroupName, ok = input.Parsed["resourceGroupName"]; !ok {
return resourceids.NewSegmentNotSpecifiedError(id, "resourceGroupName", input)
}
if id.AvailabilitySetName, ok = input.Parsed["availabilitySetName"]; !ok {
return resourceids.NewSegmentNotSpecifiedError(id, "availabilitySetName", input)
}
return nil
}
This means that both of the Parse
functions can be updated to call this new FromParseResult
function, meaning that we can update each Resource ID from:
// ParseAvailabilitySetID parses 'input' into a AvailabilitySetId
func ParseAvailabilitySetID(input string) (*AvailabilitySetId, error) {
parser := resourceids.NewParserFromResourceIdType(AvailabilitySetId{})
parsed, err := parser.Parse(input, false)
if err != nil {
return nil, fmt.Errorf("parsing %q: %+v", input, err)
}
var ok bool
id := AvailabilitySetId{}
if id.SubscriptionId, ok = parsed.Parsed["subscriptionId"]; !ok {
return nil, resourceids.NewSegmentNotSpecifiedError(id, "subscriptionId", *parsed)
}
if id.ResourceGroupName, ok = parsed.Parsed["resourceGroupName"]; !ok {
return nil, resourceids.NewSegmentNotSpecifiedError(id, "resourceGroupName", *parsed)
}
if id.AvailabilitySetName, ok = parsed.Parsed["availabilitySetName"]; !ok {
return nil, resourceids.NewSegmentNotSpecifiedError(id, "availabilitySetName", *parsed)
}
return &id, nil
}
// ParseAvailabilitySetIDInsensitively parses 'input' case-insensitively into a AvailabilitySetId
// note: this method should only be used for API response data and not user input
func ParseAvailabilitySetIDInsensitively(input string) (*AvailabilitySetId, error) {
parser := resourceids.NewParserFromResourceIdType(AvailabilitySetId{})
parsed, err := parser.Parse(input, true)
if err != nil {
return nil, fmt.Errorf("parsing %q: %+v", input, err)
}
var ok bool
id := AvailabilitySetId{}
if id.SubscriptionId, ok = parsed.Parsed["subscriptionId"]; !ok {
return nil, resourceids.NewSegmentNotSpecifiedError(id, "subscriptionId", *parsed)
}
if id.ResourceGroupName, ok = parsed.Parsed["resourceGroupName"]; !ok {
return nil, resourceids.NewSegmentNotSpecifiedError(id, "resourceGroupName", *parsed)
}
if id.AvailabilitySetName, ok = parsed.Parsed["availabilitySetName"]; !ok {
return nil, resourceids.NewSegmentNotSpecifiedError(id, "availabilitySetName", *parsed)
}
return &id, nil
}
to:
// ParseAvailabilitySetID parses 'input' into a AvailabilitySetId
func ParseAvailabilitySetID(input string) (*AvailabilitySetId, error) {
parser := resourceids.NewParserFromResourceIdType(&AvailabilitySetId{})
parsed, err := parser.Parse(input, false)
if err != nil {
return nil, fmt.Errorf("parsing %q: %+v", input, err)
}
id := &AvailabilitySetId{}
if err := id.FromParseResult(*parsed); err != nil {
return nil, err
}
return id, nil
}
// ParseAvailabilitySetIDInsensitively parses 'input' case-insensitively into a AvailabilitySetId
// note: this method should only be used for API response data and not user input
func ParseAvailabilitySetIDInsensitively(input string) (*AvailabilitySetId, error) {
parser := resourceids.NewParserFromResourceIdType(&AvailabilitySetId{})
parsed, err := parser.Parse(input, true)
if err != nil {
return nil, fmt.Errorf("parsing %q: %+v", input, err)
}
id := &AvailabilitySetId{}
if err := id.FromParseResult(*parsed); err != nil {
return nil, err
}
return id, nil
}
func (id *AvailabilitySetId) FromParseResult(input resourceids.ParseResult) error {
var ok bool
if id.SubscriptionId, ok = input.Parsed["subscriptionId"]; !ok {
return resourceids.NewSegmentNotSpecifiedError(id, "subscriptionId", input)
}
if id.ResourceGroupName, ok = input.Parsed["resourceGroupName"]; !ok {
return resourceids.NewSegmentNotSpecifiedError(id, "resourceGroupName", input)
}
if id.AvailabilitySetName, ok = input.Parsed["availabilitySetName"]; !ok {
return resourceids.NewSegmentNotSpecifiedError(id, "availabilitySetName", input)
}
return nil
}
In terms of rollout, this needs to be done in a few stages:
- Update the Go SDK Generator in
hashicorp/pandora
to output the new FromParseResult
function (and the Parse functions to use this)
- Update the
commonids
in this repository to output the new FromParseResult
function (and update the Parse functions to use this)
- Add the new function to the
ResourceID
interface, meaning that any resourceids.ResourceId
implementation which doesn't support this will fail to compile (meaning we can mop-up any implementations)
- Vendor those changes into
hashicorp/terraform-provider-azurerm
Which then enables #188 and #189