From 9e9ff2c22ec48cb853603ff2951538cca00a3d6a Mon Sep 17 00:00:00 2001 From: Daniele Martinoli Date: Mon, 11 Jul 2022 15:25:09 +0200 Subject: [PATCH 1/4] Changes to match Serverless Framework updates --- src/serverless.js | 81 ++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/src/serverless.js b/src/serverless.js index 753bdba..d3069a2 100644 --- a/src/serverless.js +++ b/src/serverless.js @@ -1,21 +1,21 @@ +const path = require('path') +const { isEmpty, mergeDeepRight } = require('ramda') const kubernetes = require('@kubernetes/client-node') const { Component } = require('@serverless/core') const defaults = { + kubeConfigPath: path.join(process.env.HOME, '.kube', 'config'), knativeGroup: 'serving.knative.dev', - knativeVersion: 'v1alpha1', + knativeVersion: 'v1', registryAddress: 'docker.io', namespace: 'default' } class KnativeServing extends Component { - async deploy(inputs = {}) { - const config = { - ...defaults, - ...inputs - } + async default(inputs = {}) { + const config = mergeDeepRight(defaults, inputs) - const k8sCustom = this.getKubernetesClient(kubernetes.CustomObjectsApi) + const k8sCustom = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CustomObjectsApi) let serviceExists = true try { @@ -41,13 +41,12 @@ class KnativeServing extends Component { } async remove(inputs = {}) { - const config = { - ...defaults, - ...inputs, - ...this.state + let config = mergeDeepRight(defaults, inputs) + if (isEmpty(config)) { + config = this.state } - const k8sCustom = this.getKubernetesClient(kubernetes.CustomObjectsApi) + const k8sCustom = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CustomObjectsApi) let params = Object.assign({}, config) const manifest = this.getManifest(params) @@ -55,9 +54,22 @@ class KnativeServing extends Component { await this.deleteService(k8sCustom, params) this.state = {} + await this.save() return {} } + async info(inputs = {}) { + const config = mergeDeepRight(defaults, inputs) + + const k8sCustom = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CustomObjectsApi) + const serviceUrls = await this.getServiceUrls(k8sCustom, config) + config.serviceUrls = serviceUrls + + this.state = config + await this.save() + return this.state + } + // "private" methods async getServiceUrl(k8s, config) { let url @@ -71,30 +83,27 @@ class KnativeServing extends Component { return url } - getKubernetesClient(type) { - const { endpoint, port } = this.credentials.kubernetes - const token = this.credentials.kubernetes.serviceAccountToken - const skipTLSVerify = this.credentials.kubernetes.skipTlsVerify == 'true' - const kc = new kubernetes.KubeConfig() - kc.loadFromOptions({ - clusters: [ - { - name: 'cluster', - skipTLSVerify, - server: `${endpoint}:${port}` - } - ], - users: [{ name: 'user', token }], - contexts: [ - { - name: 'context', - user: 'user', - cluster: 'cluster' - } - ], - currentContext: 'context' - }) - return kc.makeApiClient(type) + async getServiceUrls(k8s, config) { + let urls = new Map() + do { + const services = await this.listServices(k8s, config) + if (services.response.statusCode == 200 && services.body.items) { + services.body.items.forEach( s => { + const serviceName = s.metadata.name + const serviceUrl = s.status.url + urls.set(serviceName, serviceUrl) + }) + } + await new Promise((resolve) => setTimeout(() => resolve(), 2000)) + } while (!urls) + return urls + } + + getKubernetesClient(configPath, type) { + let kc = new kubernetes.KubeConfig() + kc.loadFromFile(configPath) + kc = kc.makeApiClient(type) + return kc } getManifest(svc) { From d8ca87af7452158a25c3afe6709e281db2e574bb Mon Sep 17 00:00:00 2001 From: Daniele Martinoli Date: Thu, 14 Jul 2022 10:33:36 +0200 Subject: [PATCH 2/4] Fetching IstioIngress to restore K8s runtime option --- src/serverless.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/serverless.js b/src/serverless.js index d3069a2..001cea9 100644 --- a/src/serverless.js +++ b/src/serverless.js @@ -15,6 +15,7 @@ class KnativeServing extends Component { async default(inputs = {}) { const config = mergeDeepRight(defaults, inputs) + const k8sCore = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CoreV1Api) const k8sCustom = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CustomObjectsApi) let serviceExists = true @@ -36,6 +37,9 @@ class KnativeServing extends Component { const serviceUrl = await this.getServiceUrl(k8sCustom, config) config.serviceUrl = serviceUrl + const istioIngressIp = await this.getIstioIngressIp(k8sCore) + config.istioIngressIp = istioIngressIp + this.state = config return this.state } @@ -61,16 +65,27 @@ class KnativeServing extends Component { async info(inputs = {}) { const config = mergeDeepRight(defaults, inputs) + const k8sCore = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CoreV1Api) const k8sCustom = this.getKubernetesClient(config.kubeConfigPath, kubernetes.CustomObjectsApi) const serviceUrls = await this.getServiceUrls(k8sCustom, config) config.serviceUrls = serviceUrls + const istioIngressIp = await this.getIstioIngressIp(k8sCore) + config.istioIngressIp = istioIngressIp + this.state = config await this.save() return this.state } // "private" methods + async getIstioIngressIp(k8s) { + const res = await k8s.readNamespacedService('istio-ingressgateway', 'istio-system') + if (res.body && res.body.status.loadBalancer && res.body.status.loadBalancer.ingress) { + return res.body.status.loadBalancer.ingress[0].ip + } + } + async getServiceUrl(k8s, config) { let url do { From 5eb694b274acd17d33086be40aa89ff27d7a2dc9 Mon Sep 17 00:00:00 2001 From: Daniele Martinoli Date: Thu, 14 Jul 2022 16:27:39 +0200 Subject: [PATCH 3/4] Added autoscaler annotations to the generated manifest --- src/serverless.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/serverless.js b/src/serverless.js index 001cea9..75420e6 100644 --- a/src/serverless.js +++ b/src/serverless.js @@ -133,6 +133,14 @@ class KnativeServing extends Component { if (svc.pullPolicy) { imageConfig.imagePullPolicy = svc.pullPolicy } + + const annotations = {} + if (svc.autoscaler) { + for (const key in svc.autoscaler) { + const value = (typeof svc.autoscaler[key] == 'number') ? svc.autoscaler[key].toString() : svc.autoscaler[key] + annotations[`autoscaling.knative.dev/${key}`] = value + } + } return { apiVersion: `${svc.knativeGroup}/${svc.knativeVersion}`, kind: 'Service', @@ -142,6 +150,9 @@ class KnativeServing extends Component { }, spec: { template: { + metadata: { + annotations + }, spec: { containers: [ imageConfig From 03d42970432b0362ea1b918065f4cba439192f6d Mon Sep 17 00:00:00 2001 From: Tomer Figenblat Date: Fri, 19 Aug 2022 11:54:13 +0300 Subject: [PATCH 4/4] fix: ignore istio service fetch error for using kourier environment Signed-off-by: Tomer Figenblat --- src/serverless.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/serverless.js b/src/serverless.js index 75420e6..fe75c45 100644 --- a/src/serverless.js +++ b/src/serverless.js @@ -80,9 +80,13 @@ class KnativeServing extends Component { // "private" methods async getIstioIngressIp(k8s) { - const res = await k8s.readNamespacedService('istio-ingressgateway', 'istio-system') - if (res.body && res.body.status.loadBalancer && res.body.status.loadBalancer.ingress) { - return res.body.status.loadBalancer.ingress[0].ip + try { + const res = await k8s.readNamespacedService('istio-ingressgateway', 'istio-system') + if (res.body && res.body.status.loadBalancer && res.body.status.loadBalancer.ingress) { + return res.body.status.loadBalancer.ingress[0].ip + } + } catch (_err) { + // ignore istio errors to leverage usage of kourier } }