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