internal async static Task <(IEnumerable <IKubernetesResource>, IDictionary <string, string>)> GetFunctionsDeploymentResources( string name, string imageName, string @namespace, TriggersPayload triggers, IDictionary <string, string> secrets, string pullSecret = null, string secretsCollectionName = null, string configMapName = null, bool useConfigMap = false, int?pollingInterval = null, int?cooldownPeriod = null, string serviceType = "LoadBalancer", int?minReplicas = null, int?maxReplicas = null, string keysSecretCollectionName = null, bool mountKeysAsContainerVolume = false) { ScaledObjectV1Alpha1 scaledobject = null; var result = new List <IKubernetesResource>(); var deployments = new List <DeploymentV1Apps>(); var httpFunctions = triggers.FunctionsJson .Where(b => b.Value["bindings"]?.Any(e => e?["type"].ToString().IndexOf("httpTrigger", StringComparison.OrdinalIgnoreCase) != -1) == true); var nonHttpFunctions = triggers.FunctionsJson.Where(f => httpFunctions.All(h => h.Key != f.Key)); keysSecretCollectionName = string.IsNullOrEmpty(keysSecretCollectionName) ? $"func-keys-kube-secret-{name}" : keysSecretCollectionName; if (httpFunctions.Any()) { int position = 0; var enabledFunctions = httpFunctions.ToDictionary(k => $"AzureFunctionsJobHost__functions__{position++}", v => v.Key); //Environment variables for the func app keys kubernetes secret var kubernetesSecretEnvironmentVariable = FuncAppKeysHelper.FuncKeysKubernetesEnvironVariables(keysSecretCollectionName, mountKeysAsContainerVolume); var additionalEnvVars = enabledFunctions.Concat(kubernetesSecretEnvironmentVariable).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var deployment = GetDeployment(name + "-http", @namespace, imageName, pullSecret, 1, additionalEnvVars, port: 80); deployments.Add(deployment); var service = GetService(name + "-http", @namespace, deployment, serviceType); result.Add(service); } if (nonHttpFunctions.Any()) { int position = 0; var enabledFunctions = nonHttpFunctions.ToDictionary(k => $"AzureFunctionsJobHost__functions__{position++}", v => v.Key); var deployment = GetDeployment(name, @namespace, imageName, pullSecret, minReplicas ?? 0, enabledFunctions); deployments.Add(deployment); scaledobject = GetScaledObject(name, @namespace, triggers, deployment, pollingInterval, cooldownPeriod, minReplicas, maxReplicas); } // Set worker runtime if needed. if (!secrets.ContainsKey(Constants.FunctionsWorkerRuntime)) { secrets[Constants.FunctionsWorkerRuntime] = GlobalCoreToolsSettings.CurrentWorkerRuntime.ToString(); } int resourceIndex = 0; if (useConfigMap) { var configMap = GetConfigMap(name, @namespace, secrets); result.Insert(resourceIndex, configMap); resourceIndex++; foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { ConfigMapRef = new NamedObjectV1 { Name = configMap.Metadata.Name } } }; } } else if (!string.IsNullOrEmpty(secretsCollectionName)) { foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { SecretRef = new NamedObjectV1 { Name = secretsCollectionName } } }; } } else if (!string.IsNullOrEmpty(configMapName)) { foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { ConfigMapRef = new NamedObjectV1 { Name = configMapName } } }; } } else { var secret = GetSecret(name, @namespace, secrets); result.Insert(resourceIndex, secret); resourceIndex++; foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { SecretRef = new NamedObjectV1 { Name = secret.Metadata.Name } } }; } } IDictionary <string, string> resultantFunctionKeys = new Dictionary <string, string>(); if (httpFunctions.Any()) { var currentImageFuncKeys = FuncAppKeysHelper.CreateKeys(httpFunctions.Select(f => f.Key)); resultantFunctionKeys = GetFunctionKeys(currentImageFuncKeys, await GetExistingFunctionKeys(keysSecretCollectionName, @namespace)); if (resultantFunctionKeys?.Any() == true) { result.Insert(resourceIndex, GetSecret(keysSecretCollectionName, @namespace, resultantFunctionKeys)); resourceIndex++; } //if function keys Secrets needs to be mounted as volume in the function runtime container if (mountKeysAsContainerVolume) { FuncAppKeysHelper.CreateFuncAppKeysVolumeMountDeploymentResource(deployments, keysSecretCollectionName); } //Create the Pod identity with the role to modify the function kubernetes secret else { var svcActName = $"{name}-function-keys-identity-svc-act"; var svcActDeploymentResource = GetServiceAccount(svcActName, @namespace); result.Insert(resourceIndex, svcActDeploymentResource); resourceIndex++; var funcKeysManagerRoleName = "functions-keys-manager-role"; var secretManagerRole = GetSecretManagerRole(funcKeysManagerRoleName, @namespace); result.Insert(resourceIndex, secretManagerRole); resourceIndex++; var roleBindingName = $"{svcActName}-functions-keys-manager-rolebinding"; var funcKeysRoleBindingDeploymentResource = GetRoleBinding(roleBindingName, @namespace, funcKeysManagerRoleName, svcActName); result.Insert(resourceIndex, funcKeysRoleBindingDeploymentResource); resourceIndex++; //add service account identity to the pod foreach (var deployment in deployments) { deployment.Spec.Template.Spec.ServiceAccountName = svcActName; } } } result = result.Concat(deployments).ToList(); return(scaledobject != null ? result.Append(scaledobject) : result, resultantFunctionKeys); }
internal static IEnumerable <IKubernetesResource> GetFunctionsDeploymentResources( string name, string imageName, string @namespace, TriggersPayload triggers, IDictionary <string, string> secrets, string pullSecret = null, string secretsCollectionName = null, string configMapName = null, bool useConfigMap = false, int?pollingInterval = null, int?cooldownPeriod = null, string serviceType = "LoadBalancer", int?minReplicas = null, int?maxReplicas = null) { ScaledObjectV1Alpha1 scaledobject = null; var result = new List <IKubernetesResource>(); var deployments = new List <DeploymentV1Apps>(); var httpFunctions = triggers.FunctionsJson .Where(b => b.Value["bindings"]?.Any(e => e?["type"].ToString().IndexOf("httpTrigger", StringComparison.OrdinalIgnoreCase) != -1) == true); var nonHttpFunctions = triggers.FunctionsJson.Where(f => httpFunctions.All(h => h.Key != f.Key)); if (httpFunctions.Any()) { int position = 0; var enabledFunctions = httpFunctions.ToDictionary(k => $"AzureFunctionsJobHost__functions__{position++}", v => v.Key); var deployment = GetDeployment(name + "-http", @namespace, imageName, pullSecret, 1, enabledFunctions, new Dictionary <string, string> { { "osiris.deislabs.io/enabled", "true" }, { "osiris.deislabs.io/minReplicas", "1" } }, port: 80); deployments.Add(deployment); var service = GetService(name + "-http", @namespace, deployment, serviceType, new Dictionary <string, string> { { "osiris.deislabs.io/enabled", "true" }, { "osiris.deislabs.io/deployment", deployment.Metadata.Name } }); result.Add(service); } if (nonHttpFunctions.Any()) { int position = 0; var enabledFunctions = nonHttpFunctions.ToDictionary(k => $"AzureFunctionsJobHost__functions__{position++}", v => v.Key); var deployment = GetDeployment(name, @namespace, imageName, pullSecret, minReplicas ?? 0, enabledFunctions); deployments.Add(deployment); scaledobject = GetScaledObject(name, @namespace, triggers, deployment, pollingInterval, cooldownPeriod, minReplicas, maxReplicas); } // Set worker runtime if needed. if (!secrets.ContainsKey(Constants.FunctionsWorkerRuntime)) { secrets[Constants.FunctionsWorkerRuntime] = GlobalCoreToolsSettings.CurrentWorkerRuntime.ToString(); } if (useConfigMap) { var configMap = GetConfigMap(name, @namespace, secrets); result.Insert(0, configMap); foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { ConfigMapRef = new NamedObjectV1 { Name = configMap.Metadata.Name } } }; } } else if (!string.IsNullOrEmpty(secretsCollectionName)) { foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { SecretRef = new NamedObjectV1 { Name = secretsCollectionName } } }; } } else if (!string.IsNullOrEmpty(configMapName)) { foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { ConfigMapRef = new NamedObjectV1 { Name = configMapName } } }; } } else { var secret = GetSecret(name, @namespace, secrets); result.Insert(0, secret); foreach (var deployment in deployments) { deployment.Spec.Template.Spec.Containers.First().EnvFrom = new ContainerEnvironmentFromV1[] { new ContainerEnvironmentFromV1 { SecretRef = new NamedObjectV1 { Name = secret.Metadata.Name } } }; } } result = result.Concat(deployments).ToList(); return(scaledobject != null ? result.Append(scaledobject) : result); }