github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/azure/arm/azure_client.go (about) 1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the MIT License. See the LICENSE file in builder/azure for license information. 3 4 package arm 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "math" 10 "net/http" 11 "net/url" 12 "os" 13 "strconv" 14 15 "github.com/Azure/azure-sdk-for-go/arm/compute" 16 "github.com/Azure/azure-sdk-for-go/arm/network" 17 "github.com/Azure/azure-sdk-for-go/arm/resources/resources" 18 armStorage "github.com/Azure/azure-sdk-for-go/arm/storage" 19 "github.com/Azure/azure-sdk-for-go/storage" 20 "github.com/Azure/go-autorest/autorest" 21 "github.com/Azure/go-autorest/autorest/azure" 22 "github.com/mitchellh/packer/builder/azure/common" 23 "github.com/mitchellh/packer/version" 24 ) 25 26 const ( 27 EnvPackerLogAzureMaxLen = "PACKER_LOG_AZURE_MAXLEN" 28 ) 29 30 var ( 31 packerUserAgent = fmt.Sprintf(";packer/%s", version.FormattedVersion()) 32 ) 33 34 type AzureClient struct { 35 storage.BlobStorageClient 36 resources.DeploymentsClient 37 resources.GroupsClient 38 network.PublicIPAddressesClient 39 network.InterfacesClient 40 network.SubnetsClient 41 network.VirtualNetworksClient 42 compute.VirtualMachinesClient 43 common.VaultClient 44 armStorage.AccountsClient 45 46 InspectorMaxLength int 47 Template *CaptureTemplate 48 } 49 50 func getCaptureResponse(body string) *CaptureTemplate { 51 var operation CaptureOperation 52 err := json.Unmarshal([]byte(body), &operation) 53 if err != nil { 54 return nil 55 } 56 57 if operation.Properties != nil && operation.Properties.Output != nil { 58 return operation.Properties.Output 59 } 60 61 return nil 62 } 63 64 // HACK(chrboum): This method is a hack. It was written to work around this issue 65 // (https://github.com/Azure/azure-sdk-for-go/issues/307) and to an extent this 66 // issue (https://github.com/Azure/azure-rest-api-specs/issues/188). 67 // 68 // Capturing a VM is a long running operation that requires polling. There are 69 // couple different forms of polling, and the end result of a poll operation is 70 // discarded by the SDK. It is expected that any discarded data can be re-fetched, 71 // so discarding it has minimal impact. Unfortunately, there is no way to re-fetch 72 // the template returned by a capture call that I am aware of. 73 // 74 // If the second issue were fixed the VM ID would be included when GET'ing a VM. The 75 // VM ID could be used to locate the captured VHD, and captured template. 76 // Unfortunately, the VM ID is not included so this method cannot be used either. 77 // 78 // This code captures the template and saves it to the client (the AzureClient type). 79 // It expects that the capture API is called only once, or rather you only care that the 80 // last call's value is important because subsequent requests are not persisted. There 81 // is no care given to multiple threads writing this value because for our use case 82 // it does not matter. 83 func templateCapture(client *AzureClient) autorest.RespondDecorator { 84 return func(r autorest.Responder) autorest.Responder { 85 return autorest.ResponderFunc(func(resp *http.Response) error { 86 body, bodyString := handleBody(resp.Body, math.MaxInt64) 87 resp.Body = body 88 89 captureTemplate := getCaptureResponse(bodyString) 90 if captureTemplate != nil { 91 client.Template = captureTemplate 92 } 93 94 return r.Respond(resp) 95 }) 96 } 97 } 98 99 // WAITING(chrboum): I have logged https://github.com/Azure/azure-sdk-for-go/issues/311 to get this 100 // method included in the SDK. It has been accepted, and I'll cut over to the official way 101 // once it ships. 102 func byConcatDecorators(decorators ...autorest.RespondDecorator) autorest.RespondDecorator { 103 return func(r autorest.Responder) autorest.Responder { 104 return autorest.DecorateResponder(r, decorators...) 105 } 106 } 107 108 func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string, 109 cloud *azure.Environment, 110 servicePrincipalToken, servicePrincipalTokenVault *azure.ServicePrincipalToken) (*AzureClient, error) { 111 112 var azureClient = &AzureClient{} 113 114 maxlen := getInspectorMaxLength() 115 116 azureClient.DeploymentsClient = resources.NewDeploymentsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 117 azureClient.DeploymentsClient.Authorizer = servicePrincipalToken 118 azureClient.DeploymentsClient.RequestInspector = withInspection(maxlen) 119 azureClient.DeploymentsClient.ResponseInspector = byInspecting(maxlen) 120 azureClient.DeploymentsClient.UserAgent += packerUserAgent 121 122 azureClient.GroupsClient = resources.NewGroupsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 123 azureClient.GroupsClient.Authorizer = servicePrincipalToken 124 azureClient.GroupsClient.RequestInspector = withInspection(maxlen) 125 azureClient.GroupsClient.ResponseInspector = byInspecting(maxlen) 126 azureClient.GroupsClient.UserAgent += packerUserAgent 127 128 azureClient.InterfacesClient = network.NewInterfacesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 129 azureClient.InterfacesClient.Authorizer = servicePrincipalToken 130 azureClient.InterfacesClient.RequestInspector = withInspection(maxlen) 131 azureClient.InterfacesClient.ResponseInspector = byInspecting(maxlen) 132 azureClient.InterfacesClient.UserAgent += packerUserAgent 133 134 azureClient.SubnetsClient = network.NewSubnetsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 135 azureClient.SubnetsClient.Authorizer = servicePrincipalToken 136 azureClient.SubnetsClient.RequestInspector = withInspection(maxlen) 137 azureClient.SubnetsClient.ResponseInspector = byInspecting(maxlen) 138 azureClient.SubnetsClient.UserAgent += packerUserAgent 139 140 azureClient.VirtualNetworksClient = network.NewVirtualNetworksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 141 azureClient.VirtualNetworksClient.Authorizer = servicePrincipalToken 142 azureClient.VirtualNetworksClient.RequestInspector = withInspection(maxlen) 143 azureClient.VirtualNetworksClient.ResponseInspector = byInspecting(maxlen) 144 azureClient.VirtualNetworksClient.UserAgent += packerUserAgent 145 146 azureClient.PublicIPAddressesClient = network.NewPublicIPAddressesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 147 azureClient.PublicIPAddressesClient.Authorizer = servicePrincipalToken 148 azureClient.PublicIPAddressesClient.RequestInspector = withInspection(maxlen) 149 azureClient.PublicIPAddressesClient.ResponseInspector = byInspecting(maxlen) 150 azureClient.PublicIPAddressesClient.UserAgent += packerUserAgent 151 152 azureClient.VirtualMachinesClient = compute.NewVirtualMachinesClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 153 azureClient.VirtualMachinesClient.Authorizer = servicePrincipalToken 154 azureClient.VirtualMachinesClient.RequestInspector = withInspection(maxlen) 155 azureClient.VirtualMachinesClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), templateCapture(azureClient)) 156 azureClient.VirtualMachinesClient.UserAgent += packerUserAgent 157 158 azureClient.AccountsClient = armStorage.NewAccountsClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID) 159 azureClient.AccountsClient.Authorizer = servicePrincipalToken 160 azureClient.AccountsClient.RequestInspector = withInspection(maxlen) 161 azureClient.AccountsClient.ResponseInspector = byInspecting(maxlen) 162 azureClient.AccountsClient.UserAgent += packerUserAgent 163 164 keyVaultURL, err := url.Parse(cloud.KeyVaultEndpoint) 165 if err != nil { 166 return nil, err 167 } 168 169 azureClient.VaultClient = common.NewVaultClient(*keyVaultURL) 170 azureClient.VaultClient.Authorizer = servicePrincipalTokenVault 171 azureClient.VaultClient.RequestInspector = withInspection(maxlen) 172 azureClient.VaultClient.ResponseInspector = byInspecting(maxlen) 173 azureClient.VaultClient.UserAgent += packerUserAgent 174 175 accountKeys, err := azureClient.AccountsClient.ListKeys(resourceGroupName, storageAccountName) 176 if err != nil { 177 return nil, err 178 } 179 180 storageClient, err := storage.NewClient( 181 storageAccountName, 182 *(*accountKeys.Keys)[0].Value, 183 cloud.StorageEndpointSuffix, 184 storage.DefaultAPIVersion, 185 true /*useHttps*/) 186 187 if err != nil { 188 return nil, err 189 } 190 191 azureClient.BlobStorageClient = storageClient.GetBlobService() 192 return azureClient, nil 193 } 194 195 func getInspectorMaxLength() int64 { 196 value, ok := os.LookupEnv(EnvPackerLogAzureMaxLen) 197 if !ok { 198 return math.MaxInt64 199 } 200 201 i, err := strconv.ParseInt(value, 10, 64) 202 if err != nil { 203 return 0 204 } 205 206 if i < 0 { 207 return 0 208 } 209 210 return i 211 }