github.phpd.cn/hashicorp/packer@v1.3.2/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 "context" 13 "fmt" 14 "strings" 15 16 "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute" 17 ) 18 19 type resourceResolver struct { 20 client *AzureClient 21 findVirtualNetworkResourceGroup func(*AzureClient, string) (string, error) 22 findVirtualNetworkSubnet func(*AzureClient, string, string) (string, error) 23 } 24 25 func newResourceResolver(client *AzureClient) *resourceResolver { 26 return &resourceResolver{ 27 client: client, 28 findVirtualNetworkResourceGroup: findVirtualNetworkResourceGroup, 29 findVirtualNetworkSubnet: findVirtualNetworkSubnet, 30 } 31 } 32 33 func (s *resourceResolver) Resolve(c *Config) error { 34 if s.shouldResolveResourceGroup(c) { 35 resourceGroupName, err := s.findVirtualNetworkResourceGroup(s.client, c.VirtualNetworkName) 36 if err != nil { 37 return err 38 } 39 40 subnetName, err := s.findVirtualNetworkSubnet(s.client, resourceGroupName, c.VirtualNetworkName) 41 if err != nil { 42 return err 43 } 44 45 c.VirtualNetworkResourceGroupName = resourceGroupName 46 c.VirtualNetworkSubnetName = subnetName 47 } 48 49 if s.shouldResolveManagedImageName(c) { 50 image, err := findManagedImageByName(s.client, c.CustomManagedImageName, c.CustomManagedImageResourceGroupName) 51 if err != nil { 52 return err 53 } 54 55 c.customManagedImageID = *image.ID 56 } 57 58 return nil 59 } 60 61 func (s *resourceResolver) shouldResolveResourceGroup(c *Config) bool { 62 return c.VirtualNetworkName != "" && c.VirtualNetworkResourceGroupName == "" 63 } 64 65 func (s *resourceResolver) shouldResolveManagedImageName(c *Config) bool { 66 return c.CustomManagedImageName != "" 67 } 68 69 func getResourceGroupNameFromId(id string) string { 70 // "/subscriptions/3f499422-dd76-4114-8859-86d526c9deb6/resourceGroups/packer-Resource-Group-yylnwsl30j/providers/... 71 xs := strings.Split(id, "/") 72 return xs[4] 73 } 74 75 func findManagedImageByName(client *AzureClient, name, resourceGroupName string) (*compute.Image, error) { 76 images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), resourceGroupName) 77 if err != nil { 78 return nil, err 79 } 80 81 for images.NotDone() { 82 image := images.Value() 83 if strings.EqualFold(name, *image.Name) { 84 return &image, nil 85 } 86 if err = images.Next(); err != nil { 87 return nil, err 88 } 89 } 90 91 return nil, fmt.Errorf("Cannot find an image named '%s' in the resource group '%s'", name, resourceGroupName) 92 } 93 94 func findVirtualNetworkResourceGroup(client *AzureClient, name string) (string, error) { 95 virtualNetworks, err := client.VirtualNetworksClient.ListAllComplete(context.TODO()) 96 if err != nil { 97 return "", err 98 } 99 100 resourceGroupNames := make([]string, 0) 101 for virtualNetworks.NotDone() { 102 virtualNetwork := virtualNetworks.Value() 103 if strings.EqualFold(name, *virtualNetwork.Name) { 104 rgn := getResourceGroupNameFromId(*virtualNetwork.ID) 105 resourceGroupNames = append(resourceGroupNames, rgn) 106 } 107 if err = virtualNetworks.Next(); err != nil { 108 return "", err 109 } 110 } 111 112 if len(resourceGroupNames) == 0 { 113 return "", fmt.Errorf("Cannot find a resource group with a virtual network called %q", name) 114 } 115 116 if len(resourceGroupNames) > 1 { 117 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) 118 } 119 120 return resourceGroupNames[0], nil 121 } 122 123 func findVirtualNetworkSubnet(client *AzureClient, resourceGroupName string, name string) (string, error) { 124 subnets, err := client.SubnetsClient.List(context.TODO(), resourceGroupName, name) 125 if err != nil { 126 return "", err 127 } 128 129 subnetList := subnets.Values() // only first page of subnets, but only interested in ==0 or >1 130 131 if len(subnetList) == 0 { 132 return "", fmt.Errorf("Cannot find a subnet in the resource group %q associated with the virtual network called %q", resourceGroupName, name) 133 } 134 135 if len(subnetList) > 1 { 136 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) 137 } 138 139 subnet := subnetList[0] 140 return *subnet.Name, nil 141 }