private async Task PreRunConditions() { if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.python) { var pythonVersion = await PythonHelpers.GetEnvironmentPythonVersion(); PythonHelpers.AssertPythonVersion(pythonVersion, errorIfNotSupported: true, errorIfNoVersion: true); PythonHelpers.SetWorkerPath(pythonVersion?.ExecutablePath, overwrite: false); PythonHelpers.SetWorkerRuntimeVersionPython(pythonVersion); } else if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.dotnet && !NoBuild) { if (DotnetHelpers.CanDotnetBuild()) { var outputPath = Path.Combine("bin", "output"); await DotnetHelpers.BuildDotnetProject(outputPath, string.Empty); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, outputPath); } else if (StaticSettings.IsDebug) { ColoredConsole.WriteLine("Could not find a valid .csproj file. Skipping the build."); } } else if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.powershell && !CommandChecker.CommandExists("dotnet")) { throw new CliException("Dotnet is required for PowerShell Functions. Please install dotnet (.NET Core SDK) for your system from https://www.microsoft.com/net/download"); } if (!NetworkHelpers.IsPortAvailable(Port)) { throw new CliException($"Port {Port} is unavailable. Close the process using that port, or specify another port using --port [-p]."); } }
private async Task InitLanguageSpecificArtifacts(WorkerRuntime workerRuntime) { if (workerRuntime == Helpers.WorkerRuntime.python) { await PythonHelpers.InstallPackage(); } }
private void PreRunConditions() { if (_secretsManager.GetSecrets().Any(p => p.Key == Constants.FunctionsWorkerRuntime && p.Value == "Python")) { PythonHelpers.VerifyVirtualEnvironment(); } }
private async Task PreRunConditions(WorkerRuntime workerRuntime) { if (workerRuntime == WorkerRuntime.python) { PythonHelpers.VerifyVirtualEnvironment(); } else if (workerRuntime == WorkerRuntime.dotnet && !NoBuild) { if (DotnetHelpers.CanDotnetBuild()) { var outputPath = Path.Combine("bin", "output"); await DotnetHelpers.BuildDotnetProject(outputPath, string.Empty); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, outputPath); } else if (StaticSettings.IsDebug) { ColoredConsole.WriteLine("Could not find a valid .csproj file. Skipping the build."); } } if (!NetworkHelpers.IsPortAvailable(Port)) { throw new CliException($"Port {Port} is unavailable. Close the process using that port, or specify another port using --port [-p]."); } }
private async Task InitLanguageSpecificArtifacts(string language) { if (language == "Python") { await PythonHelpers.InstallPackage(); } }
/// <summary> /// Handler for Linux Consumption publish event /// </summary> /// <param name="functionApp">Function App in Azure</param> /// <param name="zipFileFactory">Factory for local project zipper</param> /// <returns>ShouldSyncTrigger value</returns> private async Task <bool> HandleLinuxConsumptionPublish(Site functionApp, Func <Task <Stream> > zipFileFactory) { string fileNameNoExtension = string.Format("{0}-{1}", DateTimeOffset.UtcNow.ToString("yyyyMMddHHmmss"), Guid.NewGuid()); // Consumption Linux, try squashfs as a package format. if (PublishBuildOption == BuildOption.Remote) { await EnsureRemoteBuildIsSupported(functionApp); await RemoveFunctionAppAppSetting(functionApp, Constants.WebsiteRunFromPackage, Constants.WebsiteContentAzureFileConnectionString, Constants.WebsiteContentShared); Task <DeployStatus> pollConsumptionBuild(HttpClient client) => KuduLiteDeploymentHelpers.WaitForRemoteBuild(client, functionApp); var deployStatus = await PerformServerSideBuild(functionApp, zipFileFactory, pollConsumptionBuild); return(deployStatus == DeployStatus.Success); } else if (PublishBuildOption == BuildOption.Local) { await PublishRunFromPackage(functionApp, await zipFileFactory(), $"{fileNameNoExtension}.zip"); return(true); } else if (GlobalCoreToolsSettings.CurrentWorkerRuntimeOrNone == WorkerRuntime.python && !NoBuild && BuildNativeDeps) { await PublishRunFromPackage(functionApp, await PythonHelpers.ZipToSquashfsStream(await zipFileFactory()), $"{fileNameNoExtension}.squashfs"); return(true); } else { await PublishRunFromPackage(functionApp, await zipFileFactory(), $"{fileNameNoExtension}.zip"); return(true); } }
private static async Task InitLanguageSpecificArtifacts(WorkerRuntime workerRuntime, string language, bool managedDependenciesOption) { if (workerRuntime == Helpers.WorkerRuntime.python) { await PythonHelpers.SetupPythonProject(); } else if (workerRuntime == Helpers.WorkerRuntime.powershell) { await WriteFiles("profile.ps1", await StaticResources.PowerShellProfilePs1); if (managedDependenciesOption) { string majorVersion = await PowerShellHelper.GetLatestAzModuleMajorVersion(); var requirementsContent = await StaticResources.PowerShellRequirementsPsd1; requirementsContent = requirementsContent.Replace("MAJOR_VERSION", majorVersion); await WriteFiles("requirements.psd1", requirementsContent); } } else if (workerRuntime == Helpers.WorkerRuntime.node) { if (language == Constants.Languages.TypeScript) { await WriteFiles(".funcignore", await StaticResources.FuncIgnore); await WriteFiles("package.json", await StaticResources.PackageJson); await WriteFiles("tsconfig.json", await StaticResources.TsConfig); } else { await WriteFiles("package.json", await StaticResources.JavascriptPackageJson); } } }
private static async Task InitLanguageSpecificArtifacts(WorkerRuntime workerRuntime, string language, bool managedDependenciesOption) { if (workerRuntime == Helpers.WorkerRuntime.python) { await PythonHelpers.SetupPythonProject(); } else if (workerRuntime == Helpers.WorkerRuntime.powershell) { await WriteFiles("profile.ps1", await StaticResources.PowerShellProfilePs1); if (managedDependenciesOption) { string majorVersion = null; bool failedToGetModuleVersion = false; try { majorVersion = await PowerShellHelper.GetLatestAzModuleMajorVersion(); } catch { failedToGetModuleVersion = true; } string guidance = null; var requirementsContent = await StaticResources.PowerShellRequirementsPsd1; if (failedToGetModuleVersion) { guidance = "Uncomment the next line and replace the MAJOR_VERSION, e.g., 'Az' = '2.*'"; var warningMsg = "Failed to get Az module version. Edit the requirements.psd1 file when the powershellgallery.com is accessible."; ColoredConsole.WriteLine(WarningColor(warningMsg)); } else { guidance = string.Empty; requirementsContent = requirementsContent.Replace("# 'Az'", "'Az'"); requirementsContent = requirementsContent.Replace("MAJOR_VERSION", majorVersion); } requirementsContent = requirementsContent.Replace("[GUIDANCE]", guidance); await WriteFiles("requirements.psd1", requirementsContent); } } else if (workerRuntime == Helpers.WorkerRuntime.node) { if (language == Constants.Languages.TypeScript) { await WriteFiles(".funcignore", await StaticResources.FuncIgnore); await WriteFiles("package.json", await StaticResources.PackageJson); await WriteFiles("tsconfig.json", await StaticResources.TsConfig); } else { await WriteFiles("package.json", await StaticResources.JavascriptPackageJson); } } }
public async void WorkerInfoRuntimeShouldBePython() { WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion(); if (worker.Runtime != WorkerRuntime.python) { throw new Exception("Worker runtime should always be python"); } }
public async void InterpreterShouldHaveExecutablePath() { WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion(); if (worker.ExecutablePath == null) { throw new Exception("Python executable path should not be empty"); } }
public async void InterpreterShouldHaveMajorVersion() { WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion(); if (worker.Major != 2 && worker.Major != 3) { throw new Exception("Python major version should be 2 or 3"); } }
public override async Task RunAsync() { var functionAppRoot = string.IsNullOrEmpty(FolderName) ? Path.Combine(Environment.CurrentDirectory, FolderName) : ScriptHostHelpers.GetFunctionAppRootDirectory(Environment.CurrentDirectory); string outputPath; if (string.IsNullOrEmpty(OutputPath)) { outputPath = Path.Combine(Environment.CurrentDirectory, $"{Path.GetFileName(functionAppRoot)}"); } else { outputPath = Path.Combine(Environment.CurrentDirectory, OutputPath); if (FileSystemHelpers.DirectoryExists(outputPath)) { outputPath = Path.Combine(outputPath, $"{Path.GetFileName(functionAppRoot)}"); } } if (!FileSystemHelpers.FileExists(Path.Combine(functionAppRoot, ScriptConstants.HostMetadataFileName))) { throw new CliException($"Can't find {Path.Combine(functionAppRoot, ScriptConstants.HostMetadataFileName)}"); } var workerRuntime = WorkerRuntimeLanguageHelper.GetCurrentWorkerRuntimeLanguage(_secretsManager); outputPath += Squashfs ? ".squashfs" : ".zip"; if (FileSystemHelpers.FileExists(outputPath)) { ColoredConsole.WriteLine($"Deleting the old package {outputPath}"); try { FileSystemHelpers.FileDelete(outputPath); } catch (Exception) { throw new CliException($"Could not delete {outputPath}"); } } // Restore all valid extensions var installExtensionAction = new InstallExtensionAction(_secretsManager, false); await installExtensionAction.RunAsync(); var stream = await ZipHelper.GetAppZipFile(functionAppRoot, BuildNativeDeps, noBuild : false, buildOption : BuildOption.Default, additionalPackages : AdditionalPackages); if (Squashfs) { stream = await PythonHelpers.ZipToSquashfsStream(stream); } ColoredConsole.WriteLine($"Creating a new package {outputPath}"); await FileSystemHelpers.WriteToFile(outputPath, stream); }
private async Task InitLanguageSpecificArtifacts(WorkerRuntime workerRuntime) { if (workerRuntime == Helpers.WorkerRuntime.python) { await PythonHelpers.InstallPackage(); } else if (workerRuntime == Helpers.WorkerRuntime.powershell) { await WriteFiles("profile.ps1", await StaticResources.PowerShellProfilePs1); } }
private static async Task WritePythonDockerFile() { WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion(); if (worker?.Major == 3 && worker?.Minor == 7) { await WriteFiles("Dockerfile", await StaticResources.DockerfilePython37); } else { await WriteFiles("Dockerfile", await StaticResources.DockerfilePython36); } }
private async Task PreRunConditions(WorkerRuntime workerRuntime) { if (workerRuntime == WorkerRuntime.python) { PythonHelpers.VerifyVirtualEnvironment(); } else if (workerRuntime == WorkerRuntime.dotnet && Build) { const string outputPath = "bin/output"; await DotnetHelpers.BuildDotnetProject(outputPath); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, outputPath); } }
private async Task InitLanguageSpecificArtifacts(WorkerRuntime workerRuntime) { if (workerRuntime == Helpers.WorkerRuntime.python) { await PythonHelpers.InstallPackage(); } else if (workerRuntime == Helpers.WorkerRuntime.powershell) { await WriteFiles("profile.ps1", await StaticResources.PowerShellProfilePs1); } if (Language == Constants.Languages.TypeScript) { await WriteFiles(".funcignore", await StaticResources.FuncIgnore); await WriteFiles("package.json", await StaticResources.PackageJson); await WriteFiles("tsconfig.json", await StaticResources.TsConfig); } }
public static async Task <Stream> GetAppZipFile(WorkerRuntime workerRuntime, string functionAppRoot, GitIgnoreParser ignoreParser = null) { var gitIgnorePath = Path.Combine(functionAppRoot, Constants.FuncIgnoreFile); if (ignoreParser == null && FileSystemHelpers.FileExists(gitIgnorePath)) { ignoreParser = new GitIgnoreParser(await FileSystemHelpers.ReadAllTextFromFileAsync(gitIgnorePath)); } if (workerRuntime == WorkerRuntime.python) { return(await PythonHelpers.GetPythonDeploymentPackage(GetLocalFiles(functionAppRoot, ignoreParser), functionAppRoot)); } else { return(CreateZip(GetLocalFiles(functionAppRoot, ignoreParser), functionAppRoot)); } }
private async Task InternalPublishFunctionApp(GitIgnoreParser ignoreParser) { ColoredConsole.WriteLine("Getting site publishing info..."); var functionApp = await _armManager.GetFunctionAppAsync(FunctionAppName); var functionAppRoot = ScriptHostHelpers.GetFunctionAppRootDirectory(Environment.CurrentDirectory); if (functionApp.IsLinux && !functionApp.IsDynamicLinux && RunFromZipDeploy) { ColoredConsole .WriteLine(ErrorColor("--zip is not supported with dedicated linux apps.")); return; } var workerRuntime = _secretsManager.GetSecrets().FirstOrDefault(s => s.Key.Equals(Constants.FunctionsWorkerRuntime, StringComparison.OrdinalIgnoreCase)).Value; if (!string.IsNullOrWhiteSpace(workerRuntime)) { var worker = WorkerRuntimeLanguageHelper.NormalizeWorkerRuntime(workerRuntime); if (worker == WorkerRuntime.python) { if (!SkipWheelRestore) { await PythonHelpers.InstallPipWheel(); await PythonHelpers.DownloadWheels(); } else { ColoredConsole.WriteLine("Skipping wheels download"); } } } // if consumption linux, or --zip, run from zip if (functionApp.IsDynamicLinux || RunFromZipDeploy) { await PublishRunFromZip(functionApp, functionAppRoot, ignoreParser); } else { await PublishZipDeploy(functionApp, functionAppRoot, ignoreParser); } }
private async Task PreRunConditions(WorkerRuntime workerRuntime) { if (workerRuntime == WorkerRuntime.python) { PythonHelpers.VerifyVirtualEnvironment(); } else if (workerRuntime == WorkerRuntime.dotnet && Build) { const string outputPath = "bin/output"; await DotnetHelpers.BuildDotnetProject(outputPath, string.Empty); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, outputPath); } if (!NetworkHelpers.IsPortAvailable(Port)) { throw new CliException($"Port {Port} is unavailable. Close the process using that port, or specify another port using --port [-p]."); } }
private async Task PreRunConditions() { if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.python) { await PythonHelpers.ValidatePythonVersion(setWorkerExecutable : true, errorIfNoExactMatch : true, errorOutIfOld : true); // We need to update the PYTHONPATH to add worker's dependencies var pythonPath = Environment.GetEnvironmentVariable("PYTHONPATH") ?? string.Empty; var pythonWorkerDeps = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "workers", "python", "deps"); if (!pythonPath.Contains(pythonWorkerDeps)) { Environment.SetEnvironmentVariable("PYTHONPATH", $"{pythonPath}{Path.PathSeparator}{pythonWorkerDeps}", EnvironmentVariableTarget.Process); } if (StaticSettings.IsDebug) { ColoredConsole.WriteLine($"PYTHONPATH for the process is: {Environment.GetEnvironmentVariable("PYTHONPATH")}"); } } else if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.dotnet && !NoBuild) { if (DotnetHelpers.CanDotnetBuild()) { var outputPath = Path.Combine("bin", "output"); await DotnetHelpers.BuildDotnetProject(outputPath, string.Empty); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, outputPath); } else if (StaticSettings.IsDebug) { ColoredConsole.WriteLine("Could not find a valid .csproj file. Skipping the build."); } } else if (GlobalCoreToolsSettings.CurrentWorkerRuntime == WorkerRuntime.powershell && !CommandChecker.CommandExists("dotnet")) { throw new CliException("Dotnet is required for PowerShell Functions. Please install dotnet (.NET Core SDK) for your system from https://www.microsoft.com/net/download"); } if (!NetworkHelpers.IsPortAvailable(Port)) { throw new CliException($"Port {Port} is unavailable. Close the process using that port, or specify another port using --port [-p]."); } }
public async Task init_with_python_Dockerfile() { WorkerLanguageVersionInfo worker = await PythonHelpers.GetEnvironmentPythonVersion(); Skip.If(worker == null); await CliTester.Run(new RunConfiguration { Commands = new[] { $"init . --worker-runtime python --docker" }, CheckFiles = new[] { new FileResult { Name = "Dockerfile", ContentContains = new[] { $"FROM mcr.microsoft.com/azure-functions/python:2.0-python{worker.Major}.{worker.Minor}" } } }, OutputContains = new[] { "Dockerfile" } }, _output); }
/// <summary> /// Handler for Linux Consumption publish event /// </summary> /// <param name="functionAppRoot">Function App project path in local machine</param> /// <param name="functionApp">Function App in Azure</param> /// <param name="fileNameNoExtension">Name of the file to be uploaded</param> /// <returns>ShouldSyncTrigger value</returns> private async Task <bool> HandleLinuxConsumptionPublish(string functionAppRoot, Site functionApp, string fileNameNoExtension) { // Choose if the content need to use remote build BuildOption buildOption = PublishHelper.UpdateLinuxConsumptionBuildOption(PublishBuildOption); GitIgnoreParser ignoreParser = PublishHelper.GetIgnoreParser(functionAppRoot); // We update the buildOption, so we need to update the zipFileStream factory as well Func <Task <Stream> > zipFileStreamTask = () => ZipHelper.GetAppZipFile(functionAppRoot, BuildNativeDeps, buildOption, NoBuild, ignoreParser, AdditionalPackages, ignoreDotNetCheck: true); // Consumption Linux, try squashfs as a package format. if (GlobalCoreToolsSettings.CurrentWorkerRuntimeOrNone == WorkerRuntime.python && !NoBuild && (BuildNativeDeps || buildOption == BuildOption.Remote)) { if (BuildNativeDeps) { await PublishRunFromPackage(functionApp, await PythonHelpers.ZipToSquashfsStream(await zipFileStreamTask()), $"{fileNameNoExtension}.squashfs"); return(true); } // Remote build don't need sync trigger, container will be deallocated once the build is finished if (buildOption == BuildOption.Remote) { await RemoveFunctionAppAppSetting(functionApp, "WEBSITE_RUN_FROM_PACKAGE", "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "WEBSITE_CONTENTSHARE"); Task <DeployStatus> pollConsumptionBuild(HttpClient client) => KuduLiteDeploymentHelpers.WaitForConsumptionServerSideBuild(client, functionApp, AccessToken, ManagementURL); var deployStatus = await PerformServerSideBuild(functionApp, zipFileStreamTask, pollConsumptionBuild); return(deployStatus == DeployStatus.Success); } } else { await PublishRunFromPackage(functionApp, await zipFileStreamTask(), $"{fileNameNoExtension}.zip"); return(true); } return(true); }
private async Task PreRunConditions(WorkerRuntime workerRuntime) { if (workerRuntime == WorkerRuntime.python) { await PythonHelpers.VerifyPythonVersions(setWorkerExecutable : true); // We need to update the PYTHONPATH to add worker's dependencies var pythonPath = Environment.GetEnvironmentVariable("PYTHONPATH") ?? string.Empty; var pythonWorkerDeps = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "workers", "python", "deps"); if (!pythonPath.Contains(pythonWorkerDeps)) { Environment.SetEnvironmentVariable("PYTHONPATH", $"{pythonWorkerDeps}{Path.PathSeparator}{pythonPath}", EnvironmentVariableTarget.Process); } if (StaticSettings.IsDebug) { ColoredConsole.WriteLine($"PYTHONPATH for the process is: {Environment.GetEnvironmentVariable("PYTHONPATH")}"); } } else if (workerRuntime == WorkerRuntime.dotnet && !NoBuild) { if (DotnetHelpers.CanDotnetBuild()) { var outputPath = Path.Combine("bin", "output"); await DotnetHelpers.BuildDotnetProject(outputPath, string.Empty); Environment.CurrentDirectory = Path.Combine(Environment.CurrentDirectory, outputPath); } else if (StaticSettings.IsDebug) { ColoredConsole.WriteLine("Could not find a valid .csproj file. Skipping the build."); } } if (!NetworkHelpers.IsPortAvailable(Port)) { throw new CliException($"Port {Port} is unavailable. Close the process using that port, or specify another port using --port [-p]."); } }
/// <summary> /// Handler for Linux Consumption publish event /// </summary> /// <param name="functionApp">Function App in Azure</param> /// <param name="zipFileFactory">Factory for local project zipper</param> /// <returns>ShouldSyncTrigger value</returns> private async Task <bool> HandleLinuxConsumptionPublish(Site functionApp, Func <Task <Stream> > zipFileFactory) { string fileNameNoExtension = string.Format("{0}-{1}", DateTimeOffset.UtcNow.ToString("yyyyMMddHHmmss"), Guid.NewGuid()); // Consumption Linux, try squashfs as a package format. if (PublishBuildOption == BuildOption.Remote) { await RemoveFunctionAppAppSetting(functionApp, "WEBSITE_RUN_FROM_PACKAGE", "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "WEBSITE_CONTENTSHARE"); Task <DeployStatus> pollConsumptionBuild(HttpClient client) => KuduLiteDeploymentHelpers.WaitForConsumptionServerSideBuild(client, functionApp, AccessToken, ManagementURL); var deployStatus = await PerformServerSideBuild(functionApp, zipFileFactory, pollConsumptionBuild); return(deployStatus == DeployStatus.Success); } else if (PublishBuildOption == BuildOption.Local) { await PublishRunFromPackage(functionApp, await zipFileFactory(), $"{fileNameNoExtension}.zip"); return(true); } else if (GlobalCoreToolsSettings.CurrentWorkerRuntimeOrNone == WorkerRuntime.python && !NoBuild && BuildNativeDeps) { await PublishRunFromPackage(functionApp, await PythonHelpers.ZipToSquashfsStream(await zipFileFactory()), $"{fileNameNoExtension}.squashfs"); return(true); } else { await PublishRunFromPackage(functionApp, await zipFileFactory(), $"{fileNameNoExtension}.zip"); return(true); } }
private async Task PublishFunctionApp(Site functionApp, GitIgnoreParser ignoreParser, IDictionary <string, string> additionalAppSettings) { ColoredConsole.WriteLine("Getting site publishing info..."); var functionAppRoot = ScriptHostHelpers.GetFunctionAppRootDirectory(Environment.CurrentDirectory); // For dedicated linux apps, we do not support run from package right now var isFunctionAppDedicated = !functionApp.IsDynamic && !functionApp.IsElasticPremium; if (functionApp.IsLinux && isFunctionAppDedicated && RunFromPackageDeploy) { ColoredConsole.WriteLine("Assuming --nozip (do not run from package) for publishing to Linux dedicated plan."); RunFromPackageDeploy = false; } var workerRuntime = _secretsManager.GetSecrets().FirstOrDefault(s => s.Key.Equals(Constants.FunctionsWorkerRuntime, StringComparison.OrdinalIgnoreCase)).Value; var workerRuntimeEnum = string.IsNullOrEmpty(workerRuntime) ? WorkerRuntime.None : WorkerRuntimeLanguageHelper.NormalizeWorkerRuntime(workerRuntime); if (workerRuntimeEnum == WorkerRuntime.python && !functionApp.IsLinux) { throw new CliException("Publishing Python functions is only supported for Linux FunctionApps"); } Func <Task <Stream> > zipStreamFactory = () => ZipHelper.GetAppZipFile(workerRuntimeEnum, functionAppRoot, BuildNativeDeps, NoBuild, ignoreParser, AdditionalPackages, ignoreDotNetCheck: true); bool shouldSyncTriggers = true; var fileNameNoExtension = string.Format("{0}-{1}", DateTimeOffset.UtcNow.ToString("yyyyMMddHHmmss"), Guid.NewGuid()); if (functionApp.IsLinux && functionApp.IsDynamic) { // Consumption Linux, try squashfs as a package format. if (workerRuntimeEnum == WorkerRuntime.python && !NoBuild && BuildNativeDeps) { await PublishRunFromPackage(functionApp, await PythonHelpers.ZipToSquashfsStream(await zipStreamFactory()), $"{fileNameNoExtension}.squashfs"); } else { await PublishRunFromPackage(functionApp, await zipStreamFactory(), $"{fileNameNoExtension}.zip"); } } else if (functionApp.IsLinux && functionApp.IsElasticPremium) { // Elastic Premium Linux await PublishRunFromPackage(functionApp, await zipStreamFactory(), $"{fileNameNoExtension}.zip"); } else if (RunFromPackageDeploy) { // Windows default await PublishRunFromPackageLocal(functionApp, zipStreamFactory); } else { // ZipDeploy takes care of the SyncTriggers operation so we don't // need to perform one shouldSyncTriggers = false; // Dedicated Linux or "--no-zip" await PublishZipDeploy(functionApp, zipStreamFactory); } if (PublishLocalSettings) { await PublishLocalAppSettings(functionApp, additionalAppSettings); } else if (additionalAppSettings.Any()) { await PublishAppSettings(functionApp, new Dictionary <string, string>(), additionalAppSettings); } if (shouldSyncTriggers) { await Task.Delay(TimeSpan.FromSeconds(5)); await SyncTriggers(functionApp); } // Linux Elastic Premium functions take longer to deploy. Right now, we cannot guarantee that functions info will be most up to date. // So, we only show the info, if Function App is not Linux Elastic Premium if (!(functionApp.IsLinux && functionApp.IsElasticPremium)) { await AzureHelper.PrintFunctionsInfo(functionApp, AccessToken, ManagementURL, showKeys : true); } }
private async Task <IDictionary <string, string> > ValidateFunctionAppPublish(Site functionApp, WorkerRuntime workerRuntime) { var result = new Dictionary <string, string>(); // Check version if (!functionApp.IsLinux) { if (functionApp.AzureAppSettings.TryGetValue(Constants.FunctionsExtensionVersion, out string version)) { // v2 can be either "~2", "beta", or an exact match like "2.0.11961-alpha" if (!version.Equals("~2") && !version.StartsWith("2.0") && !version.Equals("beta", StringComparison.OrdinalIgnoreCase)) { if (Force) { result.Add(Constants.FunctionsExtensionVersion, "~2"); } else { throw new CliException("You're trying to publish to a non-v2 function app from v2 tooling.\n" + "You can pass --force to force update the app to v2, or switch to v1 or v3 tooling for publishing"); } } } } if (functionApp.AzureAppSettings.TryGetValue(Constants.FunctionsWorkerRuntime, out string workerRuntimeStr)) { var resolution = $"You can pass --force to update your Azure app with '{workerRuntime}' as a '{Constants.FunctionsWorkerRuntime}'"; try { var azureWorkerRuntime = WorkerRuntimeLanguageHelper.NormalizeWorkerRuntime(workerRuntimeStr); if (azureWorkerRuntime != workerRuntime) { if (Force) { ColoredConsole.WriteLine(WarningColor($"Setting '{Constants.FunctionsWorkerRuntime}' to '{workerRuntime}' because --force was passed")); result[Constants.FunctionsWorkerRuntime] = workerRuntime.ToString(); } else { throw new CliException($"Your Azure Function App has '{Constants.FunctionsWorkerRuntime}' set to '{azureWorkerRuntime}' while your local project is set to '{workerRuntime}'.\n" + resolution); } } } catch (ArgumentException) when(Force) { result[Constants.FunctionsWorkerRuntime] = workerRuntime.ToString(); } catch (ArgumentException) when(!Force) { throw new CliException($"Your app has an unknown {Constants.FunctionsWorkerRuntime} defined '{workerRuntimeStr}'. Only {WorkerRuntimeLanguageHelper.AvailableWorkersRuntimeString} are supported.\n" + resolution); } } if (!functionApp.AzureAppSettings.ContainsKey("AzureWebJobsStorage") && functionApp.IsDynamic) { throw new CliException($"'{FunctionAppName}' app is missing AzureWebJobsStorage app setting. That setting is required for publishing consumption linux apps."); } if (functionApp.IsLinux && !functionApp.IsDynamic && !string.IsNullOrEmpty(functionApp.LinuxFxVersion)) { // If linuxFxVersion does not match any of our images if (PublishHelper.IsLinuxFxVersionUsingCustomImage(functionApp.LinuxFxVersion)) { ColoredConsole.WriteLine($"Your functionapp is using a custom image {functionApp.LinuxFxVersion}.\nAssuming that the image contains the correct framework.\n"); } // If there the functionapp is our image but does not match the worker runtime image, we either fail or force update else if (!PublishHelper.IsLinuxFxVersionRuntimeMatched(functionApp.LinuxFxVersion, workerRuntime)) { if (Force) { var updatedSettings = new Dictionary <string, string> { [Constants.LinuxFxVersion] = $"DOCKER|{Constants.WorkerRuntimeImages.GetValueOrDefault(workerRuntime).FirstOrDefault()}" }; var settingsResult = await AzureHelper.UpdateWebSettings(functionApp, updatedSettings, AccessToken, ManagementURL); if (!settingsResult.IsSuccessful) { ColoredConsole.Error .WriteLine(ErrorColor("Error updating linux image version:")) .WriteLine(ErrorColor(settingsResult.ErrorResult)); } } else { throw new CliException($"Your Linux dedicated app has the container image version (LinuxFxVersion) set to {functionApp.LinuxFxVersion} which is not expected for the worker runtime {workerRuntime}. " + $"To force publish use --force. This will update your app to the expected image for worker runtime {workerRuntime}\n"); } } } // Check if azure-functions-worker exists in requirements.txt for Python function app if (workerRuntime == WorkerRuntime.python) { await PythonHelpers.WarnIfAzureFunctionsWorkerInRequirementsTxt(); } return(result); }