From 57270c9058ad76df32f5a23536f444cc335f3950 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 29 Apr 2020 19:23:15 -0700 Subject: [PATCH] Various namespace fixups - Fix use of default namespace for tye undeploy - Support --namespace for tye undeploy - Make handling of --namespace consistent --- .../KubernetesManifestGenerator.cs | 4 ++++ src/Microsoft.Tye.Core/ValidateIngressStep.cs | 5 ++++- src/Microsoft.Tye.Core/ValidateSecretStep.cs | 17 ++++++++++------- src/tye/Program.UndeployCommand.cs | 5 +++-- src/tye/UndeployHost.cs | 16 +++++++++++----- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs b/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs index 8db9d8f7..fb549a5b 100644 --- a/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs +++ b/src/Microsoft.Tye.Core/KubernetesManifestGenerator.cs @@ -25,6 +25,10 @@ namespace Microsoft.Tye var metadata = new YamlMappingNode(); root.Add("metadata", metadata); metadata.Add("name", ingress.Name); + if (!string.IsNullOrEmpty(application.Namespace)) + { + metadata.Add("namespace", application.Namespace); + } var annotations = new YamlMappingNode(); metadata.Add("annotations", annotations); diff --git a/src/Microsoft.Tye.Core/ValidateIngressStep.cs b/src/Microsoft.Tye.Core/ValidateIngressStep.cs index fcdd2198..b7e7aa69 100644 --- a/src/Microsoft.Tye.Core/ValidateIngressStep.cs +++ b/src/Microsoft.Tye.Core/ValidateIngressStep.cs @@ -59,7 +59,10 @@ namespace Microsoft.Tye // Workaround for https://github.com/kubernetes-client/csharp/issues/372 var store = await KubernetesClientConfiguration.LoadKubeConfigAsync(); var context = store.Contexts.Where(c => c.Name == config.CurrentContext).FirstOrDefault(); - config.Namespace ??= context?.ContextDetails?.Namespace; + + // Use namespace of application, or current context, or 'default' + config.Namespace = application.Namespace; + config.Namespace ??= context?.ContextDetails?.Namespace ?? "default"; var kubernetes = new Kubernetes(config); diff --git a/src/Microsoft.Tye.Core/ValidateSecretStep.cs b/src/Microsoft.Tye.Core/ValidateSecretStep.cs index eda1e293..c508c81a 100644 --- a/src/Microsoft.Tye.Core/ValidateSecretStep.cs +++ b/src/Microsoft.Tye.Core/ValidateSecretStep.cs @@ -56,13 +56,16 @@ namespace Microsoft.Tye // Workaround for https://github.com/kubernetes-client/csharp/issues/372 var store = await KubernetesClientConfiguration.LoadKubeConfigAsync(); var context = store.Contexts.Where(c => c.Name == config.CurrentContext).FirstOrDefault(); - config.Namespace ??= context?.ContextDetails?.Namespace; + + // Use namespace of application, or current context, or 'default' + config.Namespace = application.Namespace; + config.Namespace ??= context?.ContextDetails?.Namespace ?? "default"; var kubernetes = new Kubernetes(config); try { - var result = await kubernetes.ReadNamespacedSecretWithHttpMessagesAsync(secretInputBinding.Name, config.Namespace ?? "default"); + var result = await kubernetes.ReadNamespacedSecretWithHttpMessagesAsync(secretInputBinding.Name, config.Namespace); output.WriteInfoLine($"Found existing secret '{secretInputBinding.Name}'."); continue; } @@ -89,7 +92,7 @@ namespace Microsoft.Tye $"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " + $"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " + $"use the following command to manually create the secret." + System.Environment.NewLine + - $"kubectl create secret generic {secretInputBinding.Name} --from-literal=connectionstring="); + $"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=connectionstring="); } if (!Interactive && secretInputBinding is SecretUrlInputBinding) @@ -98,7 +101,7 @@ namespace Microsoft.Tye $"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " + $"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " + $"use the following command to manually create the secret." + System.Environment.NewLine + - $"kubectl create secret generic {secretInputBinding.Name} --from-literal=protocol= --from-literal=host= --from-literal=port="); + $"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=protocol= --from-literal=host= --from-literal=port="); } V1Secret secret; @@ -110,7 +113,7 @@ namespace Microsoft.Tye { output.WriteAlwaysLine($"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created."); output.WriteAlwaysLine($"Manually create a secret with:"); - output.WriteAlwaysLine($"kubectl create secret generic {secretInputBinding.Name} --from-literal=connectionstring="); + output.WriteAlwaysLine($"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=connectionstring="); continue; } @@ -143,7 +146,7 @@ namespace Microsoft.Tye { output.WriteAlwaysLine($"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created."); output.WriteAlwaysLine($"Manually create a secret with:"); - output.WriteAlwaysLine($"kubectl create secret generic {secretInputBinding.Name} -from-literal=protocol= --from-literal=host= --from-literal=port="); + output.WriteAlwaysLine($"kubectl create secret generic {secretInputBinding.Name} --namespace {config.Namespace} --from-literal=protocol= --from-literal=host= --from-literal=port="); continue; } @@ -170,7 +173,7 @@ namespace Microsoft.Tye try { - await kubernetes.CreateNamespacedSecretWithHttpMessagesAsync(secret, config.Namespace ?? "default"); + await kubernetes.CreateNamespacedSecretWithHttpMessagesAsync(secret, config.Namespace); output.WriteInfoLine($"Created secret '{secret.Metadata.Name}'."); } catch (Exception ex) diff --git a/src/tye/Program.UndeployCommand.cs b/src/tye/Program.UndeployCommand.cs index 6708ed4a..0f02a6dc 100644 --- a/src/tye/Program.UndeployCommand.cs +++ b/src/tye/Program.UndeployCommand.cs @@ -19,6 +19,7 @@ namespace Microsoft.Tye var command = new Command("undeploy", "delete deployed application") { CommonArguments.Path_Required, + StandardOptions.Namespace, StandardOptions.Interactive, StandardOptions.Verbosity, @@ -28,7 +29,7 @@ namespace Microsoft.Tye }, }; - command.Handler = CommandHandler.Create((console, path, verbosity, interactive, whatIf) => + command.Handler = CommandHandler.Create((console, path, verbosity, @namespace, interactive, whatIf) => { // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 if (path is null) @@ -36,7 +37,7 @@ namespace Microsoft.Tye throw new CommandException("No project or solution file was found."); } - return UndeployHost.UndeployAsync(console, path, verbosity, interactive, whatIf); + return UndeployHost.UndeployAsync(console, path, verbosity, @namespace, interactive, whatIf); }); return command; diff --git a/src/tye/UndeployHost.cs b/src/tye/UndeployHost.cs index b27d64b2..89adf0bd 100644 --- a/src/tye/UndeployHost.cs +++ b/src/tye/UndeployHost.cs @@ -12,13 +12,12 @@ using k8s; using k8s.Models; using Microsoft.Rest; using Microsoft.Tye.ConfigModel; -using Newtonsoft.Json; namespace Microsoft.Tye { public static class UndeployHost { - public static async Task UndeployAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, bool whatIf) + public static async Task UndeployAsync(IConsole console, FileInfo path, Verbosity verbosity, string @namespace, bool interactive, bool whatIf) { var output = new OutputContext(console, verbosity); @@ -26,18 +25,25 @@ namespace Microsoft.Tye // We don't need to know anything about the services, just the application name. var application = ConfigFactory.FromFile(path); + if (!String.IsNullOrEmpty(@namespace)) + { + application.Namespace = @namespace; + } - await ExecuteUndeployAsync(output, application, interactive, whatIf); + await ExecuteUndeployAsync(output, application, @namespace, interactive, whatIf); } - public static async Task ExecuteUndeployAsync(OutputContext output, ConfigApplication application, bool interactive, bool whatIf) + public static async Task ExecuteUndeployAsync(OutputContext output, ConfigApplication application, string @namespace, bool interactive, bool whatIf) { var config = KubernetesClientConfiguration.BuildDefaultConfig(); // Workaround for https://github.com/kubernetes-client/csharp/issues/372 var store = await KubernetesClientConfiguration.LoadKubeConfigAsync(); var context = store.Contexts.Where(c => c.Name == config.CurrentContext).FirstOrDefault(); - config.Namespace ??= context?.ContextDetails?.Namespace; + + // Use namespace of application, or current context, or 'default' + config.Namespace = application.Namespace; + config.Namespace ??= context?.ContextDetails?.Namespace ?? "default"; var kubernetes = new Kubernetes(config);