github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/azure/arm/resource_resolver.go (about)

     1  package arm
     2  
     3  // Code to resolve resources that are required by the API.  These resources
     4  // can most likely be resolved without asking the user, thereby reducing the
     5  // amount of configuration they need to provide.
     6  //
     7  // Resource resolver differs from config retriever because resource resolver
     8  // requires a client to communicate with the Azure API.  A config retriever is
     9  // used to determine values without use of a client.
    10  
    11  import (
    12  	"fmt"
    13  	"github.com/Azure/azure-sdk-for-go/arm/compute"
    14  	"strings"
    15  )
    16  
    17  type resourceResolver struct {
    18  	client                          *AzureClient
    19  	findVirtualNetworkResourceGroup func(*AzureClient, string) (string, error)
    20  	findVirtualNetworkSubnet        func(*AzureClient, string, string) (string, error)
    21  }
    22  
    23  func newResourceResolver(client *AzureClient) *resourceResolver {
    24  	return &resourceResolver{
    25  		client: client,
    26  		findVirtualNetworkResourceGroup: findVirtualNetworkResourceGroup,
    27  		findVirtualNetworkSubnet:        findVirtualNetworkSubnet,
    28  	}
    29  }
    30  
    31  func (s *resourceResolver) Resolve(c *Config) error {
    32  	if s.shouldResolveResourceGroup(c) {
    33  		resourceGroupName, err := s.findVirtualNetworkResourceGroup(s.client, c.VirtualNetworkName)
    34  		if err != nil {
    35  			return err
    36  		}
    37  
    38  		subnetName, err := s.findVirtualNetworkSubnet(s.client, resourceGroupName, c.VirtualNetworkName)
    39  		if err != nil {
    40  			return err
    41  		}
    42  
    43  		c.VirtualNetworkResourceGroupName = resourceGroupName
    44  		c.VirtualNetworkSubnetName = subnetName
    45  	}
    46  
    47  	if s.shouldResolveManagedImageName(c) {
    48  		image, err := findManagedImageByName(s.client, c.CustomManagedImageName, c.CustomManagedImageResourceGroupName)
    49  		if err != nil {
    50  			return err
    51  		}
    52  
    53  		c.customManagedImageID = *image.ID
    54  	}
    55  
    56  	return nil
    57  }
    58  
    59  func (s *resourceResolver) shouldResolveResourceGroup(c *Config) bool {
    60  	return c.VirtualNetworkName != "" && c.VirtualNetworkResourceGroupName == ""
    61  }
    62  
    63  func (s *resourceResolver) shouldResolveManagedImageName(c *Config) bool {
    64  	return c.CustomManagedImageName != ""
    65  }
    66  
    67  func getResourceGroupNameFromId(id string) string {
    68  	// "/subscriptions/3f499422-dd76-4114-8859-86d526c9deb6/resourceGroups/packer-Resource-Group-yylnwsl30j/providers/...
    69  	xs := strings.Split(id, "/")
    70  	return xs[4]
    71  }
    72  
    73  func findManagedImageByName(client *AzureClient, name, resourceGroupName string) (*compute.Image, error) {
    74  	images, err := client.ImagesClient.ListByResourceGroup(resourceGroupName)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	for _, image := range *images.Value {
    80  		if strings.EqualFold(name, *image.Name) {
    81  			return &image, nil
    82  		}
    83  	}
    84  
    85  	return nil, fmt.Errorf("Cannot find an image named '%s' in the resource group '%s'", name, resourceGroupName)
    86  }
    87  
    88  func findVirtualNetworkResourceGroup(client *AzureClient, name string) (string, error) {
    89  	virtualNetworks, err := client.VirtualNetworksClient.ListAll()
    90  	if err != nil {
    91  		return "", err
    92  	}
    93  
    94  	resourceGroupNames := make([]string, 0)
    95  
    96  	for _, virtualNetwork := range *virtualNetworks.Value {
    97  		if strings.EqualFold(name, *virtualNetwork.Name) {
    98  			rgn := getResourceGroupNameFromId(*virtualNetwork.ID)
    99  			resourceGroupNames = append(resourceGroupNames, rgn)
   100  		}
   101  	}
   102  
   103  	if len(resourceGroupNames) == 0 {
   104  		return "", fmt.Errorf("Cannot find a resource group with a virtual network called %q", name)
   105  	}
   106  
   107  	if len(resourceGroupNames) > 1 {
   108  		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)
   109  	}
   110  
   111  	return resourceGroupNames[0], nil
   112  }
   113  
   114  func findVirtualNetworkSubnet(client *AzureClient, resourceGroupName string, name string) (string, error) {
   115  	subnets, err := client.SubnetsClient.List(resourceGroupName, name)
   116  	if err != nil {
   117  		return "", err
   118  	}
   119  
   120  	if len(*subnets.Value) == 0 {
   121  		return "", fmt.Errorf("Cannot find a subnet in the resource group %q associated with the virtual network called %q", resourceGroupName, name)
   122  	}
   123  
   124  	if len(*subnets.Value) > 1 {
   125  		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)
   126  	}
   127  
   128  	subnet := (*subnets.Value)[0]
   129  	return *subnet.Name, nil
   130  }