2016-06-30 19:51:52 -04:00
package arm
// Code to resolve resources that are required by the API. These resources
// can most likely be resolved without asking the user, thereby reducing the
// amount of configuration they need to provide.
//
// Resource resolver differs from config retriever because resource resolver
// requires a client to communicate with the Azure API. A config retriever is
// used to determine values without use of a client.
import (
2018-04-06 04:12:58 -04:00
"context"
2016-06-30 19:51:52 -04:00
"fmt"
"strings"
2018-01-22 20:21:10 -05:00
2018-04-06 04:12:58 -04:00
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
2016-06-30 19:51:52 -04:00
)
type resourceResolver struct {
client * AzureClient
findVirtualNetworkResourceGroup func ( * AzureClient , string ) ( string , error )
findVirtualNetworkSubnet func ( * AzureClient , string , string ) ( string , error )
}
func newResourceResolver ( client * AzureClient ) * resourceResolver {
return & resourceResolver {
2018-08-24 18:56:44 -04:00
client : client ,
2016-06-30 19:51:52 -04:00
findVirtualNetworkResourceGroup : findVirtualNetworkResourceGroup ,
findVirtualNetworkSubnet : findVirtualNetworkSubnet ,
}
}
func ( s * resourceResolver ) Resolve ( c * Config ) error {
if s . shouldResolveResourceGroup ( c ) {
resourceGroupName , err := s . findVirtualNetworkResourceGroup ( s . client , c . VirtualNetworkName )
if err != nil {
return err
}
subnetName , err := s . findVirtualNetworkSubnet ( s . client , resourceGroupName , c . VirtualNetworkName )
if err != nil {
return err
}
c . VirtualNetworkResourceGroupName = resourceGroupName
c . VirtualNetworkSubnetName = subnetName
}
2017-05-29 00:06:09 -04:00
if s . shouldResolveManagedImageName ( c ) {
2017-05-30 14:25:46 -04:00
image , err := findManagedImageByName ( s . client , c . CustomManagedImageName , c . CustomManagedImageResourceGroupName )
2017-05-29 00:06:09 -04:00
if err != nil {
return err
}
2017-06-22 19:36:40 -04:00
c . customManagedImageID = * image . ID
2017-05-29 00:06:09 -04:00
}
2016-06-30 19:51:52 -04:00
return nil
}
func ( s * resourceResolver ) shouldResolveResourceGroup ( c * Config ) bool {
return c . VirtualNetworkName != "" && c . VirtualNetworkResourceGroupName == ""
}
2017-05-29 00:06:09 -04:00
func ( s * resourceResolver ) shouldResolveManagedImageName ( c * Config ) bool {
2017-05-30 14:25:46 -04:00
return c . CustomManagedImageName != ""
2017-05-29 00:06:09 -04:00
}
2016-06-30 19:51:52 -04:00
func getResourceGroupNameFromId ( id string ) string {
// "/subscriptions/3f499422-dd76-4114-8859-86d526c9deb6/resourceGroups/packer-Resource-Group-yylnwsl30j/providers/...
xs := strings . Split ( id , "/" )
return xs [ 4 ]
}
2017-05-29 00:06:09 -04:00
func findManagedImageByName ( client * AzureClient , name , resourceGroupName string ) ( * compute . Image , error ) {
2018-04-06 04:12:58 -04:00
images , err := client . ImagesClient . ListByResourceGroupComplete ( context . TODO ( ) , resourceGroupName )
2017-05-29 00:06:09 -04:00
if err != nil {
return nil , err
}
2018-04-06 04:12:58 -04:00
for images . NotDone ( ) {
image := images . Value ( )
2017-05-29 00:06:09 -04:00
if strings . EqualFold ( name , * image . Name ) {
return & image , nil
}
2018-04-06 04:12:58 -04:00
if err = images . Next ( ) ; err != nil {
return nil , err
}
2017-05-29 00:06:09 -04:00
}
return nil , fmt . Errorf ( "Cannot find an image named '%s' in the resource group '%s'" , name , resourceGroupName )
}
2016-06-30 19:51:52 -04:00
func findVirtualNetworkResourceGroup ( client * AzureClient , name string ) ( string , error ) {
2018-04-06 04:12:58 -04:00
virtualNetworks , err := client . VirtualNetworksClient . ListAllComplete ( context . TODO ( ) )
2016-06-30 19:51:52 -04:00
if err != nil {
return "" , err
}
resourceGroupNames := make ( [ ] string , 0 )
2018-04-06 04:12:58 -04:00
for virtualNetworks . NotDone ( ) {
virtualNetwork := virtualNetworks . Value ( )
2016-06-30 19:51:52 -04:00
if strings . EqualFold ( name , * virtualNetwork . Name ) {
rgn := getResourceGroupNameFromId ( * virtualNetwork . ID )
resourceGroupNames = append ( resourceGroupNames , rgn )
}
2018-04-06 04:12:58 -04:00
if err = virtualNetworks . Next ( ) ; err != nil {
return "" , err
}
2016-06-30 19:51:52 -04:00
}
if len ( resourceGroupNames ) == 0 {
return "" , fmt . Errorf ( "Cannot find a resource group with a virtual network called %q" , name )
}
if len ( resourceGroupNames ) > 1 {
2016-09-28 12:50:10 -04:00
return "" , fmt . Errorf ( "Found multiple resource groups with a virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate" , name )
2016-06-30 19:51:52 -04:00
}
return resourceGroupNames [ 0 ] , nil
}
func findVirtualNetworkSubnet ( client * AzureClient , resourceGroupName string , name string ) ( string , error ) {
2018-04-06 04:12:58 -04:00
subnets , err := client . SubnetsClient . List ( context . TODO ( ) , resourceGroupName , name )
2016-06-30 19:51:52 -04:00
if err != nil {
return "" , err
}
2018-04-06 04:12:58 -04:00
subnetList := subnets . Values ( ) // only first page of subnets, but only interested in ==0 or >1
if len ( subnetList ) == 0 {
2016-06-30 19:51:52 -04:00
return "" , fmt . Errorf ( "Cannot find a subnet in the resource group %q associated with the virtual network called %q" , resourceGroupName , name )
}
2018-04-06 04:12:58 -04:00
if len ( subnetList ) > 1 {
return "" , fmt . Errorf ( "Found multiple subnets in the resource group %q associated with the virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate" , resourceGroupName , name )
2016-06-30 19:51:52 -04:00
}
2018-04-06 04:12:58 -04:00
subnet := subnetList [ 0 ]
2016-06-30 19:51:52 -04:00
return * subnet . Name , nil
}