public async Task<IHttpActionResult> Update(UpdateVersion version) { return await DoActionAsync("UpdateController.Update", async (serviceClient) => { var updateClient = new UpdateClient(null, DashConfiguration.PackageUpdateServiceLocation); var updateManifest = await updateClient.GetUpdateVersionAsync(UpdateClient.Components.DashServer, version.Version); if (updateManifest == null) { return NotFound(); } var package = updateManifest.GetPackage(UpdateClient.GetPackageFlavorLabel(AzureService.GetServiceFlavor())); if (package == null) { return NotFound(); } var servicePackage = package.FindFileByExtension(".cspkg"); var serviceConfig = package.FindFileByExtension(".cscfg"); if (servicePackage == null || serviceConfig == null) { return NotFound(); } var operationId = DashTrace.CorrelationId.ToString(); try { var operationStatus = await UpdateConfigStatus.GetConfigUpdateStatus(operationId); await operationStatus.UpdateStatus(UpdateConfigStatus.States.PreServiceUpdate, "Begin software upgrade to version [{0}]. Operation Id: [{1}]", version.Version, operationId); // Do a couple of things up-front to ensure that we can upgrade & then kick the upgrade off & don't wait for it to complete. // Make sure reverse-DNS is configured var updateResponse = await serviceClient.UpdateService(new HostedServiceUpdateParameters { ReverseDnsFqdn = String.Format("{0}.cloudapp.net.", serviceClient.ServiceName), }); // Copy current config to config for new version var currentConfig = await serviceClient.GetDeploymentConfiguration(); var currentSettings = AzureServiceConfiguration.GetSettingsProjected(currentConfig); var newConfigDoc = XDocument.Load( await updateClient.DownloadPackageFileAsync(UpdateClient.Components.DashServer, updateManifest, package, serviceConfig.Name)); var newSettings = AzureServiceConfiguration.GetSettings(newConfigDoc); // Keep the same number of instances var ns = AzureServiceConfiguration.Namespace; AzureServiceConfiguration.GetInstances(newConfigDoc).Value = AzureServiceConfiguration.GetInstances(currentConfig).Value; foreach (var currentSetting in currentSettings) { var newSetting = AzureServiceConfiguration.GetSetting(newSettings, currentSetting.Item1); if (newSetting != null) { newSetting.SetAttributeValue("value", currentSetting.Item2); } } // Certificates (if there are any) var currentCerts = AzureServiceConfiguration.GetCertificates(currentConfig); if (currentCerts != null) { var newCerts = AzureServiceConfiguration.GetCertificates(newConfigDoc); newCerts.RemoveNodes(); foreach (var currentCert in currentCerts.Elements()) { var newCert = new XElement(ns + "Certificate"); foreach (var currentAttrib in currentCert.Attributes()) { newCert.SetAttributeValue(currentAttrib.Name, currentAttrib.Value); } newCerts.Add(newCert); } } // Send the update to the service Uri packageUri; if (!String.IsNullOrWhiteSpace(servicePackage.SasUri)) { packageUri = new Uri(servicePackage.SasUri); } else { packageUri = await updateClient.GetPackageFileSasUriAsync(UpdateClient.Components.DashServer, updateManifest, package, servicePackage.Name); } await operationStatus.UpdateStatus(UpdateConfigStatus.States.PreServiceUpdate, "Service upgrade using package [{0}].", packageUri.ToString()); var upgradeResponse = await serviceClient.UpgradeDeployment(new DeploymentUpgradeParameters { Label = String.Format("Dash.ManagementAPI-{0:o}", DateTime.UtcNow), PackageUri = packageUri, Configuration = newConfigDoc.ToString(), Mode = DeploymentUpgradeMode.Auto, }); operationStatus.CloudServiceUpdateOperationId = upgradeResponse.RequestId; await operationStatus.UpdateStatus(UpdateConfigStatus.States.UpdatingService, "Service upgrade in progress."); await EnqueueServiceOperationUpdate(serviceClient, operationId); // Manually fire up the async worker var queueTask = ProcessOperationMessageLoop(operationId, null, null, GetMessageDelay(), null); return Content(upgradeResponse.StatusCode, new OperationResult { OperationId = operationId, }); } catch (CloudException ex) { return Content(ex.Response.StatusCode, new OperationResult { OperationId = operationId, ErrorCode = ex.ErrorCode, ErrorMessage = ex.ErrorMessage, }); } catch (Exception ex) { return InternalServerError(ex); } }); }