diff --git a/src/Microsoft.Tye.Core/ApplicationBuilder.cs b/src/Microsoft.Tye.Core/ApplicationBuilder.cs index d3d9ffc6..c1400492 100644 --- a/src/Microsoft.Tye.Core/ApplicationBuilder.cs +++ b/src/Microsoft.Tye.Core/ApplicationBuilder.cs @@ -19,6 +19,8 @@ namespace Microsoft.Tye public string Name { get; set; } + public string? Namespace { get; set; } + public ContainerRegistry? Registry { get; set; } public List Extensions { get; } = new List(); diff --git a/src/Microsoft.Tye.Core/ApplicationFactory.cs b/src/Microsoft.Tye.Core/ApplicationFactory.cs index fe0d99a4..be2c11a3 100644 --- a/src/Microsoft.Tye.Core/ApplicationFactory.cs +++ b/src/Microsoft.Tye.Core/ApplicationFactory.cs @@ -28,7 +28,7 @@ namespace Microsoft.Tye rootConfig.Validate(); var root = new ApplicationBuilder(source, rootConfig.Name ?? source.Directory.Name.ToLowerInvariant()); - + root.Namespace = rootConfig.Namespace; queue.Enqueue(rootConfig); while (queue.Count > 0) diff --git a/src/Microsoft.Tye.Core/ConfigModel/ConfigApplication.cs b/src/Microsoft.Tye.Core/ConfigModel/ConfigApplication.cs index aa06fec6..70d4e5d4 100644 --- a/src/Microsoft.Tye.Core/ConfigModel/ConfigApplication.cs +++ b/src/Microsoft.Tye.Core/ConfigModel/ConfigApplication.cs @@ -24,6 +24,8 @@ namespace Microsoft.Tye.ConfigModel public string? Name { get; set; } + public string? Namespace { get; set; } + public string? Registry { get; set; } public string? Network { get; set; } diff --git a/src/Microsoft.Tye.Core/GenerateKubernetesManifestStep.cs b/src/Microsoft.Tye.Core/GenerateKubernetesManifestStep.cs index 77757657..36a39811 100644 --- a/src/Microsoft.Tye.Core/GenerateKubernetesManifestStep.cs +++ b/src/Microsoft.Tye.Core/GenerateKubernetesManifestStep.cs @@ -12,6 +12,8 @@ namespace Microsoft.Tye public string Environment { get; set; } = "production"; + public string? Namespace { get; set; } = null; + public override Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { diff --git a/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs b/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs index a4060abb..b60798e8 100644 --- a/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs +++ b/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs @@ -26,6 +26,9 @@ namespace Microsoft.Tye var metadata = new YamlMappingNode(); root.Add("metadata", metadata); metadata.Add("name", project.Name); + if (!String.IsNullOrEmpty(application.Namespace)) { + metadata.Add("namespace", application.Namespace); + } if (service.Annotations.Count > 0) { @@ -104,6 +107,9 @@ namespace Microsoft.Tye var metadata = new YamlMappingNode(); root.Add("metadata", metadata); metadata.Add("name", project.Name); + if (!String.IsNullOrEmpty(application.Namespace)) { + metadata.Add("namespace", application.Namespace); + } if (deployment.Annotations.Count > 0) { diff --git a/src/Microsoft.Tye.Core/Serialization/ConfigApplicationParser.cs b/src/Microsoft.Tye.Core/Serialization/ConfigApplicationParser.cs index 0f5af8e1..4988d2e1 100644 --- a/src/Microsoft.Tye.Core/Serialization/ConfigApplicationParser.cs +++ b/src/Microsoft.Tye.Core/Serialization/ConfigApplicationParser.cs @@ -20,6 +20,9 @@ namespace Tye.Serialization case "name": app.Name = YamlParser.GetScalarValue(key, child.Value); break; + case "namespace": + app.Namespace = YamlParser.GetScalarValue(key, child.Value); + break; case "network": app.Network = YamlParser.GetScalarValue(key, child.Value); break; diff --git a/src/Microsoft.Tye.Core/StandardOptions.cs b/src/Microsoft.Tye.Core/StandardOptions.cs index b4a0276c..48dd8eb9 100644 --- a/src/Microsoft.Tye.Core/StandardOptions.cs +++ b/src/Microsoft.Tye.Core/StandardOptions.cs @@ -195,5 +195,18 @@ namespace Microsoft.Tye }; } } + + public static Option Namespace + { + get + { + return new Option(new[] { "-n", "--namespace" }) + { + Description = "Specify the namespace for the deployment", + Required = false, + Argument = new Argument(), + }; + } + } } } diff --git a/src/tye/GenerateHost.cs b/src/tye/GenerateHost.cs index b6d85acf..91a74a24 100644 --- a/src/tye/GenerateHost.cs +++ b/src/tye/GenerateHost.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.CommandLine; using System.IO; @@ -12,7 +13,7 @@ namespace Microsoft.Tye { public static class GenerateHost { - public static async Task GenerateAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive) + public static async Task GenerateAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, string ns) { var output = new OutputContext(console, verbosity); @@ -22,7 +23,10 @@ namespace Microsoft.Tye { throw new CommandException($"No services found in \"{application.Source.Name}\""); } - + if (!String.IsNullOrEmpty(ns)) + { + application.Namespace = ns; + } await ExecuteGenerateAsync(output, application, environment: "production", interactive); } diff --git a/src/tye/Program.DeployCommand.cs b/src/tye/Program.DeployCommand.cs index 9576ceee..4c914cda 100644 --- a/src/tye/Program.DeployCommand.cs +++ b/src/tye/Program.DeployCommand.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using System.Collections.Generic; using System.CommandLine; using System.CommandLine.Invocation; @@ -21,6 +22,7 @@ namespace Microsoft.Tye CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Verbosity, + StandardOptions.Namespace, }; command.AddOption(new Option(new[] { "-f", "--force" }) @@ -29,7 +31,7 @@ namespace Microsoft.Tye Required = false }); - command.Handler = CommandHandler.Create(async (console, path, verbosity, interactive, force) => + command.Handler = CommandHandler.Create(async (console, path, verbosity, interactive, force, @namespace) => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (path is null) @@ -45,7 +47,10 @@ namespace Microsoft.Tye { throw new CommandException($"No services found in \"{application.Source.Name}\""); } - + if (!String.IsNullOrEmpty(@namespace)) + { + application.Namespace = @namespace; + } await ExecuteDeployAsync(new OutputContext(console, verbosity), application, environment: "production", interactive, force); }); @@ -75,7 +80,7 @@ namespace Microsoft.Tye new ValidateSecretStep() { Environment = environment, Interactive = interactive, Force = force, }, }; - steps.Add(new GenerateKubernetesManifestStep() { Environment = environment, }); + steps.Add(new GenerateKubernetesManifestStep() { Environment = environment, Namespace = application.Namespace }); steps.Add(new DeployServiceYamlStep() { Environment = environment, }); ApplyRegistryAndDefaults(output, application, interactive, requireRegistry: true); @@ -103,7 +108,12 @@ namespace Microsoft.Tye await ApplicationYamlWriter.WriteAsync(output, writer, application); } - output.WriteDebugLine("Running 'kubectl apply'."); + string ns = $"namespace ${application.Namespace}"; + if (String.IsNullOrEmpty(application.Namespace)) + { + ns = "current namespace"; + } + output.WriteDebugLine($"Running 'kubectl apply' in ${ns}"); output.WriteCommandLine("kubectl", $"apply -f \"{tempFile.FilePath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( diff --git a/src/tye/Program.GenerateCommand.cs b/src/tye/Program.GenerateCommand.cs index e6e17345..a6764712 100644 --- a/src/tye/Program.GenerateCommand.cs +++ b/src/tye/Program.GenerateCommand.cs @@ -21,13 +21,14 @@ namespace Microsoft.Tye CommonArguments.Path_Required, StandardOptions.Interactive, StandardOptions.Verbosity, + StandardOptions.Namespace, }; // This is a super-secret VIP-only command! It's useful for testing, but we're // not documenting it right now. command.IsHidden = true; - command.Handler = CommandHandler.Create((console, path, verbosity, interactive) => + command.Handler = CommandHandler.Create((console, path, verbosity, interactive, @namespace) => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (path is null) @@ -35,7 +36,7 @@ namespace Microsoft.Tye throw new CommandException("No project or solution file was found."); } - return GenerateHost.GenerateAsync(console, path, verbosity, interactive); + return GenerateHost.GenerateAsync(console, path, verbosity, interactive, @namespace); }); return command;