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 }