From 05dc0a66e4bab6a93ab05ea90be7d175c59b26b2 Mon Sep 17 00:00:00 2001 From: LCW Date: Sun, 24 Jul 2022 14:12:14 +0800 Subject: [PATCH 01/74] feat: add openfunction plugin --- apisix/plugins/openfunction.lua | 104 ++++++++++++++++++++++++++++++++ conf/config-default.yaml | 1 + 2 files changed, 105 insertions(+) create mode 100644 apisix/plugins/openfunction.lua diff --git a/apisix/plugins/openfunction.lua b/apisix/plugins/openfunction.lua new file mode 100644 index 000000000000..3d5dfe99ac11 --- /dev/null +++ b/apisix/plugins/openfunction.lua @@ -0,0 +1,104 @@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one or more +-- contributor license agreements. See the NOTICE file distributed with +-- this work for additional information regarding copyright ownership. +-- The ASF licenses this file to You under the Apache License, Version 2.0 +-- (the "License"); you may not use this file except in compliance with +-- the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +local core = require("apisix.core") +local http = require("resty.http") +local ngx_encode_base64 = ngx.encode_base64 + +local schema = { + type = "object", + properties = { + function_uri = {type = "string"}, + ssl_verify = { + type = "boolean", + default = true, + }, + service_token = {type = "string"}, + timeout = { + type = "integer", + minimum = 1, + maximum = 60000, + default = 60000, + description = "timeout in milliseconds", + }, + keepalive = {type = "boolean", default = true}, + keepalive_timeout = {type = "integer", minimum = 1000, default = 60000}, + keepalive_pool = {type = "integer", minimum = 1, default = 5} + }, + required = {"function_uri"} +} + + +local _M = { + version = 0.1, + priority = -1902, + name = "openfunction", + schema = schema, +} + + +function _M.check_schema(conf) + local ok, err = core.schema.check(schema, conf) + if not ok then + return false, err + end + + return true +end + + +function _M.access(conf, ctx) + local params = { + method = ngx.req.get_method(), + body = core.request.get_body(), + keepalive = conf.keepalive, + ssl_verify = conf.ssl_verify, + headers = core.request.headers(ctx) or {} + } + + -- setting authorization headers if not already set + if not params.headers["Authorization"] and conf.service_token then + params.headers["Authorization"] = "Basic " .. ngx_encode_base64(conf.service_token) + end + + if conf.keepalive then + params.keepalive_timeout = conf.keepalive_timeout + params.keepalive_pool = conf.keepalive_pool + end + + local endpoint = conf.function_uri + local httpc = http.new() + httpc:set_timeout(conf.timeout) + + local res, err = httpc:request_uri(endpoint, params) + + if not res then + core.log.error("failed to process ",_M.name, ", err: ", err) + return 503 + end + + -- setting response headers + if res.headers ~= nil then + core.response.set_header(res.headers) + end + + return res.status, res.body + +end + + +return _M diff --git a/conf/config-default.yaml b/conf/config-default.yaml index 642d4e89de41..acaf0f9a0063 100755 --- a/conf/config-default.yaml +++ b/conf/config-default.yaml @@ -471,6 +471,7 @@ plugins: # plugin list (sorted by priority) - aws-lambda # priority: -1899 - azure-functions # priority: -1900 - openwhisk # priority: -1901 + - openfunction # priority: -1902 - serverless-post-function # priority: -2000 - ext-plugin-post-req # priority: -3000 - ext-plugin-post-resp # priority: -4000 From fc8a099f6616e3b8e21a17753ec9bca982aadbe2 Mon Sep 17 00:00:00 2001 From: LCW Date: Thu, 4 Aug 2022 16:46:19 +0800 Subject: [PATCH 02/74] feat: add openfunction plugin --- docs/en/latest/config.json | 3 +- t/admin/plugins.t | 1 + t/plugin/openfunction.t | 253 +++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 t/plugin/openfunction.t diff --git a/docs/en/latest/config.json b/docs/en/latest/config.json index 939a5cac91c3..6eebc2cf90e9 100644 --- a/docs/en/latest/config.json +++ b/docs/en/latest/config.json @@ -165,7 +165,8 @@ "plugins/serverless", "plugins/azure-functions", "plugins/openwhisk", - "plugins/aws-lambda" + "plugins/aws-lambda", + "plugins/openfunction" ] }, { diff --git a/t/admin/plugins.t b/t/admin/plugins.t index 1d78b2432989..462760d19d86 100644 --- a/t/admin/plugins.t +++ b/t/admin/plugins.t @@ -126,6 +126,7 @@ example-plugin aws-lambda azure-functions openwhisk +openfunction serverless-post-function ext-plugin-post-req ext-plugin-post-resp diff --git a/t/plugin/openfunction.t b/t/plugin/openfunction.t new file mode 100644 index 000000000000..91ff08269ce0 --- /dev/null +++ b/t/plugin/openfunction.t @@ -0,0 +1,253 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +use t::APISIX 'no_plan'; + +repeat_each(1); +no_long_string(); +no_root_location(); + +add_block_preprocessor(sub { + my ($block) = @_; + + if ((!defined $block->error_log) && (!defined $block->no_error_log)) { + $block->set_value("no_error_log", "[error]"); + } + + if (!defined $block->request) { + $block->set_value("request", "GET /t"); + } +}); + +run_tests(); + +__DATA__ + +=== TEST 1: sanity +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.openfunction") + local ok, err = plugin.check_schema({function_uri = "http://60.188.58.218:30585/default/function-sample", service_token = "test:test"}) + if not ok then + ngx.say(err) + end + + ngx.say("done") + } + } +--- response_body +done + + + +=== TEST 2: missing `function_uri` +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.openfunction") + local ok, err = plugin.check_schema({service_token = "test:test"}) + if not ok then + ngx.say(err) + end + } + } +--- response_body +property "function_uri" is required + + + +=== TEST 3: wrong type for `function_uri` +--- config + location /t { + content_by_lua_block { + local plugin = require("apisix.plugins.openfunction") + local ok, err = plugin.check_schema({function_uri = 30858, service_token = "test:test"}) + if not ok then + ngx.say(err) + end + } + } +--- response_body +property "function_uri" validation failed: wrong type: expected string, got number + + + +=== TEST 4: setup route with plugin +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "openfunction": { + "function_uri": "http://60.188.58.218:30585/default/function-sample/world", + "service_token": "test:test" + } + }, + "upstream": { + "nodes": {}, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + + +=== TEST 5: hit route (with GET request) +--- request +GET /hello +--- response_body +Hello, world! + + + +=== TEST 6: reset route with test-body function +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "openfunction": { + "function_uri": "http://127.0.0.1:30585/default/test-body", + "service_token": "test:test" + } + }, + "upstream": { + "nodes": {}, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + +=== TEST 7: hit route with POST method +--- request +POST /hello +test +--- response_body +Hello, test! + + +=== TEST 8: reset route with test-body function without service_token +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "openfunction": { + "function_uri": "http://127.0.0.1:30585/default/test-body" + } + }, + "upstream": { + "nodes": {}, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + +=== TEST 9: hit route with POST request when openfunction required basic auth +--- request +POST /hello +test +--- error_code: 401 +--- response_body_like eval +qr/401 Authorization Required/ + + + + +=== TEST 10: reset route to non-existent function_uri +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "plugins": { + "openfunction": { + "function_uri": "http://127.0.0.1:30585/default/non-existent", + "service_token": "test:test" + } + }, + "upstream": { + "nodes": {}, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- response_body +passed + + + +=== TEST 11: hit route (with non-existent function_uri) +--- request +POST /hello +test +--- more_headers +Content-Type: application/x-www-form-urlencoded +--- error_code: 404 +--- response_body_like eval +qr/404 Not Found/ From 2b46f002734962d0bef7ad751670d66be52ffd1c Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 8 Aug 2022 10:46:50 +0800 Subject: [PATCH 03/74] fix: change test uri --- t/plugin/openfunction.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/plugin/openfunction.t b/t/plugin/openfunction.t index 91ff08269ce0..3f9802279038 100644 --- a/t/plugin/openfunction.t +++ b/t/plugin/openfunction.t @@ -41,7 +41,7 @@ __DATA__ location /t { content_by_lua_block { local plugin = require("apisix.plugins.openfunction") - local ok, err = plugin.check_schema({function_uri = "http://60.188.58.218:30585/default/function-sample", service_token = "test:test"}) + local ok, err = plugin.check_schema({function_uri = "http://127.0.0.1:30585/default/function-sample", service_token = "test:test"}) if not ok then ngx.say(err) end @@ -96,7 +96,7 @@ property "function_uri" validation failed: wrong type: expected string, got numb [[{ "plugins": { "openfunction": { - "function_uri": "http://60.188.58.218:30585/default/function-sample/world", + "function_uri": "http://127.0.0.1:30585/default/function-sample/world", "service_token": "test:test" } }, From 0c3887ae2607659ef9cf658dad29e1300366a529 Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 8 Aug 2022 13:37:22 +0800 Subject: [PATCH 04/74] CI: prepare openfunction env --- ci/init-plugin-test-service.sh | 68 ++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index 5f468502304d..384cdc6cc9cb 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -41,3 +41,71 @@ docker exec -i rmqnamesrv /home/rocketmq/rocketmq-4.6.0/bin/mqadmin updateTopic # prepare vault kv engine docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv" + +# prepare openfunction env +prepare_kind_k8s() { + curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 + chmod +x ./kind + curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" + sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl + kind create cluster --name myk8s-01 +} + +install_openfuncntion() { + curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash + helm repo add openfunction https://openfunction.github.io/charts/ + helm repo update + kubectl create namespace openfunction + helm install openfunction --set global.Keda.enabled=false --set global.Dapr.enabled=false openfunction/openfunction -n openfunction + kubectl wait pods --all --for=condition=Ready --timeout=300s -n openfunction + kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission + kubectl delete deployment -n keda --all + kubectl delete deployment -n dapr-system --all + kubectl delete pod -n keda --all + kubectl delete pod -n dapr-system --all +} + +set_container_registry_secret() { + REGISTRY_SERVER=https://index.docker.io/v1/ REGISTRY_USER=apisixtestaccount123 REGISTRY_PASSWORD=apisixtestaccount + kubectl create secret docker-registry push-secret \ + --docker-server=$REGISTRY_SERVER \ + --docker-username=$REGISTRY_USER \ + --docker-password=$REGISTRY_PASSWORD +} + +create_functions() { + wget https://raw.githubusercontent.com/jackkkkklee/samples/release-0.6/functions/knative/hello-world-go/function-sample.yaml + wget https://raw.githubusercontent.com/jackkkkklee/samples/main/functions/knative/hello-world-go/function-sample-test-body.yaml + + kubectl apply -f function-sample.yaml + kubectl apply -f function-sample-test-body.yaml + + kubectl set resources deployment -n openfunction --all=true --requests=cpu=40m,memory=64Mi + kubectl set resources deployment -n kube-system --all=true --requests=cpu=50m,memory=64Mi + + kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Succeeded --timeout=300s + kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Running --timeout=300s + kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Succeeded --timeout=300s + kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Running --timeout=300s + +} + +set_ingress_controller() { + yum install -y httpd + htpasswd -cd auth test test + kubectl create secret generic basic-auth --from-file=auth + + kubectl patch ingress openfunction -p '{"metadata":{"annotations":{"nginx.ingress.kubernetes.io/auth-type":"basic","nginx.ingress.kubernetes.io/auth-secret":"basic-auth","nginx.ingress.kubernetes.io/auth-realm":"Authentication Required - test"}}}' + kubectl patch svc ingress-nginx-controller -n ingress-nginx -p $'spec:\n type: NodePort' + kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec":{"ports":[{"appProtocol":"http","name":"myhttp","nodePort": 30585,"port": 80,"protocol": "TCP", "targetPort": "http"}]}}' + } +port_forward() { + nohup kubectl port-forward --address 0.0.0.0 --namespace=ingress-nginx service/ingress-nginx-controller 30585:80 >/dev/null 2>&1 & +} + +prepare_kind_k8s +install_openfuncntion +set_container_registry_secret +create_functions +set_ingress_controller +port_forward From 3d549ec41c268fd3adedb0228c1872f4d6927bb0 Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 8 Aug 2022 13:39:17 +0800 Subject: [PATCH 05/74] docs: add openfunction plugins --- docs/en/latest/plugins/openfunction.md | 122 +++++++++++++++++++++++ docs/zh/latest/plugins/openfunction.md | 129 +++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 docs/en/latest/plugins/openfunction.md create mode 100644 docs/zh/latest/plugins/openfunction.md diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md new file mode 100644 index 000000000000..774d9c6e4f80 --- /dev/null +++ b/docs/en/latest/plugins/openfunction.md @@ -0,0 +1,122 @@ +--- +title: openfunction +keywords: + - APISIX + - Plugin + - OpenFunction + - openfunction +description: This document contains information about the CNCF OpenFunction Plugin. +--- + + + +## Description + +The `openfunction` Plugin is used to integrate APISIX with [CNCF OpenWhisk](https://openfunction.dev/) serverless platform. + +This Plugin can be configured on a Route and requests will be send to the configured OpenWhish API endpoint as the upstream. + +## Attributes + +| Name | Type | Required | Default | Valid values | Description | +| ----------------- | ------- | -------- | ------- | ------------ | ---------------------------------------------------------------------------------------------------------- | +| function_uri | string | True | | | function uri. For example, `https://localhost:30858/default/function-sample`. | +| ssl_verify | boolean | False | true | | When set to `true` verifies the SSL certificate. | +| service_token | string | False | | | The token format is 'xx:xx' which support basic auth for ingress controller, . | +| timeout | integer | False | 60000ms | [1, 60000]ms | OpenFunction action and HTTP call timeout in ms. | +| keepalive | boolean | False | true | | When set to `true` keeps the connection alive for reuse. | +| keepalive_timeout | integer | False | 60000ms | [1000,...]ms | Time is ms for connection to remain idle without closing. | +| keepalive_pool | integer | False | 5 | [1,...] | Maximum number of requests that can be sent on this connection before closing it. | + +:::note + +The `timeout` attribute sets the time taken by the OpenFunction to execute, and the timeout for the HTTP client in APISIX. OpenFunction calls may take time to pull the runtime image and start the container. So, if the value is set too small, it may cause a large number of requests to fail. + + +::: + +## Enabling the Plugin + +Before configuring the Plugin, you need to have OpenFunction running. The example below shows OpenFunction installed in Helm: + +```shell +#add the OpenFunction chart repository +helm repo add openfunction https://openfunction.github.io/charts/ +helm repo update + +#install the OpenFunction chart +kubectl create namespace openfunction +helm install openfunction openfunction/openfunction -n openfunction +``` + +You can then verify if OpenFunction is ready: + +```shell +kubectl get pods -namespace openfunction +``` + +You can then create a function follow the [sample](https://github.com/OpenFunction/samples) + +You can now configure the Plugin on a specific Route and point to this running OpenFunction service: + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/hello", + "plugins": { + "openfunction": { + "function_uri": "http://localhost:3233/default/function-sample/test", + "service_token": "foo:foo" + } + } +}' +``` + +## Example usage + +Once you have configured the Plugin, you can send a request to the Route and it will invoke the configured function: + +```shell +curl -i http://127.0.0.1:9080/hello +``` + +This will give back the response from the function: + +``` +hello, test! +``` + +## Disable Plugin + +To disable the `openfunction` Plugin, you can delete the corresponding JSON configuration from the Plugin configuration. APISIX will automatically reload and you do not have to restart for this to take effect. + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/index.html", + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } +}' +``` diff --git a/docs/zh/latest/plugins/openfunction.md b/docs/zh/latest/plugins/openfunction.md new file mode 100644 index 000000000000..a26c4f7c0a20 --- /dev/null +++ b/docs/zh/latest/plugins/openfunction.md @@ -0,0 +1,129 @@ +--- +title: openfunction +keywords: + - APISIX + - Plugin + - OpenFunction + - openfunction +description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信息及使用方法。 +--- + + + +## 描述 + +`openfunction` 插件用于将开源的分布式无服务器平台 [CNCF OpenFunction](https://openfunction.dev/) 作为动态上游集成至 APISIX。 + +启用 `openfunction` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 OpenFunction 的 function发起一个新的请求,然后 `openfunction` 插件会将响应信息返回至客户端。 + +## 属性 + +| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | +| ----------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ | +| function_uri | string | 是 | | | OpenFunction function uri,例如 `https://localhost:30858/default/function-sample`。 | +| ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 | +| service_token | string | 是 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持ingress controller的basic auth认证方式。 | +| timeout | integer | 否 | 60000ms | [1,60000]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | +| keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 | +| keepalive_timeout | integer | 否 | 60000ms | [1000,...]ms | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 | +| keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 | + +:::note + +`timeout` 字段规定了 OpenFunction function 的最大执行时间,以及 APISIX 中 HTTP 客户端的请求超时时间。 + +因为 OpenFunction function 调用可能会耗费很长时间来拉取容器镜像和启动容器,所以如果 `timeout` 字段值设置太小,可能会导致大量的失败请求。 + + +::: + +## 启用插件 + +### 搭建 Apache OpenFunction 测试环境 + +1. 在使用 `openfunction` 插件之前,你需要通过以下命令运行 OpenFunction 。请确保当前环境中已经安装 Kubernetes 软件。 + +```shell +#add the OpenFunction chart repository +helm repo add openfunction https://openfunction.github.io/charts/ +helm repo update + +#install the OpenFunction chart +kubectl create namespace openfunction +helm install openfunction openfunction/openfunction -n openfunction +``` + +2. 你可以通过以下命令来验证openfunction是否已经安装成功: +```shell +kubectl get pods -namespace openfunction +``` + +3. 你可以通过官方示例创建函数 [sample](https://github.com/OpenFunction/samples) + + + +### 创建路由 + +通过以下命令创建一个路由,并在配置文件中添加 `openfunction` 插件: + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "uri": "/hello", + "plugins": { + "openfunction": { + "function_uri": "http://localhost:3233/default/function-sample/test", + "service_token": "foo:foo" + } + } +}' +``` + +### 测试请求 + +使用 `curl` 命令测试: + +```shell +curl -i http://127.0.0.1:9080/hello +``` + +正常返回结果: + +``` +hello, test! +``` + +## 禁用插件 + +当你需要禁用 `openfunction` 插件时,可以通过以下命令删除相应的 JSON 配置,APISIX 将会自动重新加载相关配置,无需重启服务: + +```shell +curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d ' +{ + "methods": ["GET"], + "uri": "/hello", + "upstream": { + "type": "roundrobin", + "nodes": { + "127.0.0.1:1980": 1 + } + } +}' +``` From e13f8703aebd10fd8547cd8d866a521629df0f2a Mon Sep 17 00:00:00 2001 From: LCW Date: Tue, 9 Aug 2022 11:34:53 +0800 Subject: [PATCH 06/74] fix: increase the timeout time --- ci/init-plugin-test-service.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index 384cdc6cc9cb..3b6bfd420787 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -83,10 +83,10 @@ create_functions() { kubectl set resources deployment -n openfunction --all=true --requests=cpu=40m,memory=64Mi kubectl set resources deployment -n kube-system --all=true --requests=cpu=50m,memory=64Mi - kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Succeeded --timeout=300s - kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Running --timeout=300s - kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Succeeded --timeout=300s - kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Running --timeout=300s + kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s + kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Running --timeout=500s + kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s + kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Running --timeout=500s } From f59a15fff48f050d89c3e1ee486789232bf81683 Mon Sep 17 00:00:00 2001 From: LCW Date: Tue, 9 Aug 2022 12:41:04 +0800 Subject: [PATCH 07/74] fix: correct htpasswd command --- ci/init-plugin-test-service.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index 3b6bfd420787..893c266cc27f 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -91,8 +91,7 @@ create_functions() { } set_ingress_controller() { - yum install -y httpd - htpasswd -cd auth test test + htpasswd -cb auth test test kubectl create secret generic basic-auth --from-file=auth kubectl patch ingress openfunction -p '{"metadata":{"annotations":{"nginx.ingress.kubernetes.io/auth-type":"basic","nginx.ingress.kubernetes.io/auth-secret":"basic-auth","nginx.ingress.kubernetes.io/auth-realm":"Authentication Required - test"}}}' From 69ee6519bd95b66c6b03334c8477900136b318dc Mon Sep 17 00:00:00 2001 From: LCW Date: Tue, 9 Aug 2022 14:10:44 +0800 Subject: [PATCH 08/74] ci: fix openfunction ci params --- ci/init-plugin-test-service.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index 893c266cc27f..910ece4d6fad 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -80,8 +80,8 @@ create_functions() { kubectl apply -f function-sample.yaml kubectl apply -f function-sample-test-body.yaml - kubectl set resources deployment -n openfunction --all=true --requests=cpu=40m,memory=64Mi - kubectl set resources deployment -n kube-system --all=true --requests=cpu=50m,memory=64Mi + kubectl set resources deployment -n openfunction --all=true --requests=cpu=40m,memory=100Mi + kubectl set resources deployment -n kube-system --all=true --requests=cpu=40m,memory=100Mi kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Running --timeout=500s From 283c5e877b8bc2ec33b3e057d07bfe54ba948fdc Mon Sep 17 00:00:00 2001 From: LCW Date: Tue, 9 Aug 2022 14:55:41 +0800 Subject: [PATCH 09/74] ci: fix openfunction ci params --- ci/init-plugin-test-service.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index 910ece4d6fad..7d30b6e9b508 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -84,9 +84,9 @@ create_functions() { kubectl set resources deployment -n kube-system --all=true --requests=cpu=40m,memory=100Mi kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s - kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Running --timeout=500s + kubectl wait fn function-sample --for=jsonpath='{.status.serving.state}'=Running --timeout=500s kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s - kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Running --timeout=500s + kubectl wait fn test-body --for=jsonpath='{.status.serving.state}'=Running --timeout=500s } From 467d6d007c649482d6183dac4cb31a515e60cbd4 Mon Sep 17 00:00:00 2001 From: CongwangLi <47933502+jackkkkklee@users.noreply.github.com> Date: Wed, 10 Aug 2022 10:47:46 +0800 Subject: [PATCH 10/74] docs: fix name Co-authored-by: Alex Zhang --- docs/en/latest/plugins/openfunction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index 774d9c6e4f80..f86ca081bf31 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -29,7 +29,7 @@ description: This document contains information about the CNCF OpenFunction Plug ## Description -The `openfunction` Plugin is used to integrate APISIX with [CNCF OpenWhisk](https://openfunction.dev/) serverless platform. +The `openfunction` Plugin is used to integrate APISIX with [CNCF OpenFunction](https://openfunction.dev/) serverless platform. This Plugin can be configured on a Route and requests will be send to the configured OpenWhish API endpoint as the upstream. From e88936c8b0f7aaa1582050d2e9ee7f8fe1e45084 Mon Sep 17 00:00:00 2001 From: CongwangLi <47933502+jackkkkklee@users.noreply.github.com> Date: Wed, 10 Aug 2022 10:50:50 +0800 Subject: [PATCH 11/74] docs: fix verification command Co-authored-by: Alex Zhang --- docs/en/latest/plugins/openfunction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index f86ca081bf31..0a187555dab1 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -69,7 +69,7 @@ helm install openfunction openfunction/openfunction -n openfunction You can then verify if OpenFunction is ready: ```shell -kubectl get pods -namespace openfunction +kubectl get pods --namespace openfunction ``` You can then create a function follow the [sample](https://github.com/OpenFunction/samples) From 98b9ba1f8185984dd43dafe13a62ebc1303b49b7 Mon Sep 17 00:00:00 2001 From: LCW Date: Wed, 10 Aug 2022 15:03:34 +0800 Subject: [PATCH 12/74] fix: fix Code Lint --- apisix/plugins/openfunction.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/apisix/plugins/openfunction.lua b/apisix/plugins/openfunction.lua index 3d5dfe99ac11..aff1dbd3e5d5 100644 --- a/apisix/plugins/openfunction.lua +++ b/apisix/plugins/openfunction.lua @@ -18,6 +18,7 @@ local core = require("apisix.core") local http = require("resty.http") local ngx_encode_base64 = ngx.encode_base64 +local ngx = ngx local schema = { type = "object", From 23521f1e8215062401e2c720525267fd61f23bfd Mon Sep 17 00:00:00 2001 From: LCW Date: Wed, 10 Aug 2022 15:05:00 +0800 Subject: [PATCH 13/74] fix: fix Lint --- docs/en/latest/plugins/openfunction.md | 4 ++-- docs/zh/latest/plugins/openfunction.md | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index 0a187555dab1..ccb8798e5b9e 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -49,12 +49,12 @@ This Plugin can be configured on a Route and requests will be send to the config The `timeout` attribute sets the time taken by the OpenFunction to execute, and the timeout for the HTTP client in APISIX. OpenFunction calls may take time to pull the runtime image and start the container. So, if the value is set too small, it may cause a large number of requests to fail. - ::: ## Enabling the Plugin -Before configuring the Plugin, you need to have OpenFunction running. The example below shows OpenFunction installed in Helm: +Before configuring the Plugin, you need to have OpenFunction running. For details, please refer to [Installation](https://openfunction.dev/docs/getting-started/installation/). +The example below shows OpenFunction installed in Helm: ```shell #add the OpenFunction chart repository diff --git a/docs/zh/latest/plugins/openfunction.md b/docs/zh/latest/plugins/openfunction.md index a26c4f7c0a20..c335a8ffb772 100644 --- a/docs/zh/latest/plugins/openfunction.md +++ b/docs/zh/latest/plugins/openfunction.md @@ -31,7 +31,7 @@ description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信 `openfunction` 插件用于将开源的分布式无服务器平台 [CNCF OpenFunction](https://openfunction.dev/) 作为动态上游集成至 APISIX。 -启用 `openfunction` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 OpenFunction 的 function发起一个新的请求,然后 `openfunction` 插件会将响应信息返回至客户端。 +启用 `openfunction` 插件后,该插件会终止对已配置 URI 的请求,并代表客户端向 OpenFunction 的 function 发起一个新的请求,然后 `openfunction` 插件会将响应信息返回至客户端。 ## 属性 @@ -39,7 +39,7 @@ description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信 | ----------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ | | function_uri | string | 是 | | | OpenFunction function uri,例如 `https://localhost:30858/default/function-sample`。 | | ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 | -| service_token | string | 是 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持ingress controller的basic auth认证方式。 | +| service_token | string | 是 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持 ingress controller 的 basic auth 认证方式。 | | timeout | integer | 否 | 60000ms | [1,60000]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | | keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 | | keepalive_timeout | integer | 否 | 60000ms | [1000,...]ms | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 | @@ -51,14 +51,14 @@ description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信 因为 OpenFunction function 调用可能会耗费很长时间来拉取容器镜像和启动容器,所以如果 `timeout` 字段值设置太小,可能会导致大量的失败请求。 - ::: ## 启用插件 ### 搭建 Apache OpenFunction 测试环境 -1. 在使用 `openfunction` 插件之前,你需要通过以下命令运行 OpenFunction 。请确保当前环境中已经安装 Kubernetes 软件。 +1. 在使用 `openfunction` 插件之前,你需要通过以下命令运行 OpenFunction 。详情参考[官方安装指南](https://openfunction.dev/docs/getting-started/installation/) 。 +请确保当前环境中已经安装 Kubernetes 软件。 ```shell #add the OpenFunction chart repository @@ -70,15 +70,14 @@ kubectl create namespace openfunction helm install openfunction openfunction/openfunction -n openfunction ``` -2. 你可以通过以下命令来验证openfunction是否已经安装成功: +2. 你可以通过以下命令来验证 openfunction 是否已经安装成功: + ```shell kubectl get pods -namespace openfunction ``` 3. 你可以通过官方示例创建函数 [sample](https://github.com/OpenFunction/samples) - - ### 创建路由 通过以下命令创建一个路由,并在配置文件中添加 `openfunction` 插件: From 822b5890232b8d1c29f62dbbbb8f2092dd2ba663 Mon Sep 17 00:00:00 2001 From: LCW Date: Thu, 11 Aug 2022 21:29:47 +0800 Subject: [PATCH 14/74] ci: avoid function building and run function in docker --- ci/init-plugin-test-service.sh | 69 +++------------------------------- 1 file changed, 6 insertions(+), 63 deletions(-) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index 7d30b6e9b508..c0d20539a9f8 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -43,68 +43,11 @@ docker exec -i rmqnamesrv /home/rocketmq/rocketmq-4.6.0/bin/mqadmin updateTopic docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv" # prepare openfunction env -prepare_kind_k8s() { - curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.11.1/kind-linux-amd64 - chmod +x ./kind - curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" - sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl - kind create cluster --name myk8s-01 -} +docker pull apisixtestaccount123/sample-go-func:v1 +docker pull apisixtestaccount123/sample-go-func:v2 +docker pull apisixtestaccount123/sample-go-func:v3 -install_openfuncntion() { - curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash - helm repo add openfunction https://openfunction.github.io/charts/ - helm repo update - kubectl create namespace openfunction - helm install openfunction --set global.Keda.enabled=false --set global.Dapr.enabled=false openfunction/openfunction -n openfunction - kubectl wait pods --all --for=condition=Ready --timeout=300s -n openfunction - kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission - kubectl delete deployment -n keda --all - kubectl delete deployment -n dapr-system --all - kubectl delete pod -n keda --all - kubectl delete pod -n dapr-system --all -} +nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-header -p 30583:8080 apisixtestaccount123/sample-go-func:v2 >/dev/null 2>&1 & +nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-body -p 30585:8080 apisixtestaccount123/sample-go-func:v1 >/dev/null 2>&1 & +nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name func-helloworld-go -p 30584:8080 apisixtestaccount123/sample-go-func:v3 >/dev/null 2>&1 & -set_container_registry_secret() { - REGISTRY_SERVER=https://index.docker.io/v1/ REGISTRY_USER=apisixtestaccount123 REGISTRY_PASSWORD=apisixtestaccount - kubectl create secret docker-registry push-secret \ - --docker-server=$REGISTRY_SERVER \ - --docker-username=$REGISTRY_USER \ - --docker-password=$REGISTRY_PASSWORD -} - -create_functions() { - wget https://raw.githubusercontent.com/jackkkkklee/samples/release-0.6/functions/knative/hello-world-go/function-sample.yaml - wget https://raw.githubusercontent.com/jackkkkklee/samples/main/functions/knative/hello-world-go/function-sample-test-body.yaml - - kubectl apply -f function-sample.yaml - kubectl apply -f function-sample-test-body.yaml - - kubectl set resources deployment -n openfunction --all=true --requests=cpu=40m,memory=100Mi - kubectl set resources deployment -n kube-system --all=true --requests=cpu=40m,memory=100Mi - - kubectl wait fn function-sample --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s - kubectl wait fn function-sample --for=jsonpath='{.status.serving.state}'=Running --timeout=500s - kubectl wait fn test-body --for=jsonpath='{.status.build.state}'=Succeeded --timeout=500s - kubectl wait fn test-body --for=jsonpath='{.status.serving.state}'=Running --timeout=500s - -} - -set_ingress_controller() { - htpasswd -cb auth test test - kubectl create secret generic basic-auth --from-file=auth - - kubectl patch ingress openfunction -p '{"metadata":{"annotations":{"nginx.ingress.kubernetes.io/auth-type":"basic","nginx.ingress.kubernetes.io/auth-secret":"basic-auth","nginx.ingress.kubernetes.io/auth-realm":"Authentication Required - test"}}}' - kubectl patch svc ingress-nginx-controller -n ingress-nginx -p $'spec:\n type: NodePort' - kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec":{"ports":[{"appProtocol":"http","name":"myhttp","nodePort": 30585,"port": 80,"protocol": "TCP", "targetPort": "http"}]}}' - } -port_forward() { - nohup kubectl port-forward --address 0.0.0.0 --namespace=ingress-nginx service/ingress-nginx-controller 30585:80 >/dev/null 2>&1 & -} - -prepare_kind_k8s -install_openfuncntion -set_container_registry_secret -create_functions -set_ingress_controller -port_forward From c31b6c819194c408d5be40acb23eb549823dbed2 Mon Sep 17 00:00:00 2001 From: LCW Date: Thu, 11 Aug 2022 21:31:06 +0800 Subject: [PATCH 15/74] test: update openfunction test case --- t/plugin/openfunction.t | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/t/plugin/openfunction.t b/t/plugin/openfunction.t index 3f9802279038..13ab71449800 100644 --- a/t/plugin/openfunction.t +++ b/t/plugin/openfunction.t @@ -41,7 +41,7 @@ __DATA__ location /t { content_by_lua_block { local plugin = require("apisix.plugins.openfunction") - local ok, err = plugin.check_schema({function_uri = "http://127.0.0.1:30585/default/function-sample", service_token = "test:test"}) + local ok, err = plugin.check_schema({function_uri = "http://127.0.0.1:30585/default/test-body"}) if not ok then ngx.say(err) end @@ -59,7 +59,7 @@ done location /t { content_by_lua_block { local plugin = require("apisix.plugins.openfunction") - local ok, err = plugin.check_schema({service_token = "test:test"}) + local ok, err = plugin.check_schema({timeout = 60000}) if not ok then ngx.say(err) end @@ -75,7 +75,7 @@ property "function_uri" is required location /t { content_by_lua_block { local plugin = require("apisix.plugins.openfunction") - local ok, err = plugin.check_schema({function_uri = 30858, service_token = "test:test"}) + local ok, err = plugin.check_schema({function_uri = 30858}) if not ok then ngx.say(err) end @@ -96,8 +96,7 @@ property "function_uri" validation failed: wrong type: expected string, got numb [[{ "plugins": { "openfunction": { - "function_uri": "http://127.0.0.1:30585/default/function-sample/world", - "service_token": "test:test" + "function_uri": "http://127.0.0.1:30584/function-sample" } }, "upstream": { @@ -119,12 +118,11 @@ passed - === TEST 5: hit route (with GET request) --- request GET /hello --- response_body -Hello, world! +Hello, function-sample! @@ -138,8 +136,7 @@ Hello, world! [[{ "plugins": { "openfunction": { - "function_uri": "http://127.0.0.1:30585/default/test-body", - "service_token": "test:test" + "function_uri": "http://127.0.0.1:30585/default/test-body" } }, "upstream": { @@ -159,6 +156,8 @@ Hello, world! --- response_body passed + + === TEST 7: hit route with POST method --- request POST /hello @@ -167,7 +166,8 @@ test Hello, test! -=== TEST 8: reset route with test-body function without service_token + +=== TEST 8: reset route with test-body function with service_token --- config location /t { content_by_lua_block { @@ -177,7 +177,10 @@ Hello, test! [[{ "plugins": { "openfunction": { - "function_uri": "http://127.0.0.1:30585/default/test-body" + "function_uri": "http://127.0.0.1:30583/", + "authorization": { + "service_token": "test:test" + } } }, "upstream": { @@ -198,14 +201,12 @@ Hello, test! passed -=== TEST 9: hit route with POST request when openfunction required basic auth + +=== TEST 9: hit route with POST request with service_token --- request POST /hello -test ---- error_code: 401 ---- response_body_like eval -qr/401 Authorization Required/ - +--- response_body chomp +[Basic dGVzdDp0ZXN0] @@ -219,8 +220,7 @@ qr/401 Authorization Required/ [[{ "plugins": { "openfunction": { - "function_uri": "http://127.0.0.1:30585/default/non-existent", - "service_token": "test:test" + "function_uri": "http://127.0.0.1:30584/default/non-existent" } }, "upstream": { @@ -250,4 +250,4 @@ test Content-Type: application/x-www-form-urlencoded --- error_code: 404 --- response_body_like eval -qr/404 Not Found/ +qr/not found/ From 4f0c086e5128cc248e886ac09c891034f4cdb229 Mon Sep 17 00:00:00 2001 From: LCW Date: Thu, 11 Aug 2022 21:31:29 +0800 Subject: [PATCH 16/74] docs: add openfunction index --- docs/zh/latest/config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/zh/latest/config.json b/docs/zh/latest/config.json index 14c45fa6f81a..cf9a4a277ca7 100644 --- a/docs/zh/latest/config.json +++ b/docs/zh/latest/config.json @@ -164,7 +164,8 @@ "plugins/serverless", "plugins/azure-functions", "plugins/openwhisk", - "plugins/aws-lambda" + "plugins/aws-lambda", + "plugins/openfunction" ] }, { From a779ca1142cb7d85e3ee20e9d042bceef7febdc5 Mon Sep 17 00:00:00 2001 From: LCW Date: Thu, 11 Aug 2022 21:33:25 +0800 Subject: [PATCH 17/74] feat: reuse serverless.generic-upstream --- apisix/plugins/openfunction.lua | 91 ++++----------------------------- 1 file changed, 11 insertions(+), 80 deletions(-) diff --git a/apisix/plugins/openfunction.lua b/apisix/plugins/openfunction.lua index aff1dbd3e5d5..d2080642c89e 100644 --- a/apisix/plugins/openfunction.lua +++ b/apisix/plugins/openfunction.lua @@ -14,92 +14,23 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- - -local core = require("apisix.core") -local http = require("resty.http") local ngx_encode_base64 = ngx.encode_base64 -local ngx = ngx - -local schema = { - type = "object", - properties = { - function_uri = {type = "string"}, - ssl_verify = { - type = "boolean", - default = true, - }, - service_token = {type = "string"}, - timeout = { - type = "integer", - minimum = 1, - maximum = 60000, - default = 60000, - description = "timeout in milliseconds", - }, - keepalive = {type = "boolean", default = true}, - keepalive_timeout = {type = "integer", minimum = 1000, default = 60000}, - keepalive_pool = {type = "integer", minimum = 1, default = 5} - }, - required = {"function_uri"} -} +local plugin_name, plugin_version, priority = "openfunction", 0.1, -1902 - -local _M = { - version = 0.1, - priority = -1902, - name = "openfunction", - schema = schema, +local openfunction_authz_schema = { + service_token = {type = "string"} } - -function _M.check_schema(conf) - local ok, err = core.schema.check(schema, conf) - if not ok then - return false, err - end - - return true -end - - -function _M.access(conf, ctx) - local params = { - method = ngx.req.get_method(), - body = core.request.get_body(), - keepalive = conf.keepalive, - ssl_verify = conf.ssl_verify, - headers = core.request.headers(ctx) or {} - } - +local function request_processor(conf, ctx, params) + local headers = params.headers or {} -- setting authorization headers if not already set - if not params.headers["Authorization"] and conf.service_token then - params.headers["Authorization"] = "Basic " .. ngx_encode_base64(conf.service_token) + if not headers["Authorization"] and conf.authorization + and conf.authorization.service_token then + headers["Authorization"] = "Basic " .. ngx_encode_base64(conf.authorization.service_token) end - if conf.keepalive then - params.keepalive_timeout = conf.keepalive_timeout - params.keepalive_pool = conf.keepalive_pool - end - - local endpoint = conf.function_uri - local httpc = http.new() - httpc:set_timeout(conf.timeout) - - local res, err = httpc:request_uri(endpoint, params) - - if not res then - core.log.error("failed to process ",_M.name, ", err: ", err) - return 503 - end - - -- setting response headers - if res.headers ~= nil then - core.response.set_header(res.headers) - end - - return res.status, res.body - + params.headers = headers end - -return _M +return require("apisix.plugins.serverless.generic-upstream")(plugin_name, + plugin_version, priority, request_processor, openfunction_authz_schema) From 5096a41c0b9b3d214cfe0f532bbfb473eab7f883 Mon Sep 17 00:00:00 2001 From: CongwangLi <47933502+jackkkkklee@users.noreply.github.com> Date: Fri, 12 Aug 2022 14:56:33 +0800 Subject: [PATCH 18/74] docs: fix lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 罗泽轩 --- docs/en/latest/plugins/openfunction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index ccb8798e5b9e..8ec45948b647 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -47,7 +47,7 @@ This Plugin can be configured on a Route and requests will be send to the config :::note -The `timeout` attribute sets the time taken by the OpenFunction to execute, and the timeout for the HTTP client in APISIX. OpenFunction calls may take time to pull the runtime image and start the container. So, if the value is set too small, it may cause a large number of requests to fail. +The `timeout` attribute sets the time taken by the OpenFunction to execute, and the timeout for the HTTP client in APISIX. OpenFunction calls may take time to pull the runtime image and start the container. So, if the value is set too small, it may cause a large number of requests to fail. ::: From 9b5dc62f29c6db7cfdf73161de2884b73661042e Mon Sep 17 00:00:00 2001 From: CongwangLi <47933502+jackkkkklee@users.noreply.github.com> Date: Fri, 12 Aug 2022 14:57:02 +0800 Subject: [PATCH 19/74] docs: fix lint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 罗泽轩 --- docs/en/latest/plugins/openfunction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index 8ec45948b647..3e7e851485d8 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -53,7 +53,7 @@ The `timeout` attribute sets the time taken by the OpenFunction to execute, and ## Enabling the Plugin -Before configuring the Plugin, you need to have OpenFunction running. For details, please refer to [Installation](https://openfunction.dev/docs/getting-started/installation/). +Before configuring the plugin, you need to have OpenFunction running. For details, please refer to [Installation](https://openfunction.dev/docs/getting-started/installation/). The example below shows OpenFunction installed in Helm: ```shell From 2d02b0265893504321c76af67616acbcb85d4422 Mon Sep 17 00:00:00 2001 From: LCW Date: Fri, 12 Aug 2022 15:20:13 +0800 Subject: [PATCH 20/74] docs: update timeout --- docs/en/latest/plugins/openfunction.md | 2 +- docs/zh/latest/plugins/openfunction.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index ccb8798e5b9e..7f4de9392f42 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -40,7 +40,7 @@ This Plugin can be configured on a Route and requests will be send to the config | function_uri | string | True | | | function uri. For example, `https://localhost:30858/default/function-sample`. | | ssl_verify | boolean | False | true | | When set to `true` verifies the SSL certificate. | | service_token | string | False | | | The token format is 'xx:xx' which support basic auth for ingress controller, . | -| timeout | integer | False | 60000ms | [1, 60000]ms | OpenFunction action and HTTP call timeout in ms. | +| timeout | integer | False | 3000ms | [100, ...]ms | OpenFunction action and HTTP call timeout in ms. | | keepalive | boolean | False | true | | When set to `true` keeps the connection alive for reuse. | | keepalive_timeout | integer | False | 60000ms | [1000,...]ms | Time is ms for connection to remain idle without closing. | | keepalive_pool | integer | False | 5 | [1,...] | Maximum number of requests that can be sent on this connection before closing it. | diff --git a/docs/zh/latest/plugins/openfunction.md b/docs/zh/latest/plugins/openfunction.md index c335a8ffb772..3a15fb2cdcaf 100644 --- a/docs/zh/latest/plugins/openfunction.md +++ b/docs/zh/latest/plugins/openfunction.md @@ -40,7 +40,7 @@ description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信 | function_uri | string | 是 | | | OpenFunction function uri,例如 `https://localhost:30858/default/function-sample`。 | | ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 | | service_token | string | 是 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持 ingress controller 的 basic auth 认证方式。 | -| timeout | integer | 否 | 60000ms | [1,60000]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | +| timeout | integer | 否 | 3000ms | [100,...]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | | keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 | | keepalive_timeout | integer | 否 | 60000ms | [1000,...]ms | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 | | keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 | From f9efd9dc07a1e1757dc7019e2c2439fd409ff167 Mon Sep 17 00:00:00 2001 From: LCW Date: Fri, 12 Aug 2022 15:21:08 +0800 Subject: [PATCH 21/74] test: add check user-specific auth header --- t/plugin/openfunction.t | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/t/plugin/openfunction.t b/t/plugin/openfunction.t index 13ab71449800..3eb300bdb759 100644 --- a/t/plugin/openfunction.t +++ b/t/plugin/openfunction.t @@ -210,7 +210,17 @@ POST /hello -=== TEST 10: reset route to non-existent function_uri +=== TEST 10: check higher priority of user-specific Authorization header +--- request +POST /hello +--- more_headers +Authorization: user-token-xxx +--- response_body chomp +[user-token-xxx] + + + +=== TEST 11: reset route to non-existent function_uri --- config location /t { content_by_lua_block { @@ -242,7 +252,7 @@ passed -=== TEST 11: hit route (with non-existent function_uri) +=== TEST 12: hit route (with non-existent function_uri) --- request POST /hello test From 59d5236759500747d7aa4348c6d2c35514a78092 Mon Sep 17 00:00:00 2001 From: LCW Date: Sun, 14 Aug 2022 11:29:29 +0800 Subject: [PATCH 22/74] docs: update attributes description --- docs/en/latest/plugins/openfunction.md | 27 ++++++++++++++------------ docs/zh/latest/plugins/openfunction.md | 25 +++++++++++++----------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/docs/en/latest/plugins/openfunction.md b/docs/en/latest/plugins/openfunction.md index 682e4e20dfb5..fa7120915bd3 100644 --- a/docs/en/latest/plugins/openfunction.md +++ b/docs/en/latest/plugins/openfunction.md @@ -35,15 +35,16 @@ This Plugin can be configured on a Route and requests will be send to the config ## Attributes -| Name | Type | Required | Default | Valid values | Description | -| ----------------- | ------- | -------- | ------- | ------------ | ---------------------------------------------------------------------------------------------------------- | -| function_uri | string | True | | | function uri. For example, `https://localhost:30858/default/function-sample`. | -| ssl_verify | boolean | False | true | | When set to `true` verifies the SSL certificate. | -| service_token | string | False | | | The token format is 'xx:xx' which support basic auth for ingress controller, . | -| timeout | integer | False | 3000ms | [100, ...]ms | OpenFunction action and HTTP call timeout in ms. | -| keepalive | boolean | False | true | | When set to `true` keeps the connection alive for reuse. | -| keepalive_timeout | integer | False | 60000ms | [1000,...]ms | Time is ms for connection to remain idle without closing. | -| keepalive_pool | integer | False | 5 | [1,...] | Maximum number of requests that can be sent on this connection before closing it. | +| Name | Type | Required | Default | Valid values | Description | +| --------------------------- | ------- | -------- | ------- | ------------ | ---------------------------------------------------------------------------------------------------------- | +| function_uri | string | True | | | function uri. For example, `https://localhost:30858/default/function-sample`. | +| ssl_verify | boolean | False | true | | When set to `true` verifies the SSL certificate. | +| authorization | object | False | | | Authorization credentials to access functions of OpenFunction. | +| authorization.service_token | string | False | | | The token format is 'xx:xx' which support basic auth for ingress controller, . | +| timeout | integer | False | 3000ms | [100, ...]ms | OpenFunction action and HTTP call timeout in ms. | +| keepalive | boolean | False | true | | When set to `true` keeps the connection alive for reuse. | +| keepalive_timeout | integer | False | 60000ms | [1000,...]ms | Time is ms for connection to remain idle without closing. | +| keepalive_pool | integer | False | 5 | [1,...] | Maximum number of requests that can be sent on this connection before closing it. | :::note @@ -69,7 +70,7 @@ helm install openfunction openfunction/openfunction -n openfunction You can then verify if OpenFunction is ready: ```shell -kubectl get pods --namespace openfunction +kubectl get pods -namespace openfunction ``` You can then create a function follow the [sample](https://github.com/OpenFunction/samples) @@ -83,7 +84,9 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 "plugins": { "openfunction": { "function_uri": "http://localhost:3233/default/function-sample/test", - "service_token": "foo:foo" + "authorization": { + "service_token": "test:test" + } } } }' @@ -94,7 +97,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 Once you have configured the Plugin, you can send a request to the Route and it will invoke the configured function: ```shell -curl -i http://127.0.0.1:9080/hello +curl -i http://127.0.0.1:9080/hello -X POST -d'test' ``` This will give back the response from the function: diff --git a/docs/zh/latest/plugins/openfunction.md b/docs/zh/latest/plugins/openfunction.md index 3a15fb2cdcaf..94c50781a20c 100644 --- a/docs/zh/latest/plugins/openfunction.md +++ b/docs/zh/latest/plugins/openfunction.md @@ -35,15 +35,16 @@ description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信 ## 属性 -| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | -| ----------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ | -| function_uri | string | 是 | | | OpenFunction function uri,例如 `https://localhost:30858/default/function-sample`。 | -| ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 | -| service_token | string | 是 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持 ingress controller 的 basic auth 认证方式。 | -| timeout | integer | 否 | 3000ms | [100,...]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | -| keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 | -| keepalive_timeout | integer | 否 | 60000ms | [1000,...]ms | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 | -| keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 | +| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | +| --------------------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ | +| function_uri | string | 是 | | | OpenFunction function uri,例如 `https://localhost:30858/default/function-sample`。 | +| ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 | +| authorization | object | 否 | | | 访问OpenFunction的函数的授权凭证. | +| authorization.service_token | string | 否 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持 ingress controller 的 basic auth 认证方式。 | +| timeout | integer | 否 | 3000ms | [100,...]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | +| keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 | +| keepalive_timeout | integer | 否 | 60000ms | [1000,...]ms | 当连接空闲时,保持该连接处于活动状态的时间(以毫秒为单位)。 | +| keepalive_pool | integer | 否 | 5 | [1,...] | 连接断开之前,可接收的最大请求数。 | :::note @@ -89,7 +90,9 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 "plugins": { "openfunction": { "function_uri": "http://localhost:3233/default/function-sample/test", - "service_token": "foo:foo" + "authorization": { + "service_token": "test:test" + } } } }' @@ -100,7 +103,7 @@ curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f13 使用 `curl` 命令测试: ```shell -curl -i http://127.0.0.1:9080/hello +curl -i http://127.0.0.1:9080/hello -X POST -d'test' ``` 正常返回结果: From 25c79104448ca6607c9923287ea17bf1296bf36d Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 15 Aug 2022 09:59:17 +0800 Subject: [PATCH 23/74] docs: fix lint --- docs/zh/latest/plugins/openfunction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/latest/plugins/openfunction.md b/docs/zh/latest/plugins/openfunction.md index 94c50781a20c..82b38d9cfda7 100644 --- a/docs/zh/latest/plugins/openfunction.md +++ b/docs/zh/latest/plugins/openfunction.md @@ -39,7 +39,7 @@ description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信 | --------------------------- | ------- | ------ | ------- | ------------ | ------------------------------------------------------------ | | function_uri | string | 是 | | | OpenFunction function uri,例如 `https://localhost:30858/default/function-sample`。 | | ssl_verify | boolean | 否 | true | | 当设置为 `true` 时执行 SSL 验证。 | -| authorization | object | 否 | | | 访问OpenFunction的函数的授权凭证. | +| authorization | object | 否 | | | 访问 OpenFunction 的函数的授权凭证。| | authorization.service_token | string | 否 | | | OpenFunction service token,其格式为 `xxx:xxx` ,支持 ingress controller 的 basic auth 认证方式。 | | timeout | integer | 否 | 3000ms | [100,...]ms | OpenFunction action 和 HTTP 调用超时时间(以毫秒为单位)。 | | keepalive | boolean | 否 | true | | 当设置为 `true` 时,保持连接的活动状态以便重复使用。 | From 1af451dc50560697f33a13ea82f0a7f942089f64 Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 15 Aug 2022 10:23:53 +0800 Subject: [PATCH 24/74] fix: set headers in lower-case --- apisix/plugins/openfunction.lua | 4 ++-- t/plugin/openfunction.t | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apisix/plugins/openfunction.lua b/apisix/plugins/openfunction.lua index d2080642c89e..f75c3696eb23 100644 --- a/apisix/plugins/openfunction.lua +++ b/apisix/plugins/openfunction.lua @@ -24,9 +24,9 @@ local openfunction_authz_schema = { local function request_processor(conf, ctx, params) local headers = params.headers or {} -- setting authorization headers if not already set - if not headers["Authorization"] and conf.authorization + if not headers["authorization"] and conf.authorization and conf.authorization.service_token then - headers["Authorization"] = "Basic " .. ngx_encode_base64(conf.authorization.service_token) + headers["authorization"] = "Basic " .. ngx_encode_base64(conf.authorization.service_token) end params.headers = headers diff --git a/t/plugin/openfunction.t b/t/plugin/openfunction.t index 3eb300bdb759..873ab6923833 100644 --- a/t/plugin/openfunction.t +++ b/t/plugin/openfunction.t @@ -214,7 +214,7 @@ POST /hello --- request POST /hello --- more_headers -Authorization: user-token-xxx +authorization: user-token-xxx --- response_body chomp [user-token-xxx] From 79c0b3cbdc15ab5df780bbfa97bcfd3afaed2a10 Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 15 Aug 2022 13:51:37 +0800 Subject: [PATCH 25/74] ci: add building image locally --- ci/init-plugin-test-service.sh | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/ci/init-plugin-test-service.sh b/ci/init-plugin-test-service.sh index c0d20539a9f8..fe10119ce99d 100755 --- a/ci/init-plugin-test-service.sh +++ b/ci/init-plugin-test-service.sh @@ -43,11 +43,18 @@ docker exec -i rmqnamesrv /home/rocketmq/rocketmq-4.6.0/bin/mqadmin updateTopic docker exec -i vault sh -c "VAULT_TOKEN='root' VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv" # prepare openfunction env -docker pull apisixtestaccount123/sample-go-func:v1 -docker pull apisixtestaccount123/sample-go-func:v2 -docker pull apisixtestaccount123/sample-go-func:v3 +wget https://github.com/buildpacks/pack/releases/download/v0.27.0/pack-v0.27.0-linux.tgz +tar -zxvf pack-v0.27.0-linux.tgz -nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-header -p 30583:8080 apisixtestaccount123/sample-go-func:v2 >/dev/null 2>&1 & -nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-body -p 30585:8080 apisixtestaccount123/sample-go-func:v1 >/dev/null 2>&1 & -nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name func-helloworld-go -p 30584:8080 apisixtestaccount123/sample-go-func:v3 >/dev/null 2>&1 & +# please fork and repalce this(./samples/functions/knative/hello-world-go) if you want to update function +git clone https://github.com/OpenFunction/samples.git +git clone https://github.com/jackkkkklee/my-samples.git +./pack build test-uri-image --path ./samples/functions/knative/hello-world-go --builder openfunction/builder-go:v2.4.0-1.17 --env FUNC_NAME="HelloWorld" --env FUNC_CLEAR_SOURCE=true --env FUNC_GOPROXY="https://goproxy.cn" +./pack build test-body-image --path ./my-samples/functions/knative/hello-world-go --builder openfunction/builder-go:v2.4.0-1.17 --env FUNC_NAME="HelloWorld" --env FUNC_CLEAR_SOURCE=true --env FUNC_GOPROXY="https://goproxy.cn" +git -C my-samples switch release-0.6 +./pack build test-header-image --path ./my-samples/functions/knative/hello-world-go --builder openfunction/builder-go:v2.4.0-1.17 --env FUNC_NAME="HelloWorld" --env FUNC_CLEAR_SOURCE=true --env FUNC_GOPROXY="https://goproxy.cn" + +nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-uri -p 30584:8080 test-uri-image >/dev/null 2>&1 & +nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-header -p 30583:8080 test-header-image >/dev/null 2>&1 & +nohup docker run --rm --env="FUNC_CONTEXT={\"name\":\"HelloWorld\",\"version\":\"v1.0.0\",\"port\":\"8080\",\"runtime\":\"Knative\"}" --env="CONTEXT_MODE=self-host" --name test-body -p 30585:8080 test-body-image >/dev/null 2>&1 & From 90d555590d6300ec33261dc71fb6b51fcafc0891 Mon Sep 17 00:00:00 2001 From: LCW Date: Mon, 15 Aug 2022 15:17:28 +0800 Subject: [PATCH 26/74] docs: fix plugin description --- docs/zh/latest/plugins/openfunction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/latest/plugins/openfunction.md b/docs/zh/latest/plugins/openfunction.md index 82b38d9cfda7..24f30d4e3b94 100644 --- a/docs/zh/latest/plugins/openfunction.md +++ b/docs/zh/latest/plugins/openfunction.md @@ -5,7 +5,7 @@ keywords: - Plugin - OpenFunction - openfunction -description: 本文介绍了关于 Apache CNCF OpenFunction 插件的基本信息及使用方法。 +description: 本文介绍了关于 CNCF OpenFunction 插件的基本信息及使用方法。 ---