public async Task <string> ValidateContext(HostAssignmentContext assignmentContext) { string error = null; HttpResponseMessage response = null; try { var zipUrl = assignmentContext.ZipUrl; if (!string.IsNullOrEmpty(zipUrl)) { // make sure the zip uri is valid and accessible await OperationManager.AttemptAsync(async() => { try { var request = new HttpRequestMessage(HttpMethod.Head, zipUrl); response = await _client.SendAsync(request); response.EnsureSuccessStatusCode(); } catch (Exception) { throw; } }, retries : 2, delayBeforeRetry : 300 /*ms*/); } } catch (Exception) { error = $"Invalid zip url specified (StatusCode: {response?.StatusCode})"; } return(error); }
public static async Task RestartMainSiteAsync(string requestId, TraceListener tracer) { Trace(tracer, TraceEventType.Information, "Requesting site restart"); VerifyEnvironments(); int attemptCount = 0; try { await OperationManager.AttemptAsync(async() => { attemptCount++; Trace(tracer, TraceEventType.Information, $"Requesting site restart. Attempt #{attemptCount}"); await PostAsync(Constants.RestartApiPath, requestId, null); Trace(tracer, TraceEventType.Information, $"Successfully requested a restart. Attempt #{attemptCount}"); }, RestartRetryCount, RestartRetryIntervalInMilliSeconds); } catch { Trace(tracer, TraceEventType.Information, $"Failed to request a restart. Number of attempts: {attemptCount}"); throw; } }
public async Task <bool> SendDeployStatusUpdate(DeployStatusApiResult updateStatusObj) { ITracer tracer = _traceFactory.GetTracer(); int attemptCount = 0; try { await OperationManager.AttemptAsync(async() => { attemptCount++; tracer.Trace($" PostAsync - Trying to send {updateStatusObj.DeploymentStatus} deployment status to {Constants.UpdateDeployStatusPath}. Deployment Id is {updateStatusObj.DeploymentId}"); await PostDeploymentHelper.PostAsync(Constants.UpdateDeployStatusPath, _environment.RequestId, content: JsonConvert.SerializeObject(updateStatusObj)); }, 3, 5 * 1000); // If no exception is thrown, the operation was a success return(true); } catch (Exception ex) { tracer.TraceError($"Failed to request a post deployment status. Number of attempts: {attemptCount}. Exception: {ex}"); // Do not throw the exception // We fail silently so that we do not fail the build altogether if this call fails //throw; return(false); } }
private static async Task RemoveLinuxConsumptionFunctionAppWorkers(DeploymentContext context) { string webSiteHostName = System.Environment.GetEnvironmentVariable(SettingsKeys.WebsiteHostname); string sitename = ServerConfiguration.GetApplicationName(); context.Logger.Log($"Resetting all workers for {webSiteHostName}"); try { await OperationManager.AttemptAsync(async() => { await PostDeploymentHelper.RemoveAllWorkersAsync(webSiteHostName, sitename); }, retries : 3, delayBeforeRetry : 2000); } catch (ArgumentException ae) { context.Logger.Log($"Reset all workers has malformed webSiteHostName or sitename {ae.Message}"); throw new DeploymentFailedException(ae); } catch (HttpRequestException hre) { context.Logger.Log($"Reset all workers endpoint responded with {hre.Message}"); throw new DeploymentFailedException(hre); } }
private static async Task <bool> TryFunctionsRuntimeSyncTriggers(string requestId) { try { var scmHostName = IsLocalHost ? HttpAuthority : HttpHost; var scmSplit = scmHostName.Split('.'); if (!(scmSplit.Length > 1 && scmSplit[1].Equals("scm", StringComparison.OrdinalIgnoreCase))) { return(false); } var functionsSiteHostName = string.Join(".", scmSplit.Where((el, idx) => idx != 1)); await OperationManager.AttemptAsync(async() => await PostAsync(Constants.FunctionsSyncTriggersApiPath, requestId, hostName: functionsSiteHostName), retries : 3, delayBeforeRetry : 1000); return(true); } catch (Exception) { Trace(TraceEventType.Information, "Syncing function triggers by calling the functions runtime site failed."); return(false); } }
public static async Task UpdateSiteVersion(ArtifactDeploymentInfo deploymentInfo, IEnvironment environment, ITracer tracer) { var siteVersionPath = Path.Combine(environment.SitePackagesPath, Constants.PackageNameTxt); using (tracer.Step($"Updating {siteVersionPath} with deployment {deploymentInfo.ArtifactFileName}")) { await OperationManager.AttemptAsync(() => FileSystemHelpers.WriteAllTextToFileAsync(siteVersionPath, deploymentInfo.ArtifactFileName)); } }
public async Task Delete() { await OperationManager.AttemptAsync(async() => { using (var response = await Client.DeleteAsync( $"/subscriptions/{_config.Subscription}/resourceGroups/{_config.ResourceGroup}/providers/Microsoft.Web/sites/{AppName}?api-version=2016-03-01")) { response.EnsureSuccessStatusCode(); } }, 5, 2000); }
private static async Task FunctionHostSyncTriggersAsync(DeploymentContext context) { string webSiteHostName = System.Environment.GetEnvironmentVariable(SettingsKeys.WebsiteHostname); context.Logger.Log($"Synchronizing function triggers for your function app {webSiteHostName}"); try { await OperationManager.AttemptAsync(async() => { await PostDeploymentHelper.PerformFunctionHostSyncTriggersAsync(webSiteHostName); }, retries : 3, delayBeforeRetry : 2000); } catch (HttpRequestException hre) { context.Logger.Log($"Function triggers synchronization failed due to {hre.Message}"); } }
public async Task SiteExtensionShouldDeployWebJobs() { const string appName = "SiteExtensionShouldDeployWebJobs"; await ApplicationManager.RunAsync(appName, async appManager => { var manager = appManager.SiteExtensionManager; await CleanSiteExtensions(manager); TestTracer.Trace("Install site extension with jobs"); await manager.InstallExtension("filecounterwithwebjobs", null, "https://www.myget.org/F/amitaptest/"); TestTracer.Trace("Verify jobs were deployed"); await OperationManager.AttemptAsync(async() => { var continuousJobs = (await appManager.JobsManager.ListContinuousJobsAsync()).ToArray(); Assert.Equal(1, continuousJobs.Length); Assert.Equal("filecounterwithwebjobs(cjoba)", continuousJobs[0].Name); TestTracer.Trace("Job status - {0}", continuousJobs[0].Status); Assert.Equal("PendingRestart", continuousJobs[0].Status); }, 100, 500); TriggeredJob[] triggeredJobs; await OperationManager.AttemptAsync(async() => { triggeredJobs = (await appManager.JobsManager.ListTriggeredJobsAsync()).ToArray(); Assert.Equal(2, triggeredJobs.Length); Assert.Equal("filecounterwithwebjobs(tjoba)", triggeredJobs[0].Name); Assert.Equal("filecounterwithwebjobs(tjobb)", triggeredJobs[1].Name); }, 100, 500); TestTracer.Trace("Uninstall site extension with jobs"); await manager.UninstallExtension("filecounterwithwebjobs"); TestTracer.Trace("Verify jobs removed"); await OperationManager.AttemptAsync(async() => { var continuousJobs2 = (await appManager.JobsManager.ListContinuousJobsAsync()).ToArray(); Assert.Equal(0, continuousJobs2.Length); triggeredJobs = (await appManager.JobsManager.ListTriggeredJobsAsync()).ToArray(); Assert.Equal(0, triggeredJobs.Length); }, 100, 500); }); }
/// <summary> /// This method tries to send the deployment status update through frontend to be saved to db /// Since frontend throttling is in place, we retry 3 times with 5 sec gaps in between /// </summary> /// <param name="updateStatusObj">Obj containing status to save to DB</param> /// <returns></returns> private async Task SendDeployStatusUpdate(DeployStatusApiResult updateStatusObj) { int attemptCount = 0; try { await OperationManager.AttemptAsync(async() => { attemptCount++; _tracer.Trace($" PostAsync - Trying to send {updateStatusObj.DeploymentStatus} deployment status to {Constants.UpdateDeployStatusPath}"); await PostDeploymentHelper.PostAsync(Constants.UpdateDeployStatusPath, _environment.RequestId, JsonConvert.SerializeObject(updateStatusObj)); }, 3, 5 *1000); } catch (Exception ex) { _tracer.TraceError($"Failed to request a post deployment status. Number of attempts: {attemptCount}. Exception: {ex}"); throw; } }
private static Task DeleteSiteAsync(ServerManager iis, string siteName, bool deletePhysicalFiles = true) { var site = iis.Sites[siteName]; if (site != null) { return(OperationManager.AttemptAsync(async() => { await Task.Run(() => { if (deletePhysicalFiles) { string physicalPath = site.Applications[0].VirtualDirectories[0].PhysicalPath; DeleteSafe(physicalPath); } iis.Sites.Remove(site); }); })); } return(Task.FromResult(0)); }
public static async Task <BaseApp> CreateApp(HttpClient client, MyConfig config, ILogger <AppManager> logger, string appName) { return(await OperationManager.AttemptAsync(async() => { using (var response = await client.PutAsJsonAsync( $"/subscriptions/{config.Subscription}/resourceGroups/{config.ResourceGroup}/providers/Microsoft.Web/sites/{appName}?api-version=2016-03-01", new { location = config.Region, kind = "functionapp", properties = new { siteConfig = new { appSettings = new[] { new { name = "FUNCFILE", value = "D:/local/funclite/index.js" } } } } })) { response.EnsureSuccessStatusCode(); logger.LogInformation($"App {appName} was created successfully"); var json = await response.Content.ReadAsAsync <dynamic>(); var app = new WindowsApp(client, config, logger, json.properties); await app.CompleteCreation(); return app; } }, 5, 2000)); }
private static async Task UpdateWebsiteRunFromPackageAppSetting(DeploymentContext context, CloudBlockBlob blob) { context.Logger.Log($"Updating WEBSITE_RUN_FROM_PACKAGE app setting for linux consumption app..."); SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy(); sasConstraints.SharedAccessStartTime = DateTimeOffset.UtcNow.AddMinutes(-5); sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddYears(10); sasConstraints.Permissions = SharedAccessBlobPermissions.Read; string token = blob.GetSharedAccessSignature(sasConstraints); string sas = blob.Uri + token; try { await OperationManager.AttemptAsync(async() => { await PostDeploymentHelper.UpdateWebsiteRunFromPackage(sas, context); }, retries : 3, delayBeforeRetry : 2000); } catch (ArgumentException ae) { context.Logger.Log($"Set run from package has malformed blob sas {ae.Message}"); throw new DeploymentFailedException(ae); } catch (HttpRequestException hre) { context.Logger.Log($"Set run from package endpoint responded with {hre.Message}"); Exception innerException = hre.InnerException; while (innerException != null) { context.Logger.Log($"Inner Exception = {innerException.Message}"); innerException = innerException.InnerException; } throw new DeploymentFailedException(hre); } }
public static async Task <HttpContent> GetZipContentFromURL(ZipDeploymentInfo zipDeploymentInfo, ITracer tracer) { using (var client = new HttpClient(new HttpClientHandler())) { Uri uri = new Uri(zipDeploymentInfo.ZipURL); using (tracer.Step("Trying to make a GET request to {0}", uri.AbsoluteUri)) { try { return(await OperationManager.AttemptAsync <HttpContent>(async() => { HttpResponseMessage response = await client.GetAsync(uri); response.EnsureSuccessStatusCode(); return response.Content; })); } catch (Exception ex) { tracer.TraceError(ex, "Could not make a successful GET request to {0}", uri.AbsoluteUri); throw; } } } }
public async Task <Site> CreateSiteAsync(string applicationName) { using (ServerManager iis = GetServerManager()) { try { var siteBindingCongfigs = new List <IBindingConfiguration>(); var svcSiteBindingCongfigs = new List <IBindingConfiguration>(); if (_context.Configuration != null && _context.Configuration.Bindings != null) { siteBindingCongfigs = _context.Configuration.Bindings.Where(b => b.SiteType == SiteType.Live).ToList(); svcSiteBindingCongfigs = _context.Configuration.Bindings.Where(b => b.SiteType == SiteType.Service).ToList(); } // Determine the host header values List <BindingInformation> siteBindings = BuildDefaultBindings(applicationName, siteBindingCongfigs).ToList(); List <BindingInformation> serviceSiteBindings = BuildDefaultBindings(applicationName, svcSiteBindingCongfigs).ToList(); // Create the service site for this site var serviceSite = CreateSiteAsync(iis, applicationName, GetServiceSite(applicationName), _context.Configuration.ServiceSitePath, serviceSiteBindings); // Create the main site string siteName = GetLiveSite(applicationName); string root = _context.Paths.GetApplicationPath(applicationName); string siteRoot = _context.Paths.GetLiveSitePath(applicationName); string webRoot = Path.Combine(siteRoot, Constants.WebRoot); FileSystemHelpers.EnsureDirectory(webRoot); File.WriteAllText(Path.Combine(webRoot, HostingStartHtml), HostingStartHtmlContents); var site = CreateSiteAsync(iis, applicationName, siteName, webRoot, siteBindings); // Map a path called _app to the site root under the service site MapServiceSitePath(iis, applicationName, Constants.MappedSite, root); // Commit the changes to iis iis.CommitChanges(); var serviceUrls = serviceSite.Bindings .Select(url => String.Format("{0}://{1}:{2}/", url.Protocol, String.IsNullOrEmpty(url.Host) ? "localhost" : url.Host, url.EndPoint.Port)) .ToList(); // Wait for the site to start await OperationManager.AttemptAsync(() => WaitForSiteAsync(serviceUrls.First())); // Set initial ScmType state to LocalGit var settings = new RemoteDeploymentSettingsManager(serviceUrls.First() + "api/settings"); await settings.SetValue(SettingsKeys.ScmType, ScmType.LocalGit); var siteUrls = site.Bindings .Select(url => String.Format("{0}://{1}:{2}/", url.Protocol, String.IsNullOrEmpty(url.Host) ? "localhost" : url.Host, url.EndPoint.Port)) .ToList(); return(new Site { ServiceUrls = serviceUrls, SiteUrls = siteUrls }); } catch { try { DeleteSiteAsync(applicationName).Wait(); } catch { // Don't let it throw if we're unable to delete a failed creation. } throw; } } }
public async Task <Site> CreateSiteAsync(string applicationName, ICredentials credentials = null) { using (var iis = GetServerManager()) { try { // Determine the host header values List <string> siteBindings = GetDefaultBindings(applicationName, _settingsResolver.SitesBaseUrl); List <string> serviceSiteBindings = GetDefaultBindings(applicationName, _settingsResolver.ServiceSitesBaseUrl); // Create the service site for this site string serviceSiteName = GetServiceSite(applicationName); var serviceSite = CreateSiteAsync(iis, applicationName, serviceSiteName, _pathResolver.ServiceSitePath, serviceSiteBindings, _settingsResolver.ServiceSiteBasicAuth, "kudu_service"); // Create the main site string siteName = GetLiveSite(applicationName); string root = _pathResolver.GetApplicationPath(applicationName); string siteRoot = _pathResolver.GetLiveSitePath(applicationName); string webRoot = Path.Combine(siteRoot, Constants.WebRoot); FileSystemHelpers.EnsureDirectory(webRoot); File.WriteAllText(Path.Combine(webRoot, HostingStartHtml), @"<html> <head> <title>This web site has been successfully created</title> <style type=""text/css""> BODY { color: #444444; background-color: #E5F2FF; font-family: verdana; margin: 0px; text-align: center; margin-top: 100px; } H1 { font-size: 16pt; margin-bottom: 4px; } </style> </head> <body> <h1>This web site has been successfully created</h1><br/> </body> </html>"); var site = CreateSiteAsync(iis, applicationName, siteName, webRoot, siteBindings); // Map a path called _app to the site root under the service site MapServiceSitePath(iis, applicationName, Constants.MappedSite, root); // Commit the changes to iis iis.CommitChanges(); var serviceUrls = new List <Uri>(); foreach (var url in serviceSite.Bindings) { var builder = new UriBuilder { Host = String.IsNullOrEmpty(url.Host) ? "localhost" : url.Host, Scheme = url.Protocol, Port = url.EndPoint.Port == 80 ? -1 : url.EndPoint.Port }; serviceUrls.Add(builder.Uri); } // Wait for the site to start await OperationManager.AttemptAsync(() => WaitForSiteAsync(serviceUrls[0].ToString(), credentials)); // Set initial ScmType state to LocalGit var settings = new RemoteDeploymentSettingsManager(serviceUrls.First() + "api/settings", credentials: credentials); await settings.SetValue(SettingsKeys.ScmType, ScmType.LocalGit); var siteUrls = new List <Uri>(); foreach (var url in site.Bindings) { var builder = new UriBuilder { Host = String.IsNullOrEmpty(url.Host) ? "localhost" : url.Host, Scheme = url.Protocol, Port = url.EndPoint.Port == 80 ? -1 : url.EndPoint.Port }; siteUrls.Add(builder.Uri); } return(new Site { ServiceUrls = serviceUrls, SiteUrls = siteUrls }); } catch { try { DeleteSiteAsync(applicationName).Wait(); } catch { // Don't let it throw if we're unable to delete a failed creation. } throw; } } }