private async Task <(bool succeeded, string token)> TryGetAzCliToken() { if (CommandChecker.CommandExists("az")) { var az = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? new Executable("cmd", "/c az account get-access-token --query \"accessToken\" --output json") : new Executable("az", "account get-access-token --query \"accessToken\" --output json"); var stdout = new StringBuilder(); var stderr = new StringBuilder(); var exitCode = await az.RunAsync(o => stdout.AppendLine(o), e => stderr.AppendLine(e)); if (exitCode == 0) { return(true, stdout.ToString().Trim(' ', '\n', '\r', '"')); } else { if (StaticSettings.IsDebug) { ColoredConsole.WriteLine(VerboseColor($"Unable to fetch access token from az cli. Error: {stderr.ToString().Trim(' ', '\n', '\r')}")); } } } return(false, null); }
private async Task <string> AzureCliGetToken() { if (CommandChecker.CommandExists("az")) { var az = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? new Executable("cmd", "/c az account get-access-token --query \"accessToken\"") : new Executable("az", "account get-access-token --query \"accessToken\""); var stdout = new StringBuilder(); var stderr = new StringBuilder(); var exitCode = await az.RunAsync(o => stdout.AppendLine(o), e => stderr.AppendLine(e)); if (exitCode != 0) { throw new CliException(stderr.ToString().Trim(' ', '\n', '\r')); } else { return(stdout.ToString().Trim(' ', '\n', '\r', '"')); } } else { throw new FileNotFoundException("Cannot find az cli. Please make sure to install az cli."); } }
public async override Task RunAsync() { var extensionBundleManager = ExtensionBundleHelper.GetExtensionBundleManager(); if (extensionBundleManager.IsExtensionBundleConfigured()) { var hostFilePath = Path.Combine(Environment.CurrentDirectory, ScriptConstants.HostMetadataFileName); if (_showExtensionBundleWarning) { ColoredConsole.WriteLine(WarningColor($"No action performed. Extension bundle is configured in {hostFilePath}")); } return; } if (CommandChecker.CommandExists("dotnet")) { var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(_secretsManager, Csx, ConfigPath); var installExtensions = new Executable("dotnet", $"build \"{extensionsProj}\" -o \"{OutputPath}\""); await installExtensions.RunAsync(output => ColoredConsole.WriteLine(output), error => ColoredConsole.WriteLine(ErrorColor(error))); } else { ColoredConsole.Error.WriteLine(ErrorColor(Constants.Errors.ExtensionsNeedDotnet)); } }
internal static async Task <Stream> GetPythonDeploymentPackage(IEnumerable <string> files, string functionAppRoot, bool buildNativeDeps, bool noBundler, string additionalPackages) { if (!FileSystemHelpers.FileExists(Path.Combine(functionAppRoot, Constants.RequirementsTxt))) { throw new CliException($"{Constants.RequirementsTxt} is not found. " + $"{Constants.RequirementsTxt} is required for python function apps. Please make sure to generate one before publishing."); } var externalPythonPackages = Path.Combine(functionAppRoot, Constants.ExternalPythonPackages); if (FileSystemHelpers.DirectoryExists(externalPythonPackages)) { ColoredConsole.WriteLine($"Deleting the old {Constants.ExternalPythonPackages} directory"); FileSystemHelpers.DeleteDirectorySafe(Path.Combine(functionAppRoot, Constants.ExternalPythonPackages)); } if (buildNativeDeps) { if (CommandChecker.CommandExists("docker") && await DockerHelpers.VerifyDockerAccess()) { return(await InternalPreparePythonDeploymentInDocker(files, functionAppRoot, additionalPackages, noBundler)); } else { throw new CliException("Docker is required to build native dependencies for python function apps"); } } else { return(await InternalPreparePythonDeployment(files, functionAppRoot)); } }
public static void EnsureDotNetForExtensions(Template template) { if (template.Metadata.Extensions != null && !CommandChecker.CommandExists("dotnet")) { throw new CliException($"The {template.Metadata.Name} template has extensions. {Constants.Errors.ExtensionsNeedDotnet}"); } }
private async Task <string> RunAzCLICommand(string param) { if (!CommandChecker.CommandExists("az")) { throw new CliException("az CLI not found"); } var az = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? new Executable("cmd", $"/c az {param}") : new Executable("az", param); var stdout = new StringBuilder(); var stderr = new StringBuilder(); var exitCode = await az.RunAsync(o => stdout.AppendLine(o), e => stderr.AppendLine(e)); if (exitCode == 0) { return(stdout.ToString().Trim(' ', '\n', '\r', '"')); } else { if (StaticSettings.IsDebug) { ColoredConsole.WriteLine(VerboseColor($"Unable to run az CLI command `az {param}`. Error: {stderr.ToString().Trim(' ', '\n', '\r')}")); } throw new CliException("Error running Az CLI command"); } }
public static void EnsureDotnet() { if (!CommandChecker.CommandExists("dotnet")) { throw new CliException("dotnet sdk is required for dotnet based functions. Please install https://microsoft.com/net"); } }
public async override Task RunAsync() { if (CommandChecker.CommandExists("dotnet")) { var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(); var args = $"add {extensionsProj} package {Package} --version {Version}"; if (!string.IsNullOrEmpty(Source)) { args += $" --source {Source}"; } var addPackage = new Executable("dotnet", args); await addPackage.RunAsync(output => ColoredConsole.WriteLine(output), error => ColoredConsole.WriteLine(ErrorColor(error))); var syncAction = new SyncExtensionsAction() { OutputPath = OutputPath }; await syncAction.RunAsync(); } else { ColoredConsole.Error.WriteLine(ErrorColor("Extensions command require dotnet on your path. Please make sure to install dotnet for your system from https://www.microsoft.com/net/download")); } }
public static void EnsureDotNetForExtensions(Template template) { if (template.Metadata.Extensions != null && !CommandChecker.CommandExists("dotnet")) { throw new CliException($"The {template.Metadata.Name} template has extensions which require dotnet on your path. " + $"Please make sure to install dotnet for your system from https://www.microsoft.com/net/download"); } }
internal static async Task <Stream> GetPythonDeploymentPackage(IEnumerable <string> files, string functionAppRoot, bool buildNativeDeps, BuildOption buildOption, string additionalPackages) { var reqTxtFile = Path.Combine(functionAppRoot, Constants.RequirementsTxt); if (!FileSystemHelpers.FileExists(reqTxtFile)) { throw new CliException($"{Constants.RequirementsTxt} is not found. " + $"{Constants.RequirementsTxt} is required for python function apps. Please make sure to generate one before publishing."); } var packagesLocation = Path.Combine(functionAppRoot, Constants.ExternalPythonPackages); if (FileSystemHelpers.DirectoryExists(packagesLocation)) { // Only update packages if checksum of requirements.txt does not match // If build option is remote, we don't need to verify if packages are in sync, as we need to delete them regardless if (buildOption != BuildOption.Remote && await ArePackagesInSync(reqTxtFile, packagesLocation)) { ColoredConsole.WriteLine(Yellow($"Directory {Constants.ExternalPythonPackages} already in sync with {Constants.RequirementsTxt}. Skipping restoring dependencies...")); return(await ZipHelper.CreateZip(files.Union(FileSystemHelpers.GetFiles(packagesLocation)), functionAppRoot)); } ColoredConsole.WriteLine($"Deleting the old {Constants.ExternalPythonPackages} directory"); FileSystemHelpers.DeleteDirectorySafe(packagesLocation); } FileSystemHelpers.EnsureDirectory(packagesLocation); // Only one of the remote build or build-native-deps flag can be chosen if (buildNativeDeps) { if (CommandChecker.CommandExists("docker") && await DockerHelpers.VerifyDockerAccess()) { await RestorePythonRequirementsDocker(functionAppRoot, packagesLocation, additionalPackages); } else { throw new CliException("Docker is required to build native dependencies for python function apps"); } } else if (buildOption == BuildOption.Remote) { // No-ops, python packages will be resolved on the server side } else { await RestorePythonRequirementsPackapp(functionAppRoot, packagesLocation); } // No need to generate and compare .md5 when using remote build if (buildOption != BuildOption.Remote) { // Store a checksum of requirements.txt var md5FilePath = Path.Combine(packagesLocation, $"{Constants.RequirementsTxt}.md5"); await FileSystemHelpers.WriteAllTextToFileAsync(md5FilePath, SecurityHelpers.CalculateMd5(reqTxtFile)); } return(await ZipHelper.CreateZip(files.Union(FileSystemHelpers.GetFiles(packagesLocation)), functionAppRoot)); }
internal static async Task <Stream> GetPythonDeploymentPackage(IEnumerable <string> files, string functionAppRoot) { if (CommandChecker.CommandExists("docker") && await DockerHelpers.VerifyDockerAccess()) { return(await InternalPreparePythonDeployment(files, functionAppRoot)); } else { throw new CliException("Docker is required to publish python function apps"); } }
public async override Task RunAsync() { if (CommandChecker.CommandExists("dotnet")) { if (!string.IsNullOrEmpty(ConfigPath) && !FileSystemHelpers.DirectoryExists(ConfigPath)) { throw new CliArgumentsException("Invalid config path, please verify directory exists"); } var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(_secretsManager, Csx, ConfigPath); if (string.IsNullOrEmpty(Package) && string.IsNullOrEmpty(Version)) { var project = ProjectHelpers.GetProject(extensionsProj); foreach (var extensionPackage in ExtensionsHelper.GetExtensionPackages()) { // Only add / update package referece if it does not exist or forced update is enabled if (!ProjectHelpers.PackageReferenceExists(project, extensionPackage.Name) || Force) { await AddPackage(extensionsProj, extensionPackage.Name, extensionPackage.Version); } } } else if (!string.IsNullOrEmpty(Package) && !string.IsNullOrEmpty(Version)) { await AddPackage(extensionsProj, Package, Version); } else { throw new CliArgumentsException("Must specify extension package name and version", new CliArgument { Name = nameof(Package), Description = "Extension package name" }, new CliArgument { Name = nameof(Version), Description = "Extension package version" } ); } var syncAction = new SyncExtensionsAction(_secretsManager) { OutputPath = OutputPath, ConfigPath = ConfigPath }; await syncAction.RunAsync(); } else { ColoredConsole.Error.WriteLine(ErrorColor(Constants.Errors.ExtensionsNeedDotnet)); } }
public async override Task RunAsync() { if (CommandChecker.CommandExists("dotnet")) { var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(_secretsManager, Csx, ConfigPath); var installExtensions = new Executable("dotnet", $"build \"{extensionsProj}\" -o \"{OutputPath}\""); await installExtensions.RunAsync(output => ColoredConsole.WriteLine(output), error => ColoredConsole.WriteLine(ErrorColor(error))); } else { ColoredConsole.Error.WriteLine(ErrorColor(Constants.Errors.ExtensionsNeedDotnet)); } }
public async override Task RunAsync() { if (CommandChecker.CommandExists("dotnet")) { var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(_secretsManager, Csx, ConfigPath); var installExtensions = new Executable("dotnet", $"build \"{extensionsProj}\" -o \"{OutputPath}\""); await installExtensions.RunAsync(output => ColoredConsole.WriteLine(output), error => ColoredConsole.WriteLine(ErrorColor(error))); } else { ColoredConsole.Error.WriteLine(ErrorColor("Extensions command require dotnet on your path. Please make sure to install dotnet for your system from https://www.microsoft.com/net/download")); } }
public async override Task RunAsync() { if (CommandChecker.CommandExists("dotnet")) { var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(); var runtimeId = GetRuntimeIdentifierParameter(); var installExtensions = new Executable("dotnet", $"build {extensionsProj} -o {OutputPath} {runtimeId}"); await installExtensions.RunAsync(output => ColoredConsole.WriteLine(output), error => ColoredConsole.WriteLine(ErrorColor(error))); } else { ColoredConsole.Error.WriteLine(ErrorColor("Extensions command require dotnet on your path. Please make sure to install dotnet for your system from https://www.microsoft.com/net/download")); } }
public override async Task RunAsync() { if (!string.IsNullOrEmpty(FolderName)) { var folderPath = Path.Combine(Environment.CurrentDirectory, FolderName); FileSystemHelpers.EnsureDirectory(folderPath); Environment.CurrentDirectory = folderPath; } if (!Platforms.Contains(Platform)) { ColoredConsole.Error.WriteLine(ErrorColor($"platform {Platform} is not supported. Valid options are: {String.Join(",", Platforms)}")); return; } if (!CommandChecker.CommandExists("kubectl")) { ColoredConsole.Error.WriteLine(ErrorColor($"kubectl is required for deploying to kubernetes. Please make sure to install kubectl and try again.")); return; } var dockerFilePath = Path.Combine(Environment.CurrentDirectory, "Dockerfile"); if (!FileSystemHelpers.FileExists(dockerFilePath)) { ColoredConsole.Error.WriteLine(ErrorColor($"Dockerfile not found in directory {Environment.CurrentDirectory}")); return; } var image = $"{Registry}/{Name.SanitizeImageName()}"; ColoredConsole.WriteLine("Building Docker image..."); await DockerHelpers.DockerBuild(image, Environment.CurrentDirectory); ColoredConsole.WriteLine("Pushing function image to registry..."); await DockerHelpers.DockerPush(image); var platform = PlatformFactory.CreatePlatform(Platform, ConfigPath); if (platform == null) { ColoredConsole.Error.WriteLine(ErrorColor($"Platform {Platform} is not supported")); return; } await platform.DeployContainerizedFunction(Name, image, MinInstances, MaxInstances); }
public async override Task RunAsync() { if (CommandChecker.CommandExists("dotnet")) { if (!string.IsNullOrEmpty(ConfigPath) && !FileSystemHelpers.DirectoryExists(ConfigPath)) { throw new CliArgumentsException("Invalid config path, please verify directory exists"); } var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(_secretsManager, Csx, ConfigPath); if (string.IsNullOrEmpty(Package) && string.IsNullOrEmpty(Version)) { foreach (var extensionPackage in ExtensionsHelper.GetExtensionPackages()) { await AddPackage(extensionsProj, extensionPackage.Name, extensionPackage.Version); } } else if (!string.IsNullOrEmpty(Package) && !string.IsNullOrEmpty(Version)) { await AddPackage(extensionsProj, Package, Version); } else { throw new CliArgumentsException("Must specify extension package name and version", new CliArgument { Name = nameof(Package), Description = "Extension package name" }, new CliArgument { Name = nameof(Version), Description = "Extension package version" } ); } var syncAction = new SyncExtensionsAction(_secretsManager) { OutputPath = OutputPath, ConfigPath = ConfigPath }; await syncAction.RunAsync(); } else { ColoredConsole.Error.WriteLine(ErrorColor("Extensions command require dotnet on your path. Please make sure to install dotnet for your system from https://www.microsoft.com/net/download")); } }
internal static async Task <Stream> GetPythonDeploymentPackage(IEnumerable <string> files, string functionAppRoot, bool buildNativeDeps, string additionalPackages) { var reqTxtFile = Path.Combine(functionAppRoot, Constants.RequirementsTxt); if (!FileSystemHelpers.FileExists(reqTxtFile)) { throw new CliException($"{Constants.RequirementsTxt} is not found. " + $"{Constants.RequirementsTxt} is required for python function apps. Please make sure to generate one before publishing."); } var packagesLocation = Path.Combine(functionAppRoot, Constants.ExternalPythonPackages); if (FileSystemHelpers.DirectoryExists(packagesLocation)) { // Only update packages if checksum of requirements.txt does not match or a sync is forced if (await ArePackagesInSync(reqTxtFile, packagesLocation)) { ColoredConsole.WriteLine(Yellow($"Directory {Constants.ExternalPythonPackages} already in sync with {Constants.RequirementsTxt}. Skipping restoring dependencies...")); return(ZipHelper.CreateZip(files.Union(FileSystemHelpers.GetFiles(packagesLocation)), functionAppRoot)); } ColoredConsole.WriteLine($"Deleting the old {Constants.ExternalPythonPackages} directory"); FileSystemHelpers.DeleteDirectorySafe(Path.Combine(functionAppRoot, Constants.ExternalPythonPackages)); } FileSystemHelpers.EnsureDirectory(packagesLocation); if (buildNativeDeps) { if (CommandChecker.CommandExists("docker") && await DockerHelpers.VerifyDockerAccess()) { await RestorePythonRequirementsDocker(functionAppRoot, packagesLocation, additionalPackages); } else { throw new CliException("Docker is required to build native dependencies for python function apps"); } } else { await RestorePythonRequirementsPackapp(functionAppRoot, packagesLocation); } // Store a checksum of requirements.txt var md5FilePath = Path.Combine(packagesLocation, $"{Constants.RequirementsTxt}.md5"); await FileSystemHelpers.WriteAllTextToFileAsync(md5FilePath, SecurityHelpers.CalculateMd5(reqTxtFile)); return(ZipHelper.CreateZip(files.Union(FileSystemHelpers.GetFiles(packagesLocation)), functionAppRoot)); }
internal static async Task <X509Certificate2> GetOrCreateCertificate(string certPath, string certPassword) { if (!string.IsNullOrEmpty(certPath) && !string.IsNullOrEmpty(certPassword)) { certPassword = File.Exists(certPassword) ? File.ReadAllText(certPassword).Trim() : certPassword; return(new X509Certificate2(certPath, certPassword)); } else if (CommandChecker.CommandExists("openssl")) { return(await CreateCertificateOpenSSL()); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { ColoredConsole .WriteLine("Auto cert generation is currently not working on the .NET Core build.") .WriteLine("On Windows you can run:") .WriteLine() .Write(DarkCyan("PS> ")) .WriteLine($"$cert = {Yellow("New-SelfSignedCertificate")} -Subject localhost -DnsName localhost -FriendlyName \"Functions Development\" -KeyUsage DigitalSignature -TextExtension @(\"2.5.29.37={{text}}1.3.6.1.5.5.7.3.1\")") .Write(DarkCyan("PS> ")) .WriteLine($"{Yellow("Export-PfxCertificate")} -Cert $cert -FilePath certificate.pfx -Password (ConvertTo-SecureString -String {Red("<password>")} -Force -AsPlainText)") .WriteLine() .WriteLine("For more checkout https://docs.microsoft.com/en-us/aspnet/core/security/https") .WriteLine(); } else { ColoredConsole .WriteLine("Auto cert generation is currently not working on the .NET Core build.") .WriteLine("On Unix you can run:") .WriteLine() .Write(DarkGreen("sh> ")) .WriteLine("openssl req -new -x509 -newkey rsa:2048 -keyout localhost.key -out localhost.cer -days 365 -subj /CN=localhost") .Write(DarkGreen("sh> ")) .WriteLine("openssl pkcs12 -export -out certificate.pfx -inkey localhost.key -in localhost.cer") .WriteLine() .WriteLine("For more checkout https://docs.microsoft.com/en-us/aspnet/core/security/https") .WriteLine(); } throw new CliException("Auto cert generation is currently not working on the .NET Core build."); }
public void CommandCheckerShouldWork() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { var exists = CommandChecker.CommandExists("cmd"); var doesntExist = CommandChecker.CommandExists("fooo"); exists.Should().BeTrue(because: "checking if cmd command exists should always be true on Windows"); doesntExist.Should().BeFalse(because: "checking if fooo command exists on windows should be false"); } else { var exists = CommandChecker.CommandExists("bash"); var doesntExist = CommandChecker.CommandExists("fooo"); exists.Should().BeTrue(because: "checking if sh command exists should always be true on Unix-like"); doesntExist.Should().BeFalse(because: "checking if fooo command exists on Unix-like should be false"); } }
private async Task PreRunConditions(WorkerRuntime workerRuntime) { if (workerRuntime == 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 (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."); } } else if (workerRuntime == 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]."); } }
internal static async Task <Stream> GetPythonDeploymentPackage(IEnumerable <string> files, string functionAppRoot, bool buildNativeDeps) { if (!FileSystemHelpers.FileExists(Path.Combine(functionAppRoot, Constants.RequirementsTxt))) { throw new CliException($"{Constants.RequirementsTxt} is not found. " + $"{Constants.RequirementsTxt} is required for python function apps. Please make sure to generate one before publishing."); } if (buildNativeDeps) { if (CommandChecker.CommandExists("docker") && await DockerHelpers.VerifyDockerAccess()) { return(await InternalPreparePythonDeploymentInDocker(files, functionAppRoot)); } else { throw new CliException("Docker is required to build native dependencies for python function apps"); } } else { return(await InternalPreparePythonDeployment(files, functionAppRoot)); } }
public async override Task RunAsync() { var extensionBundleManager = ExtensionBundleHelper.GetExtensionBundleManager(); if (extensionBundleManager.IsExtensionBundleConfigured()) { var hostFilePath = Path.Combine(Environment.CurrentDirectory, ScriptConstants.HostMetadataFileName); if (_showNoActionWarning) { ColoredConsole.WriteLine(WarningColor($"No action performed. Extension bundle is configured in {hostFilePath}.")); } return; } if (!string.IsNullOrEmpty(ConfigPath) && !FileSystemHelpers.DirectoryExists(ConfigPath)) { throw new CliArgumentsException("Invalid config path, please verify directory exists"); } if (!NeedsExtensionsInstall()) { return; } if (CommandChecker.CommandExists("dotnet")) { var extensionsProj = await ExtensionsHelper.EnsureExtensionsProjectExistsAsync(_secretsManager, Csx, ConfigPath); if (string.IsNullOrEmpty(Package) && string.IsNullOrEmpty(Version)) { var project = ProjectHelpers.GetProject(extensionsProj); foreach (var extensionPackage in ExtensionsHelper.GetExtensionPackages()) { // Only add / update package referece if it does not exist or forced update is enabled if (!ProjectHelpers.PackageReferenceExists(project, extensionPackage.Name) || Force) { await AddPackage(extensionsProj, extensionPackage.Name, extensionPackage.Version); } } } else if (!string.IsNullOrEmpty(Package) && !string.IsNullOrEmpty(Version)) { await AddPackage(extensionsProj, Package, Version); } else { throw new CliArgumentsException("Must specify extension package name and version", new CliArgument { Name = nameof(Package), Description = "Extension package name" }, new CliArgument { Name = nameof(Version), Description = "Extension package version" } ); } var syncAction = new SyncExtensionsAction(_secretsManager, false) { OutputPath = OutputPath, ConfigPath = ConfigPath }; await syncAction.RunAsync(); } else { throw new CliException(Constants.Errors.ExtensionsNeedDotnet); } }
private async Task <(bool succeeded, string token)> TryGetAzPowerShellToken() { // PowerShell Core can only use Az so we can check that it exists and that the Az module exists if (CommandChecker.CommandExists(_powerShellCoreExecutable) && await CommandChecker.PowerShellModuleExistsAsync(_powerShellCoreExecutable, _azProfileModuleName)) { var az = new Executable(_powerShellCoreExecutable, $"-NonInteractive -o Text -NoProfile -c {GetPowerShellAccessTokenScript(_azProfileModuleName)}"); var stdout = new StringBuilder(); var stderr = new StringBuilder(); var exitCode = await az.RunAsync(o => stdout.AppendLine(o), e => stderr.AppendLine(e)); if (exitCode == 0) { return(true, stdout.ToString().Trim(' ', '\n', '\r', '"')); } else { if (StaticSettings.IsDebug) { ColoredConsole.WriteLine(VerboseColor($"Unable to fetch access token from Az.Profile in PowerShell Core. Error: {stderr.ToString().Trim(' ', '\n', '\r')}")); } } } // Windows PowerShell can use Az or AzureRM so first we check if powershell.exe is available if (CommandChecker.CommandExists(_windowsPowerShellExecutable)) { string moduleToUse; // depending on if Az.Profile or AzureRM.Profile is available, we need to change the prefix if (await CommandChecker.PowerShellModuleExistsAsync(_windowsPowerShellExecutable, _azProfileModuleName)) { moduleToUse = _azProfileModuleName; } else if (await CommandChecker.PowerShellModuleExistsAsync(_windowsPowerShellExecutable, _azureRmProfileModuleName)) { moduleToUse = _azureRmProfileModuleName; } else { // User doesn't have either Az.Profile or AzureRM.Profile if (StaticSettings.IsDebug) { ColoredConsole.WriteLine(VerboseColor("Unable to find Az.Profile or AzureRM.Profile.")); } return(false, null); } var az = new Executable("powershell", $"-NonInteractive -o Text -NoProfile -c {GetPowerShellAccessTokenScript(moduleToUse)}"); var stdout = new StringBuilder(); var stderr = new StringBuilder(); var exitCode = await az.RunAsync(o => stdout.AppendLine(o), e => stderr.AppendLine(e)); if (exitCode == 0) { return(true, stdout.ToString().Trim(' ', '\n', '\r', '"')); } else { if (StaticSettings.IsDebug) { ColoredConsole.WriteLine(VerboseColor($"Unable to fetch access token from '{moduleToUse}'. Error: {stderr.ToString().Trim(' ', '\n', '\r')}")); } } } return(false, null); }
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]."); } }
public async override Task RunAsync() { if (Console.IsOutputRedirected || Console.IsInputRedirected) { if (string.IsNullOrEmpty(TemplateName) || string.IsNullOrEmpty(FunctionName)) { ColoredConsole .Error .WriteLine(ErrorColor("Running with stdin\\stdout redirected. Command must specify --template, and --name explicitly.")) .WriteLine(ErrorColor("See 'func help function' for more details")); return; } } var workerRuntime = GlobalCoreToolsSettings.CurrentWorkerRuntimeOrNone; var templates = await _templatesManager.Templates; if (workerRuntime != WorkerRuntime.None && !string.IsNullOrWhiteSpace(Language)) { // validate var workerRuntimeSelected = WorkerRuntimeLanguageHelper.NormalizeWorkerRuntime(Language); if (workerRuntime != workerRuntimeSelected) { throw new CliException("Selected language doesn't match worker set in local.settings.json." + $"Selected worker is: {workerRuntime} and selected language is: {workerRuntimeSelected}"); } } else if (string.IsNullOrWhiteSpace(Language)) { if (workerRuntime == WorkerRuntime.None) { SelectionMenuHelper.DisplaySelectionWizardPrompt("language"); Language = SelectionMenuHelper.DisplaySelectionWizard(templates.Select(t => t.Metadata.Language).Where(l => !l.Equals("python", StringComparison.OrdinalIgnoreCase)).Distinct()); workerRuntime = WorkerRuntimeLanguageHelper.SetWorkerRuntime(_secretsManager, Language); } else if (workerRuntime != WorkerRuntime.dotnet || Csx) { var languages = WorkerRuntimeLanguageHelper.LanguagesForWorker(workerRuntime); var displayList = templates .Select(t => t.Metadata.Language) .Where(l => languages.Contains(l, StringComparer.OrdinalIgnoreCase)) .Distinct() .ToArray(); if (displayList.Length == 1) { Language = displayList.First(); } else if (!InferAndUpdateLanguage(workerRuntime)) { SelectionMenuHelper.DisplaySelectionWizardPrompt("language"); Language = SelectionMenuHelper.DisplaySelectionWizard(displayList); } } } else if (!string.IsNullOrWhiteSpace(Language)) { workerRuntime = WorkerRuntimeLanguageHelper.SetWorkerRuntime(_secretsManager, Language); } if (workerRuntime == WorkerRuntime.dotnet && !Csx) { SelectionMenuHelper.DisplaySelectionWizardPrompt("template"); TemplateName = TemplateName ?? SelectionMenuHelper.DisplaySelectionWizard(DotnetHelpers.GetTemplates()); ColoredConsole.Write("Function name: "); FunctionName = FunctionName ?? Console.ReadLine(); ColoredConsole.WriteLine(FunctionName); var namespaceStr = Path.GetFileName(Environment.CurrentDirectory); await DotnetHelpers.DeployDotnetFunction(TemplateName.Replace(" ", string.Empty), Utilities.SanitizeClassName(FunctionName), Utilities.SanitizeNameSpace(namespaceStr)); } else { SelectionMenuHelper.DisplaySelectionWizardPrompt("template"); string templateLanguage; try { templateLanguage = WorkerRuntimeLanguageHelper.NormalizeLanguage(Language); } catch (Exception) { // Ideally this should never happen. templateLanguage = WorkerRuntimeLanguageHelper.GetDefaultTemplateLanguageFromWorker(workerRuntime); } TelemetryHelpers.AddCommandEventToDictionary(TelemetryCommandEvents, "language", templateLanguage); TemplateName = TemplateName ?? SelectionMenuHelper.DisplaySelectionWizard(templates.Where(t => t.Metadata.Language.Equals(templateLanguage, StringComparison.OrdinalIgnoreCase)).Select(t => t.Metadata.Name).Distinct()); ColoredConsole.WriteLine(TitleColor(TemplateName)); var template = templates.FirstOrDefault(t => Utilities.EqualsIgnoreCaseAndSpace(t.Metadata.Name, TemplateName) && t.Metadata.Language.Equals(templateLanguage, StringComparison.OrdinalIgnoreCase)); if (template == null) { TelemetryHelpers.AddCommandEventToDictionary(TelemetryCommandEvents, "template", "N/A"); throw new CliException($"Can't find template \"{TemplateName}\" in \"{Language}\""); } else { TelemetryHelpers.AddCommandEventToDictionary(TelemetryCommandEvents, "template", TemplateName); var extensionBundleManager = ExtensionBundleHelper.GetExtensionBundleManager(); if (template.Metadata.Extensions != null && !extensionBundleManager.IsExtensionBundleConfigured() && !CommandChecker.CommandExists("dotnet")) { throw new CliException($"The {template.Metadata.Name} template has extensions. {Constants.Errors.ExtensionsNeedDotnet}"); } ColoredConsole.Write($"Function name: [{template.Metadata.DefaultFunctionName}] "); FunctionName = FunctionName ?? Console.ReadLine(); FunctionName = string.IsNullOrEmpty(FunctionName) ? template.Metadata.DefaultFunctionName : FunctionName; await _templatesManager.Deploy(FunctionName, template); PerformPostDeployTasks(FunctionName, Language); } } ColoredConsole.WriteLine($"The function \"{FunctionName}\" was created successfully from the \"{TemplateName}\" template."); }