public async Task <string> ValidateContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Validating host assignment context (SiteId: {assignmentContext.SiteId}, SiteName: '{assignmentContext.SiteName}'. IsWarmup: '{assignmentContext.IsWarmupRequest}')"); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); _logger.LogInformation($"Will be using {pkgContext.EnvironmentVariableName} app setting as zip url. IsWarmup: '{assignmentContext.IsWarmupRequest}')"); if (pkgContext.IsScmRunFromPackage()) { // Not user assigned so limit validation return(null); } else if (!string.IsNullOrEmpty(pkgContext.Url) && pkgContext.Url != "1") { // In AppService, ZipUrl == 1 means the package is hosted in azure files. // Otherwise we expect zipUrl to be a blobUri to a zip or a squashfs image (var error, var contentLength) = await ValidateBlobPackageContext(pkgContext); if (string.IsNullOrEmpty(error)) { assignmentContext.PackageContentLength = contentLength; } return(error); } else if (!string.IsNullOrEmpty(assignmentContext.AzureFilesConnectionString)) { return(await ValidateAzureFilesContext(assignmentContext.AzureFilesConnectionString, assignmentContext.AzureFilesContentShare)); } else { _logger.LogError($"Missing ZipUrl and AzureFiles config. Continue with empty root."); return(null); } }
private async Task ApplyContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Applying {assignmentContext.Environment.Count} app setting(s)"); assignmentContext.ApplyAppSettings(_environment); // We need to get the non-PlaceholderMode script Path so we can unzip to the correct location. // This asks the factory to skip the PlaceholderMode check when configuring options. var options = _optionsFactory.Create(ScriptApplicationHostOptionsSetup.SkipPlaceholder); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); if ((pkgContext.IsScmRunFromPackage() && await pkgContext.BlobExistsAsync(_logger)) || (!pkgContext.IsScmRunFromPackage() && !string.IsNullOrEmpty(pkgContext.Url) && pkgContext.Url != "1")) { await ApplyBlobPackageContext(pkgContext, options.ScriptPath); } else if (!string.IsNullOrEmpty(assignmentContext.AzureFilesConnectionString)) { await _meshInitServiceClient.MountCifs(assignmentContext.AzureFilesConnectionString, assignmentContext.AzureFilesContentShare, "/home"); } // BYOS var storageVolumes = assignmentContext.GetBYOSEnvironmentVariables() .Select(AzureStorageInfoValue.FromEnvironmentVariable).ToList(); var mountedVolumes = (await Task.WhenAll(storageVolumes.Where(v => v != null).Select(MountStorageAccount))).Where( result => result).ToList(); if (mountedVolumes.Count != storageVolumes.Count) { _logger.LogWarning( $"Successfully mounted {mountedVolumes.Count} / {storageVolumes.Count} BYOS storage accounts"); } }
private async Task ApplyContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Applying {assignmentContext.Environment.Count} app setting(s)"); assignmentContext.ApplyAppSettings(_environment); // We need to get the non-PlaceholderMode script Path so we can unzip to the correct location. // This asks the factory to skip the PlaceholderMode check when configuring options. var options = _optionsFactory.Create(ScriptApplicationHostOptionsSetup.SkipPlaceholder); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); if ((pkgContext.IsScmRunFromPackage() && await pkgContext.BlobExistsAsync(_logger)) || (!pkgContext.IsScmRunFromPackage() && !string.IsNullOrEmpty(pkgContext.Url) && pkgContext.Url != "1")) { await ApplyBlobPackageContext(pkgContext, options.ScriptPath); } else if (!string.IsNullOrEmpty(assignmentContext.AzureFilesConnectionString)) { await MountCifs(assignmentContext.AzureFilesConnectionString, assignmentContext.AzureFilesContentShare, "/home"); } // Irrespective of deployment mechanism mount the share for user data files. if (assignmentContext.IsUserDataMountEnabled()) { if (!string.IsNullOrEmpty(assignmentContext.AzureFilesConnectionString) && !string.IsNullOrEmpty(assignmentContext.AzureFilesContentShare)) { await MountUserData(assignmentContext); } else { _logger.LogWarning( $"{EnvironmentSettingNames.AzureFilesConnectionString} or {EnvironmentSettingNames.AzureFilesContentShare} is empty. User data share will not be mounted"); } } }
public bool StartAssignment(HostAssignmentContext context) { if (!_webHostEnvironment.InStandbyMode) { // This is only true when specializing pinned containers. if (!context.Environment.TryGetValue(EnvironmentSettingNames.ContainerStartContext, out string startContext)) { _logger.LogError("Assign called while host is not in placeholder mode and start context is not present."); return(false); } } if (_environment.IsContainerReady()) { _logger.LogError("Assign called while container is marked as specialized."); return(false); } if (context.IsWarmupRequest) { // Based on profiling download code jit-ing holds up cold start. // Pre-jit to avoid paying the cost later. Task.Run(async() => await Download(context.GetRunFromPkgContext())); return(true); } else if (_assignmentContext == null) { lock (_assignmentLock) { if (_assignmentContext != null) { return(_assignmentContext.Equals(context)); } _assignmentContext = context; } _logger.LogInformation($"Starting Assignment. Cloud Name: {_environment.GetCloudName()}"); // set a flag which will cause any incoming http requests to buffer // until specialization is complete // the host is guaranteed not to receive any requests until AFTER assign // has been initiated, so setting this flag here is sufficient to ensure // that any subsequent incoming requests while the assign is in progress // will be delayed until complete _webHostEnvironment.DelayRequests(); // start the specialization process in the background Task.Run(async() => await Assign(context)); return(true); } else { // No lock needed here since _assignmentContext is not null when we are here return(_assignmentContext.Equals(context)); } }
public async Task <string> ValidateContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Validating host assignment context (SiteId: {assignmentContext.SiteId}, SiteName: '{assignmentContext.SiteName}'. IsWarmup: '{assignmentContext.IsWarmupRequest}')"); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); _logger.LogInformation($"Will be using {pkgContext.EnvironmentVariableName} app setting as zip url. IsWarmup: '{assignmentContext.IsWarmupRequest}')"); if (pkgContext.IsScmRunFromPackage()) { // Not user assigned so limit validation return(null); } else if (!string.IsNullOrEmpty(pkgContext.Url) && pkgContext.Url != "1") { if (Uri.TryCreate(pkgContext.Url, UriKind.Absolute, out var uri)) { if (Utility.IsResourceAzureBlobWithoutSas(uri)) { // Note: this also means we skip validation for publicly available blobs _logger.LogDebug("Skipping validation for '{pkgContext.EnvironmentVariableName}' with no SAS token", pkgContext.EnvironmentVariableName); return(null); } else { // In AppService, ZipUrl == 1 means the package is hosted in azure files. // Otherwise we expect zipUrl to be a blobUri to a zip or a squashfs image var(error, contentLength) = await ValidateBlobPackageContext(pkgContext); if (string.IsNullOrEmpty(error)) { assignmentContext.PackageContentLength = contentLength; } return(error); } } else { var invalidUrlError = $"Invalid url for specified for {pkgContext.EnvironmentVariableName}"; _logger.LogError(invalidUrlError); // For now we return null here instead of the actual error since this validation is new. // Eventually this could return the error message. return(null); } } else if (!string.IsNullOrEmpty(assignmentContext.AzureFilesConnectionString)) { return(await ValidateAzureFilesContext(assignmentContext.AzureFilesConnectionString, assignmentContext.AzureFilesContentShare)); } else { _logger.LogError("Missing ZipUrl and AzureFiles config. Continue with empty root."); return(null); } }
public async Task <string> ValidateContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Validating host assignment context (SiteId: {assignmentContext.SiteId}, SiteName: '{assignmentContext.SiteName}')"); string error = null; HttpResponseMessage response = null; try { RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); _logger.LogInformation($"Will be using {pkgContext.EnvironmentVariableName} app setting as zip url"); if (pkgContext.IsScmRunFromPackage()) { // Not user assigned so limit validation return(null); } var zipUrl = pkgContext.Url; if (!string.IsNullOrEmpty(zipUrl)) { // make sure the zip uri is valid and accessible await Utility.InvokeWithRetriesAsync(async() => { try { using (_metricsLogger.LatencyEvent(MetricEventNames.LinuxContainerSpecializationZipHead)) { var request = new HttpRequestMessage(HttpMethod.Head, zipUrl); response = await _client.SendAsync(request); response.EnsureSuccessStatusCode(); } } catch (Exception e) { _logger.LogError(e, $"{MetricEventNames.LinuxContainerSpecializationZipHead} failed"); throw; } }, maxRetries : 2, retryInterval : TimeSpan.FromSeconds(0.3)); // Keep this less than ~1s total } } catch (Exception e) { error = $"Invalid zip url specified (StatusCode: {response?.StatusCode})"; _logger.LogError(e, "ValidateContext failed"); } return(error); }
private async Task ApplyContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Applying {assignmentContext.Environment.Count} app setting(s)"); assignmentContext.ApplyAppSettings(_environment); // We need to get the non-PlaceholderMode script Path so we can unzip to the correct location. // This asks the factory to skip the PlaceholderMode check when configuring options. var options = _optionsFactory.Create(ScriptApplicationHostOptionsSetup.SkipPlaceholder); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); var zipPath = pkgContext.Url; if (!string.IsNullOrEmpty(zipPath)) { // download zip and extract var zipUri = new Uri(zipPath); string filePath = null; if (pkgContext.IsScmRunFromPackage()) { bool blobExists = await pkgContext.BlobExistsAsync(_logger); if (blobExists) { filePath = await DownloadAsync(zipUri); } else { return; } } else { filePath = await DownloadAsync(zipUri); } UnpackPackage(filePath, options.ScriptPath); string bundlePath = Path.Combine(options.ScriptPath, "worker-bundle"); if (Directory.Exists(bundlePath)) { _logger.LogInformation($"Python worker bundle detected"); } } }
private async Task ApplyContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Applying {assignmentContext.Environment.Count} app setting(s)"); assignmentContext.ApplyAppSettings(_environment); // We need to get the non-PlaceholderMode script Path so we can unzip to the correct location. // This asks the factory to skip the PlaceholderMode check when configuring options. var options = _optionsFactory.Create(ScriptApplicationHostOptionsSetup.SkipPlaceholder); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); if ((pkgContext.IsScmRunFromPackage() && await pkgContext.BlobExistsAsync(_logger)) || (!pkgContext.IsScmRunFromPackage() && !string.IsNullOrEmpty(pkgContext.Url) && pkgContext.Url != "1")) { await ApplyBlobPackageContext(pkgContext, options.ScriptPath); } else if (!string.IsNullOrEmpty(assignmentContext.AzureFilesConnectionString)) { ApplyAzureFilesContext(assignmentContext.AzureFilesConnectionString, assignmentContext.AzureFilesContentShare, "/home"); } }
private async Task ApplyContext(HostAssignmentContext assignmentContext) { _logger.LogInformation($"Applying {assignmentContext.Environment.Count} app setting(s)"); assignmentContext.ApplyAppSettings(_environment, _logger); // We need to get the non-PlaceholderMode script Path so we can unzip to the correct location. // This asks the factory to skip the PlaceholderMode check when configuring options. var options = _optionsFactory.Create(ScriptApplicationHostOptionsSetup.SkipPlaceholder); RunFromPackageContext pkgContext = assignmentContext.GetRunFromPkgContext(); if (_environment.SupportsAzureFileShareMount()) { var azureFilesMounted = false; if (assignmentContext.IsAzureFilesContentShareConfigured(_logger)) { azureFilesMounted = await _runFromPackageHandler.MountAzureFileShare(assignmentContext); } else { _logger.LogError( $"No {nameof(EnvironmentSettingNames.AzureFilesConnectionString)} or {nameof(EnvironmentSettingNames.AzureFilesContentShare)} configured. Azure FileShare will not be mounted. For PowerShell Functions, Managed Dependencies will not persisted across functions host instances."); } if (pkgContext.IsRunFromPackage(options, _logger)) { if (azureFilesMounted) { _logger.LogWarning("App is configured to use both Run-From-Package and AzureFiles. Run-From-Package will take precedence"); } var blobContextApplied = await _runFromPackageHandler.ApplyBlobPackageContext(pkgContext, options.ScriptPath, azureFilesMounted, false); if (!blobContextApplied && azureFilesMounted) { _logger.LogWarning($"Failed to {nameof(_runFromPackageHandler.ApplyBlobPackageContext)}. Attempting to use local disk instead"); await _runFromPackageHandler.ApplyBlobPackageContext(pkgContext, options.ScriptPath, false); } } else { _logger.LogInformation($"No {nameof(EnvironmentSettingNames.AzureWebsiteRunFromPackage)} configured"); } } else { if (pkgContext.IsRunFromPackage(options, _logger)) { await _runFromPackageHandler.ApplyBlobPackageContext(pkgContext, options.ScriptPath, false); } else if (assignmentContext.IsAzureFilesContentShareConfigured(_logger)) { await _runFromPackageHandler.MountAzureFileShare(assignmentContext); } } // BYOS var storageVolumes = assignmentContext.GetBYOSEnvironmentVariables() .Select(AzureStorageInfoValue.FromEnvironmentVariable).ToList(); var mountedVolumes = (await Task.WhenAll(storageVolumes.Where(v => v != null).Select(MountStorageAccount))).Where( result => result).ToList(); if (storageVolumes.Any()) { if (mountedVolumes.Count != storageVolumes.Count) { _logger.LogWarning( $"Successfully mounted {mountedVolumes.Count} / {storageVolumes.Count} BYOS storage accounts"); } else { _logger.LogInformation( $"Successfully mounted {storageVolumes.Count} BYOS storage accounts"); } } }