1// +build go1.7 2 3// Package virtualmachine provides a client for Virtual Machines. 4package virtualmachine 5 6// Copyright (c) Microsoft Corporation. All rights reserved. 7// Licensed under the MIT License. See License.txt in the project root for license information. 8 9import ( 10 "encoding/xml" 11 "fmt" 12 13 "github.com/Azure/azure-sdk-for-go/services/classic/management" 14) 15 16const ( 17 azureDeploymentListURL = "services/hostedservices/%s/deployments" 18 azureDeploymentURL = "services/hostedservices/%s/deployments/%s" 19 azureUpdateDeploymentURL = "services/hostedservices/%s/deployments/%s?comp=%s" 20 azureDeploymentSlotSwapURL = "services/hostedservices/%s" 21 azureDeploymentSlotURL = "services/hostedservices/%s/deploymentslots/%s" 22 azureUpdateDeploymentSlotConfigurationURL = "services/hostedservices/%s/deploymentslots/%s?comp=%s" 23 deleteAzureDeploymentURL = "services/hostedservices/%s/deployments/%s?comp=media" 24 azureDeleteDeploymentBySlotURL = "services/hostedservices/%s/deploymentslots/%s" 25 azureAddRoleURL = "services/hostedservices/%s/deployments/%s/roles" 26 azureRoleURL = "services/hostedservices/%s/deployments/%s/roles/%s" 27 azureOperationsURL = "services/hostedservices/%s/deployments/%s/roleinstances/%s/Operations" 28 azureRoleSizeListURL = "rolesizes" 29 30 errParamNotSpecified = "Parameter %s is not specified." 31) 32 33//NewClient is used to instantiate a new VirtualMachineClient from an Azure client 34func NewClient(client management.Client) VirtualMachineClient { 35 return VirtualMachineClient{client: client} 36} 37 38// CreateDeploymentOptions can be used to create a customized deployement request 39type CreateDeploymentOptions struct { 40 DNSServers []DNSServer 41 LoadBalancers []LoadBalancer 42 ReservedIPName string 43 VirtualNetworkName string 44} 45 46// CreateDeployment creates a deployment and then creates a virtual machine 47// in the deployment based on the specified configuration. 48// 49// https://msdn.microsoft.com/en-us/library/azure/jj157194.aspx 50func (vm VirtualMachineClient) CreateDeployment( 51 role Role, 52 cloudServiceName string, 53 options CreateDeploymentOptions) (management.OperationID, error) { 54 55 req := DeploymentRequest{ 56 Name: role.RoleName, 57 DeploymentSlot: "Production", 58 Label: role.RoleName, 59 RoleList: []Role{role}, 60 DNSServers: options.DNSServers, 61 LoadBalancers: options.LoadBalancers, 62 ReservedIPName: options.ReservedIPName, 63 VirtualNetworkName: options.VirtualNetworkName, 64 } 65 66 data, err := xml.Marshal(req) 67 if err != nil { 68 return "", err 69 } 70 71 requestURL := fmt.Sprintf(azureDeploymentListURL, cloudServiceName) 72 return vm.client.SendAzurePostRequest(requestURL, data) 73} 74 75// CreateDeploymentFromPackageOptions can be used to create a customized deployement request 76type CreateDeploymentFromPackageOptions struct { 77 Name string 78 PackageURL string 79 Label string 80 Configuration string 81 StartDeployment bool 82 TreatWarningsAsError bool 83 ExtendedProperties []ExtendedProperty 84 ExtensionConfiguration ExtensionConfiguration 85} 86 87// CreateDeploymentRequest is the type for creating a deployment of a cloud service package 88// in the deployment based on the specified configuration. See 89// https://docs.microsoft.com/en-us/rest/api/compute/cloudservices/rest-create-deployment 90type CreateDeploymentRequest struct { 91 XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure CreateDeployment"` 92 // Required parameters: 93 Name string `` // Specifies the name of the deployment. 94 PackageURL string `xml:"PackageUrl"` // Specifies a URL that refers to the location of the service package in the Blob service. The service package can be located either in a storage account beneath the same subscription or a Shared Access Signature (SAS) URI from any storage account. 95 Label string `` // Specifies an identifier for the deployment that is base-64 encoded. The identifier can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The label can be used for your tracking purposes. 96 Configuration string `` // Specifies the base-64 encoded service configuration file for the deployment. 97 // Optional parameters: 98 StartDeployment bool `` // Indicates whether to start the deployment immediately after it is created. The default value is false 99 TreatWarningsAsError bool `` // Indicates whether to treat package validation warnings as errors. The default value is false. If set to true, the Created Deployment operation fails if there are validation warnings on the service package. 100 ExtendedProperties []ExtendedProperty `xml:">ExtendedProperty,omitempty"` // Array of ExtendedProprties. Each extended property must have both a defined name and value. You can have a maximum of 25 extended property name and value pairs. 101 ExtensionConfiguration ExtensionConfiguration `xml:",omitempty"` 102} 103 104// CreateDeploymentFromPackage creates a deployment from a cloud services package (.cspkg) and configuration file (.cscfg) 105func (vm VirtualMachineClient) CreateDeploymentFromPackage( 106 cloudServiceName string, 107 deploymentSlot DeploymentSlot, 108 options CreateDeploymentFromPackageOptions) (management.OperationID, error) { 109 110 if cloudServiceName == "" { 111 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 112 } 113 114 req := CreateDeploymentRequest{ 115 Name: options.Name, 116 Label: options.Label, 117 Configuration: options.Configuration, 118 PackageURL: options.PackageURL, 119 StartDeployment: options.StartDeployment, 120 TreatWarningsAsError: options.TreatWarningsAsError, 121 ExtendedProperties: options.ExtendedProperties, 122 ExtensionConfiguration: options.ExtensionConfiguration, 123 } 124 125 data, err := xml.Marshal(req) 126 if err != nil { 127 return "", err 128 } 129 130 requestURL := fmt.Sprintf(azureDeploymentSlotURL, cloudServiceName, deploymentSlot) 131 return vm.client.SendAzurePostRequest(requestURL, data) 132} 133 134// SwapDeploymentRequest is the type used for specifying information to swap the deployments in 135// a cloud service 136// https://docs.microsoft.com/en-us/rest/api/compute/cloudservices/rest-swap-deployment 137type SwapDeploymentRequest struct { 138 XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure Swap"` 139 // Required parameters: 140 Production string 141 SourceDeployment string 142} 143 144// SwapDeployment initiates a virtual IP address swap between the staging and production deployment environments for a service. 145// If the service is currently running in the staging environment, it will be swapped to the production environment. 146// If it is running in the production environment, it will be swapped to staging. 147func (vm VirtualMachineClient) SwapDeployment( 148 cloudServiceName string) (management.OperationID, error) { 149 150 if cloudServiceName == "" { 151 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 152 } 153 154 productionDeploymentName, err := vm.GetDeploymentNameForSlot(cloudServiceName, DeploymentSlotProduction) 155 if err != nil { 156 return "", err 157 } 158 159 stagingDeploymentName, err := vm.GetDeploymentNameForSlot(cloudServiceName, DeploymentSlotStaging) 160 if err != nil { 161 return "", err 162 } 163 164 req := SwapDeploymentRequest{ 165 Production: productionDeploymentName, 166 SourceDeployment: stagingDeploymentName, 167 } 168 169 data, err := xml.Marshal(req) 170 if err != nil { 171 return "", err 172 } 173 174 requestURL := fmt.Sprintf(azureDeploymentSlotSwapURL, cloudServiceName) 175 return vm.client.SendAzurePostRequest(requestURL, data) 176} 177 178// ChangeDeploymentConfigurationRequestOptions can be used to update configuration of a deployment 179type ChangeDeploymentConfigurationRequestOptions struct { 180 Mode UpgradeType 181 Configuration string 182 TreatWarningsAsError bool 183 ExtendedProperties []ExtendedProperty 184 ExtensionConfiguration ExtensionConfiguration 185} 186 187// ChangeDeploymentConfigurationRequest is the type for changing the configuration of a deployment of a cloud service p 188// https://docs.microsoft.com/en-us/rest/api/compute/cloudservices/rest-change-deployment-configuration 189type ChangeDeploymentConfigurationRequest struct { 190 XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure ChangeConfiguration"` 191 // Required parameters: 192 Configuration string `` // Specifies the base-64 encoded service configuration file for the deployment. 193 // Optional parameters: 194 Mode UpgradeType `` // Specifies the type of Upgrade (Auto | Manual | Simultaneous) . 195 TreatWarningsAsError bool `` // Indicates whether to treat package validation warnings as errors. The default value is false. If set to true, the Created Deployment operation fails if there are validation warnings on the service package. 196 ExtendedProperties []ExtendedProperty `xml:">ExtendedProperty,omitempty"` // Array of ExtendedProprties. Each extended property must have both a defined name and value. You can have a maximum of 25 extended property name and value pairs. 197 ExtensionConfiguration ExtensionConfiguration `xml:",omitempty"` 198} 199 200// ChangeDeploymentConfiguration updates the configuration for a deployment from a configuration file (.cscfg) 201func (vm VirtualMachineClient) ChangeDeploymentConfiguration( 202 cloudServiceName string, 203 deploymentSlot DeploymentSlot, 204 options ChangeDeploymentConfigurationRequestOptions) (management.OperationID, error) { 205 206 if cloudServiceName == "" { 207 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 208 } 209 210 req := ChangeDeploymentConfigurationRequest{ 211 Mode: options.Mode, 212 Configuration: options.Configuration, 213 TreatWarningsAsError: options.TreatWarningsAsError, 214 ExtendedProperties: options.ExtendedProperties, 215 ExtensionConfiguration: options.ExtensionConfiguration, 216 } 217 if req.Mode == "" { 218 req.Mode = UpgradeTypeAuto 219 } 220 221 data, err := xml.Marshal(req) 222 if err != nil { 223 return "", err 224 } 225 226 requestURL := fmt.Sprintf(azureUpdateDeploymentSlotConfigurationURL, cloudServiceName, deploymentSlot, "config") 227 return vm.client.SendAzurePostRequest(requestURL, data) 228} 229 230// UpdateDeploymentStatusRequest is the type used to make UpdateDeploymentStatus requests 231type UpdateDeploymentStatusRequest struct { 232 XMLName xml.Name `xml:"http://schemas.microsoft.com/windowsazure UpdateDeploymentStatus"` 233 // Required parameters: 234 Status string 235} 236 237// UpdateDeploymentStatus changes the running status of a deployment. The status of a deployment can be running or suspended. 238// https://docs.microsoft.com/en-us/rest/api/compute/cloudservices/rest-update-deployment-status 239func (vm VirtualMachineClient) UpdateDeploymentStatus( 240 cloudServiceName string, 241 deploymentSlot DeploymentSlot, 242 status string) (management.OperationID, error) { 243 244 if cloudServiceName == "" { 245 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 246 } 247 248 if status != "Running" && status != "Suspended" { 249 return "", fmt.Errorf("Invalid status provided") 250 } 251 252 req := UpdateDeploymentStatusRequest{ 253 Status: status, 254 } 255 256 data, err := xml.Marshal(req) 257 if err != nil { 258 return "", err 259 } 260 261 requestURL := fmt.Sprintf(azureUpdateDeploymentSlotConfigurationURL, cloudServiceName, deploymentSlot, "status") 262 return vm.client.SendAzurePostRequest(requestURL, data) 263} 264 265// UpdateDeploymentStatusByName changes the running status of a deployment. The status of a deployment can be running or suspended. 266// https://docs.microsoft.com/en-us/rest/api/compute/cloudservices/rest-update-deployment-status 267func (vm VirtualMachineClient) UpdateDeploymentStatusByName( 268 cloudServiceName string, 269 deploymentName string, 270 status string) (management.OperationID, error) { 271 272 if cloudServiceName == "" { 273 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 274 } 275 276 if status != "Running" && status != "Suspended" { 277 return "", fmt.Errorf("Invalid status provided") 278 } 279 280 req := UpdateDeploymentStatusRequest{ 281 Status: status, 282 } 283 284 data, err := xml.Marshal(req) 285 if err != nil { 286 return "", err 287 } 288 289 requestURL := fmt.Sprintf(azureUpdateDeploymentURL, cloudServiceName, deploymentName, "status") 290 return vm.client.SendAzurePostRequest(requestURL, data) 291} 292 293// GetDeploymentName queries an existing Azure cloud service for the name of the Deployment, 294// if any, in its 'Production' slot (the only slot possible). If none exists, it returns empty 295// string but no error 296// 297//https://msdn.microsoft.com/en-us/library/azure/ee460804.aspx 298func (vm VirtualMachineClient) GetDeploymentName(cloudServiceName string) (string, error) { 299 return vm.GetDeploymentNameForSlot(cloudServiceName, DeploymentSlotProduction) 300} 301 302// GetDeploymentNameForSlot queries an existing Azure cloud service for the name of the Deployment, 303// in a given slot. If none exists, it returns empty 304// string but no error 305// 306//https://msdn.microsoft.com/en-us/library/azure/ee460804.aspx 307func (vm VirtualMachineClient) GetDeploymentNameForSlot(cloudServiceName string, deploymentSlot DeploymentSlot) (string, error) { 308 var deployment DeploymentResponse 309 if cloudServiceName == "" { 310 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 311 } 312 requestURL := fmt.Sprintf(azureDeploymentSlotURL, cloudServiceName, deploymentSlot) 313 response, err := vm.client.SendAzureGetRequest(requestURL) 314 if err != nil { 315 if management.IsResourceNotFoundError(err) { 316 return "", nil 317 } 318 return "", err 319 } 320 err = xml.Unmarshal(response, &deployment) 321 if err != nil { 322 return "", err 323 } 324 325 return deployment.Name, nil 326} 327 328func (vm VirtualMachineClient) GetDeployment(cloudServiceName, deploymentName string) (DeploymentResponse, error) { 329 var deployment DeploymentResponse 330 if cloudServiceName == "" { 331 return deployment, fmt.Errorf(errParamNotSpecified, "cloudServiceName") 332 } 333 if deploymentName == "" { 334 return deployment, fmt.Errorf(errParamNotSpecified, "deploymentName") 335 } 336 requestURL := fmt.Sprintf(azureDeploymentURL, cloudServiceName, deploymentName) 337 response, azureErr := vm.client.SendAzureGetRequest(requestURL) 338 if azureErr != nil { 339 return deployment, azureErr 340 } 341 342 err := xml.Unmarshal(response, &deployment) 343 return deployment, err 344} 345 346// GetDeploymentBySlot used to retrieve deployment events for a single deployment slot (staging or production) 347func (vm VirtualMachineClient) GetDeploymentBySlot(cloudServiceName string, deploymentSlot DeploymentSlot) (DeploymentResponse, error) { 348 var deployment DeploymentResponse 349 if cloudServiceName == "" { 350 return deployment, fmt.Errorf(errParamNotSpecified, "cloudServiceName") 351 } 352 if deploymentSlot == "" { 353 return deployment, fmt.Errorf(errParamNotSpecified, "deploymentSlot") 354 } 355 requestURL := fmt.Sprintf(azureDeploymentSlotURL, cloudServiceName, deploymentSlot) 356 response, azureErr := vm.client.SendAzureGetRequest(requestURL) 357 if azureErr != nil { 358 return deployment, azureErr 359 } 360 361 err := xml.Unmarshal(response, &deployment) 362 return deployment, err 363} 364 365func (vm VirtualMachineClient) DeleteDeployment(cloudServiceName, deploymentName string) (management.OperationID, error) { 366 if cloudServiceName == "" { 367 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 368 } 369 if deploymentName == "" { 370 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 371 } 372 373 requestURL := fmt.Sprintf(deleteAzureDeploymentURL, cloudServiceName, deploymentName) 374 return vm.client.SendAzureDeleteRequest(requestURL) 375} 376 377func (vm VirtualMachineClient) DeleteDeploymentBySlot(cloudServiceName string, deploymentSlot DeploymentSlot) (management.OperationID, error) { 378 if cloudServiceName == "" { 379 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 380 } 381 if deploymentSlot == "" { 382 return "", fmt.Errorf(errParamNotSpecified, "deploymentSlot") 383 } 384 385 requestURL := fmt.Sprintf(azureDeleteDeploymentBySlotURL, cloudServiceName, deploymentSlot) 386 return vm.client.SendAzureDeleteRequest(requestURL) 387} 388 389func (vm VirtualMachineClient) GetRole(cloudServiceName, deploymentName, roleName string) (*Role, error) { 390 if cloudServiceName == "" { 391 return nil, fmt.Errorf(errParamNotSpecified, "cloudServiceName") 392 } 393 if deploymentName == "" { 394 return nil, fmt.Errorf(errParamNotSpecified, "deploymentName") 395 } 396 if roleName == "" { 397 return nil, fmt.Errorf(errParamNotSpecified, "roleName") 398 } 399 400 role := new(Role) 401 402 requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName) 403 response, azureErr := vm.client.SendAzureGetRequest(requestURL) 404 if azureErr != nil { 405 return nil, azureErr 406 } 407 408 err := xml.Unmarshal(response, role) 409 if err != nil { 410 return nil, err 411 } 412 413 return role, nil 414} 415 416// AddRole adds a Virtual Machine to a deployment of Virtual Machines, where role name = VM name 417// See https://msdn.microsoft.com/en-us/library/azure/jj157186.aspx 418func (vm VirtualMachineClient) AddRole(cloudServiceName string, deploymentName string, role Role) (management.OperationID, error) { 419 if cloudServiceName == "" { 420 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 421 } 422 if deploymentName == "" { 423 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 424 } 425 426 data, err := xml.Marshal(PersistentVMRole{Role: role}) 427 if err != nil { 428 return "", err 429 } 430 431 requestURL := fmt.Sprintf(azureAddRoleURL, cloudServiceName, deploymentName) 432 return vm.client.SendAzurePostRequest(requestURL, data) 433} 434 435// UpdateRole updates the configuration of the specified virtual machine 436// See https://msdn.microsoft.com/en-us/library/azure/jj157187.aspx 437func (vm VirtualMachineClient) UpdateRole(cloudServiceName, deploymentName, roleName string, role Role) (management.OperationID, error) { 438 if cloudServiceName == "" { 439 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 440 } 441 if deploymentName == "" { 442 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 443 } 444 if roleName == "" { 445 return "", fmt.Errorf(errParamNotSpecified, "roleName") 446 } 447 448 data, err := xml.Marshal(PersistentVMRole{Role: role}) 449 if err != nil { 450 return "", err 451 } 452 453 requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName) 454 return vm.client.SendAzurePutRequest(requestURL, "text/xml", data) 455} 456 457func (vm VirtualMachineClient) StartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) { 458 if cloudServiceName == "" { 459 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 460 } 461 if deploymentName == "" { 462 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 463 } 464 if roleName == "" { 465 return "", fmt.Errorf(errParamNotSpecified, "roleName") 466 } 467 468 startRoleOperationBytes, err := xml.Marshal(StartRoleOperation{ 469 OperationType: "StartRoleOperation", 470 }) 471 if err != nil { 472 return "", err 473 } 474 475 requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName) 476 return vm.client.SendAzurePostRequest(requestURL, startRoleOperationBytes) 477} 478 479func (vm VirtualMachineClient) ShutdownRole(cloudServiceName, deploymentName, roleName string, postaction PostShutdownAction) (management.OperationID, error) { 480 if cloudServiceName == "" { 481 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 482 } 483 if deploymentName == "" { 484 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 485 } 486 if roleName == "" { 487 return "", fmt.Errorf(errParamNotSpecified, "roleName") 488 } 489 490 shutdownRoleOperationBytes, err := xml.Marshal(ShutdownRoleOperation{ 491 OperationType: "ShutdownRoleOperation", 492 PostShutdownAction: postaction, 493 }) 494 if err != nil { 495 return "", err 496 } 497 498 requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName) 499 return vm.client.SendAzurePostRequest(requestURL, shutdownRoleOperationBytes) 500} 501 502func (vm VirtualMachineClient) RestartRole(cloudServiceName, deploymentName, roleName string) (management.OperationID, error) { 503 if cloudServiceName == "" { 504 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 505 } 506 if deploymentName == "" { 507 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 508 } 509 if roleName == "" { 510 return "", fmt.Errorf(errParamNotSpecified, "roleName") 511 } 512 513 restartRoleOperationBytes, err := xml.Marshal(RestartRoleOperation{ 514 OperationType: "RestartRoleOperation", 515 }) 516 if err != nil { 517 return "", err 518 } 519 520 requestURL := fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName) 521 return vm.client.SendAzurePostRequest(requestURL, restartRoleOperationBytes) 522} 523 524func (vm VirtualMachineClient) DeleteRole(cloudServiceName, deploymentName, roleName string, deleteVHD bool) (management.OperationID, error) { 525 if cloudServiceName == "" { 526 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 527 } 528 if deploymentName == "" { 529 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 530 } 531 if roleName == "" { 532 return "", fmt.Errorf(errParamNotSpecified, "roleName") 533 } 534 535 requestURL := fmt.Sprintf(azureRoleURL, cloudServiceName, deploymentName, roleName) 536 if deleteVHD { 537 requestURL += "?comp=media" 538 } 539 return vm.client.SendAzureDeleteRequest(requestURL) 540} 541 542func (vm VirtualMachineClient) GetRoleSizeList() (RoleSizeList, error) { 543 roleSizeList := RoleSizeList{} 544 545 response, err := vm.client.SendAzureGetRequest(azureRoleSizeListURL) 546 if err != nil { 547 return roleSizeList, err 548 } 549 550 err = xml.Unmarshal(response, &roleSizeList) 551 return roleSizeList, err 552} 553 554// CaptureRole captures a VM role. If reprovisioningConfigurationSet is non-nil, 555// the VM role is redeployed after capturing the image, otherwise, the original 556// VM role is deleted. 557// 558// NOTE: an image resulting from this operation shows up in 559// osimage.GetImageList() as images with Category "User". 560func (vm VirtualMachineClient) CaptureRole(cloudServiceName, deploymentName, roleName, imageName, imageLabel string, 561 reprovisioningConfigurationSet *ConfigurationSet) (management.OperationID, error) { 562 if cloudServiceName == "" { 563 return "", fmt.Errorf(errParamNotSpecified, "cloudServiceName") 564 } 565 if deploymentName == "" { 566 return "", fmt.Errorf(errParamNotSpecified, "deploymentName") 567 } 568 if roleName == "" { 569 return "", fmt.Errorf(errParamNotSpecified, "roleName") 570 } 571 572 if reprovisioningConfigurationSet != nil && 573 !(reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeLinuxProvisioning || 574 reprovisioningConfigurationSet.ConfigurationSetType == ConfigurationSetTypeWindowsProvisioning) { 575 return "", fmt.Errorf("ConfigurationSet type can only be WindowsProvisioningConfiguration or LinuxProvisioningConfiguration") 576 } 577 578 operation := CaptureRoleOperation{ 579 OperationType: "CaptureRoleOperation", 580 PostCaptureAction: PostCaptureActionReprovision, 581 ProvisioningConfiguration: reprovisioningConfigurationSet, 582 TargetImageLabel: imageLabel, 583 TargetImageName: imageName, 584 } 585 if reprovisioningConfigurationSet == nil { 586 operation.PostCaptureAction = PostCaptureActionDelete 587 } 588 589 data, err := xml.Marshal(operation) 590 if err != nil { 591 return "", err 592 } 593 594 return vm.client.SendAzurePostRequest(fmt.Sprintf(azureOperationsURL, cloudServiceName, deploymentName, roleName), data) 595} 596