public async override Task RunAsync() { if (DryRun) { ColoredConsole.WriteLine(KubernetesHelper.GetKedaResources(Namespace)); if (!KedaOnly) { ColoredConsole.WriteLine(KubernetesHelper.GetOsirisResources(Namespace)); } } else { var sb = new StringBuilder(); sb.AppendLine(KubernetesHelper.GetKedaResources(Namespace)); if (!KedaOnly) { sb.AppendLine(KubernetesHelper.GetOsirisResources(Namespace)); } if (!await KubernetesHelper.NamespaceExists(Namespace)) { await KubernetesHelper.CreateNamespace(Namespace); } await KubectlHelper.KubectlApply(sb.ToString(), showOutput : true); } }
private async Task CreateNamespace(string name) { if (!await KubernetesHelper.NamespaceExists(name)) { await KubernetesHelper.CreateNamespace(name); } }
public override ICommandLineParserResult ParseArgs(string[] args) { SetFlag <string>("name", "The name used for the deployment and other artifacts in kubernetes", n => { KubernetesHelper.ValidateKubernetesName(n); Name = n; }, isRequired: true); SetFlag <string>("image-name", "Image to use for the pod deployment and to read functions from", n => ImageName = n); SetFlag <string>("registry", "When set, a docker build is run and the image is pushed to that registry/name. This is mutually exclusive with --image-name. For docker hub, use username.", r => Registry = r); SetFlag <string>("namespace", "Kubernetes namespace to deploy to. Default: default", ns => Namespace = ns); SetFlag <string>("pull-secret", "The secret holding a private registry credentials", s => PullSecret = s); SetFlag <int>("polling-interval", "The polling interval for checking non-http triggers. Default: 30 (seconds)", p => PollingInterval = p); SetFlag <int>("cooldown-period", "The cooldown period for the deployment before scaling back to 0 after all triggers are no longer active. Default: 300 (seconds)", p => CooldownPeriod = p); SetFlag <int>("min-replicas", "Minimum replica count", m => MinReplicaCount = m); SetFlag <int>("max-replicas", "Maximum replica count to scale to by HPA", m => MaxReplicaCount = m); SetFlag <string>("keys-secret-name", "The name of a kubernetes secret collection to use for the function app keys (host keys, function keys etc.)", ksn => KeysSecretCollectionName = ksn); SetFlag <bool>("mount-funckeys-as-containervolume", "The flag indicating to mount the func app keys as container volume", kmv => MountFuncKeysAsContainerVolume = kmv); SetFlag <string>("secret-name", "The name of an existing kubernetes secret collection, containing func app settings, to use in the deployment instead of creating new a new one based upon local.settings.json", sn => SecretsCollectionName = sn); SetFlag <string>("config-map-name", "The name of an existing config map with func app settings to use in the deployment", cm => ConfigMapName = cm); SetFlag <string>("service-type", "Kubernetes Service Type. Default LoadBalancer Valid options: " + string.Join(",", ServiceTypes), s => { if (!string.IsNullOrEmpty(s) && !ServiceTypes.Contains(s)) { throw new CliArgumentsException($"serviceType {ServiceType} is not supported. Valid options are: {string.Join(",", ServiceTypes)}"); } ServiceType = s; }); SetFlag <bool>("no-docker", "With --image-name, the core-tools will inspect the functions inside the image. This will require mounting the image filesystem. Passing --no-docker uses current directory for functions.", nd => NoDocker = nd); SetFlag <bool>("use-config-map", "Use a ConfigMap/V1 instead of a Secret/V1 object for function app settings configurations", c => UseConfigMap = c); SetFlag <bool>("dry-run", "Show the deployment template", f => DryRun = f); SetFlag <bool>("ignore-errors", "Proceed with the deployment if a resource returns an error. Default: false", f => IgnoreErrors = f); return(base.ParseArgs(args)); }
private async Task CreateAutoscaler(string deploymentName, string nameSpace, int minInstances, int maxInstances, int cpuPercentage = 60) { var cmd = $"autoscale deploy {deploymentName} --cpu-percent={cpuPercentage} --max={maxInstances} --min={minInstances} --namespace={nameSpace}"; if (!string.IsNullOrEmpty(configFile)) { cmd += $" --kubeconfig {configFile}"; } await KubernetesHelper.RunKubectl(cmd); }
public void ValidateKubernetesNames(string name, bool isValid) { try { KubernetesHelper.ValidateKubernetesName(name); } catch { if (isValid) { throw; } } }
public async override Task RunAsync() { if (DryRun) { ColoredConsole.WriteLine(KubernetesHelper.GetKedaResources(Namespace)); } else { if (!await KubernetesHelper.NamespaceExists(Namespace)) { await KubernetesHelper.CreateNamespace(Namespace); } await KubectlHelper.KubectlApply(KubernetesHelper.GetKedaResources(Namespace), showOutput : true); } }
private async Task Deploy(string name, string image, string nameSpace, int min, int max) { var isHTTP = IsHTTPTrigger(name); await CreateNamespace(nameSpace); client.DefaultNamespace = nameSpace; ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Deploying function to Knative..."); var knativeService = GetKnativeService(name, image, nameSpace, min, max, isHTTP); var json = Newtonsoft.Json.JsonConvert.SerializeObject(knativeService, Newtonsoft.Json.Formatting.None, new Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore }); File.WriteAllText("deployment.json", json); await KubernetesHelper.RunKubectl($"apply -f deployment.json"); File.Delete("deployment.json"); var endpoint = await GetIstioClusterIngressEndpoint(); var host = GetFunctionHost(name, nameSpace); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Function deployed successfully!"); ColoredConsole.WriteLine(); if (string.IsNullOrEmpty(endpoint)) { ColoredConsole.WriteLine($"Function URL: http://{endpoint}"); } else { ColoredConsole.WriteLine("Couldn't identify Function URL: Couldn't find Istio Cluster Ingress endpoint"); } ColoredConsole.WriteLine($"Function Host: {host}"); ColoredConsole.WriteLine(); ColoredConsole.WriteLine("Plese note: it may take a few minutes for the knative service to be reachable"); }
public void PopulateMetadataDictionary_CorrectlyPopulatesRabbitMQMetadata() { string jsonText = @" { ""type"": ""rabbitMQTrigger"", ""connectionStringSetting"": ""RabbitMQConnection"", ""queueName"": ""myQueue"", ""name"": ""message"" }"; JToken jsonObj = JToken.Parse(jsonText); IDictionary <string, string> metadata = KubernetesHelper.PopulateMetadataDictionary(jsonObj); Assert.Equal(4, metadata.Count); Assert.True(metadata.ContainsKey("type")); Assert.True(metadata.ContainsKey("host")); Assert.True(metadata.ContainsKey("name")); Assert.True(metadata.ContainsKey("queueName")); Assert.Equal("rabbitMQTrigger", metadata["type"]); Assert.Equal("RabbitMQConnection", metadata["host"]); Assert.Equal("message", metadata["name"]); Assert.Equal("myQueue", metadata["queueName"]); }
private async Task Deploy(string name, string image, string nameSpace, int min, int max, double cpu = 0.1, int memory = 128, string port = "80") { await CreateNamespace(nameSpace); client.DefaultNamespace = nameSpace; var deploymentName = $"{name}-deployment"; await DeleteDeploymentIfExists(deploymentName, nameSpace); ColoredConsole.WriteLine("Deploying function to Kubernetes..."); var deployment = GetDeployment(deploymentName, image, cpu, memory, port, nameSpace, min); var json = Newtonsoft.Json.JsonConvert.SerializeObject(deployment, Newtonsoft.Json.Formatting.None, new Newtonsoft.Json.JsonSerializerSettings { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore }); File.WriteAllText("deployment.json", json); KubernetesHelper.RunKubectl($"apply -f deployment.json"); ColoredConsole.WriteLine("Deployment successful"); var service = GetService(deploymentName, nameSpace, port); try { // we can safely ignore the error here await client.ServicesV1().Create(service); } catch { } await TryRemoveAutoscaler(deploymentName, nameSpace); await CreateAutoscaler(deploymentName, nameSpace, min, max); var externalIP = ""; ColoredConsole.WriteLine("Waiting for External IP..."); while (string.IsNullOrEmpty(externalIP)) { var svc = await client.ServicesV1().Get($"{deploymentName}-service", nameSpace); if (svc != null) { if (svc.Status.LoadBalancer.Ingress.Count > 0) { externalIP = svc.Status.LoadBalancer.Ingress[0].Ip; } } } File.Delete("deployment.json"); ColoredConsole.WriteLine(""); ColoredConsole.WriteLine("Function deployed successfully!"); ColoredConsole.WriteLine($"Function IP: {externalIP}"); }
public override async Task RunAsync() { (var resolvedImageName, var shouldBuild) = ResolveImageName(); TriggersPayload triggers = null; if (DryRun) { if (shouldBuild) { // don't build on a --dry-run. // read files from the local dir triggers = await GetTriggersLocalFiles(); } else { triggers = await DockerHelpers.GetTriggersFromDockerImage(resolvedImageName); } } else { if (shouldBuild) { await DockerHelpers.DockerBuild(resolvedImageName, Environment.CurrentDirectory); } triggers = await DockerHelpers.GetTriggersFromDockerImage(resolvedImageName); } (var resources, var funcKeys) = await KubernetesHelper.GetFunctionsDeploymentResources( Name, resolvedImageName, Namespace, triggers, _secretsManager.GetSecrets(), PullSecret, SecretsCollectionName, ConfigMapName, UseConfigMap, PollingInterval, CooldownPeriod, ServiceType, MinReplicaCount, MaxReplicaCount, KeysSecretCollectionName, MountFuncKeysAsContainerVolume); if (DryRun) { ColoredConsole.WriteLine(KubernetesHelper.SerializeResources(resources, OutputSerializationOptions.Yaml)); } else { if (!await KubernetesHelper.NamespaceExists(Namespace)) { await KubernetesHelper.CreateNamespace(Namespace); } if (shouldBuild) { await DockerHelpers.DockerPush(resolvedImageName); } foreach (var resource in resources) { await KubectlHelper.KubectlApply(resource, showOutput : true, ignoreError : IgnoreErrors, @namespace : Namespace); } //Print the function keys message to the console await KubernetesHelper.PrintFunctionsInfo($"{Name}-http", Namespace, funcKeys, triggers); } }
/// <summary> /// Constructer used by unit tests /// </summary> /// <param name="kubernetesHelper">Kubernetes Helper class instance to use</param> internal NamespaceCountHandler(KubernetesHelper kubernetesHelper) { this.kubernetesHelper = kubernetesHelper; }
/// <summary> /// Constructer used by unit tests /// </summary> /// <param name="kubernetesHelper">Kubernetes Helper class instance to use</param> internal PodCountHandler(KubernetesHelper kubernetesHelper) { this.kubernetesHelper = kubernetesHelper; }
public async override Task RunAsync() { await KubernetesHelper.RemoveKeda(Namespace); }
/// <summary> /// Constructer used by unit tests /// </summary> /// <param name="kubernetesHelper">Kubernetes Helper class instance to use</param> internal NodeRamUsageHandler(KubernetesHelper kubernetesHelper) { this.kubernetesHelper = kubernetesHelper; }
private async Task CreateNamespace(string name) { await KubernetesHelper.RunKubectl($"create ns {name}"); }
/// <summary> /// Constructer used by unit tests /// </summary> /// <param name="kubernetesHelper">Kubernetes Helper class instance to use</param> internal PodCPUUsageHandler(KubernetesHelper kubernetesHelper) { this.kubernetesHelper = kubernetesHelper; }
public async Task GetKubernetesFunctionLogs(string functionName) { string nameSpace = KUBERNETES_DEFAULT_NAMESPACE; await KubernetesHelper.RunKubectl($"logs -l app={functionName}-deployment -n {nameSpace}", true); }
private async Task TryRemoveAutoscaler(string deploymentName, string nameSpace) { await KubernetesHelper.RunKubectl($"delete hpa {deploymentName} -n {nameSpace}"); }