You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/05/30 02:38:12 UTC

[apisix-java-plugin-runner] branch main updated: docs: add README.md (#17)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/apisix-java-plugin-runner.git


The following commit(s) were added to refs/heads/main by this push:
     new 732cd2d  docs: add README.md (#17)
732cd2d is described below

commit 732cd2de2a3b10dc92c417933cc93eda0bd0dad2
Author: tzssangglass <tz...@gmail.com>
AuthorDate: Sun May 30 10:38:05 2021 +0800

    docs: add README.md (#17)
---
 README.md                                          |  50 +++++++++++++
 docs/development.md                                |   0
 docs/how-it-works.md                               |   0
 docs/images/apisix-java-plugin-runner-overview.png | Bin 0 -> 524459 bytes
 docs/the-internal-of-apisix-java-plugin-runner.md  |   0
 .../plugin/runner/server/ApplicationRunner.java    |  12 +++-
 .../plugin/runner/service/CacheConfiguration.java  |   2 +-
 .../runner/codec/impl/FlatBuffersEncoderTest.java  |   9 ++-
 .../runner/handler/A6HttpCallHandlerTest.java      |   3 +-
 runner-dist/src/main/bin/startup.sh                |  15 ++--
 .../apache/apisix/plugin/runner/HttpResponse.java  |  14 ++--
 runner-starter/src/main/resources/application.yaml |  11 ++-
 .../plugin/runner/PluginRunnerApplicationTest.java |   7 ++
 sample/pom.xml                                     |   8 +++
 .../runner/filter/RewriteRequestDemoFilter.java    |  80 +++++++++++++++++++++
 .../runner/filter/StopRequestDemoFilter.java       |  65 +++++++++++++++++
 16 files changed, 247 insertions(+), 29 deletions(-)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8d12aa1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,50 @@
+apisix-java-plugin-runner
+=================
+
+Runs [Apache APISIX](http://apisix.apache.org/) plugins written in Java.
+Implemented as a sidecar that accompanies APISIX.
+
+![apisix-java-plugin-runner-overview](./docs/images/apisix-java-plugin-runner-overview.png)
+
+Status
+------
+
+This project is currently considered experimental.
+
+Why apisix-java-plugin-runner
+---------------------
+
+APISIX offers many full-featured plugins covering areas such as authentication,
+security, traffic control, serverless, analytics & monitoring, transformations, logging.
+
+It also provides highly extensible API, allowing common phases to be mounted,
+and users can use these api to develop their own plugins.
+
+APISIX supports writing plugins in multiple languages in version [2.6.0](https://github.com/apache/apisix/blob/master/CHANGELOG.md#260),
+this project is APISIX Java side implementation that supports writing plugins in java.
+
+
+How it Works
+-------------
+
+See [How it Works](./docs/how-it-works.md) to learn how apisix-java-plugin-runner collaborate
+with APISIX to run plugins written in java.
+
+The Internal of apisix-java-plugin-runner
+---------------------------------
+
+If you're interested in the internal of apisix-java-plugin-runner, we recommend you
+to read the [the-internal-of-apisix-java-plugin-runner](./docs/the-internal-of-apisix-java-plugin-runner.md),
+it explains the details of communication and protocol conversion with APISIX.
+
+Get Involved in Development
+---------------------------
+
+Welcome to make contributions, but before you start, please check out
+[development.md](./docs/development.md) to learn how to run and debug apisix-java-plugin-runner
+in your own environment.
+
+License
+-------
+
+[Apache 2.0 LICENSE](./LICENSE)
\ No newline at end of file
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/how-it-works.md b/docs/how-it-works.md
new file mode 100644
index 0000000..e69de29
diff --git a/docs/images/apisix-java-plugin-runner-overview.png b/docs/images/apisix-java-plugin-runner-overview.png
new file mode 100644
index 0000000..3f6f391
Binary files /dev/null and b/docs/images/apisix-java-plugin-runner-overview.png differ
diff --git a/docs/the-internal-of-apisix-java-plugin-runner.md b/docs/the-internal-of-apisix-java-plugin-runner.md
new file mode 100644
index 0000000..e69de29
diff --git a/runner-core/src/main/java/org/apache/apisix/plugin/runner/server/ApplicationRunner.java b/runner-core/src/main/java/org/apache/apisix/plugin/runner/server/ApplicationRunner.java
index 79df645..ca7e68c 100644
--- a/runner-core/src/main/java/org/apache/apisix/plugin/runner/server/ApplicationRunner.java
+++ b/runner-core/src/main/java/org/apache/apisix/plugin/runner/server/ApplicationRunner.java
@@ -21,6 +21,8 @@ import io.netty.channel.unix.DomainSocketAddress;
 import io.netty.handler.logging.LoggingHandler;
 import lombok.RequiredArgsConstructor;
 import org.apache.apisix.plugin.runner.handler.IOHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.stereotype.Component;
@@ -34,9 +36,11 @@ import java.util.Objects;
 @RequiredArgsConstructor
 public class ApplicationRunner implements CommandLineRunner {
 
+    private final Logger logger = LoggerFactory.getLogger(ApplicationRunner.class);
+
     private final TcpServer tcpServer;
 
-    @Value("${socket.file:/tmp/runner.sock}")
+    @Value("${socket.file}")
     private String socketFile;
 
     private final IOHandler handler;
@@ -50,6 +54,11 @@ public class ApplicationRunner implements CommandLineRunner {
         if (Objects.isNull(tcpServer)) {
             tcpServer = TcpServer.create();
         }
+
+        if (socketFile.startsWith("unix:")) {
+            socketFile = socketFile.substring("unix:".length());
+        }
+
         tcpServer = tcpServer.bindAddress(() -> new DomainSocketAddress(socketFile));
         tcpServer = tcpServer.doOnChannelInit((observer, channel, addr) -> {
 //            if (Objects.nonNull(channelHandlers)) {
@@ -62,6 +71,7 @@ public class ApplicationRunner implements CommandLineRunner {
             tcpServer = tcpServer.handle(handler::handle);
         }
         this.server = tcpServer.bindNow();
+        logger.warn("java runner is listening on the socket file: {}", socketFile);
 
         // delete socket file when tcp server shutdown
         Runtime.getRuntime()
diff --git a/runner-core/src/main/java/org/apache/apisix/plugin/runner/service/CacheConfiguration.java b/runner-core/src/main/java/org/apache/apisix/plugin/runner/service/CacheConfiguration.java
index 029c62d..fbf4873 100644
--- a/runner-core/src/main/java/org/apache/apisix/plugin/runner/service/CacheConfiguration.java
+++ b/runner-core/src/main/java/org/apache/apisix/plugin/runner/service/CacheConfiguration.java
@@ -32,6 +32,6 @@ public class CacheConfiguration {
     @Bean
     public Cache<Long, A6Conf> configurationCache(@Value("${cache.config.expired:3610}") long expired,
                                                   @Value("${cache.config.capacity:1000}") int capacity) {
-        return CacheBuilder.newBuilder().expireAfterWrite(expired, TimeUnit.SECONDS).maximumSize(capacity).build();
+        return CacheBuilder.newBuilder().expireAfterWrite(expired + 10, TimeUnit.SECONDS).maximumSize(capacity).build();
     }
 }
diff --git a/runner-core/src/test/java/org/apache/apisix/plugin/runner/codec/impl/FlatBuffersEncoderTest.java b/runner-core/src/test/java/org/apache/apisix/plugin/runner/codec/impl/FlatBuffersEncoderTest.java
index 76e5175..8a9e38b 100644
--- a/runner-core/src/test/java/org/apache/apisix/plugin/runner/codec/impl/FlatBuffersEncoderTest.java
+++ b/runner-core/src/test/java/org/apache/apisix/plugin/runner/codec/impl/FlatBuffersEncoderTest.java
@@ -21,7 +21,6 @@ import io.github.api7.A6.Err.Code;
 import io.github.api7.A6.HTTPReqCall.Action;
 import io.github.api7.A6.HTTPReqCall.Rewrite;
 import io.github.api7.A6.HTTPReqCall.Stop;
-import io.netty.handler.codec.http.HttpResponseStatus;
 import org.apache.apisix.plugin.runner.A6ConfigResponse;
 import org.apache.apisix.plugin.runner.A6ErrResponse;
 import org.apache.apisix.plugin.runner.HttpResponse;
@@ -132,8 +131,8 @@ class FlatBuffersEncoderTest {
     void testStopResponseEncode() {
         HttpResponse httpResponse = new HttpResponse(0L);
         // set status, body, resp header means stop request
-        httpResponse.setStatus(HttpResponseStatus.UNAUTHORIZED);
-        httpResponse.setRespHeaders("code", "401");
+        httpResponse.setStatusCode(401);
+        httpResponse.setHeader("code", "401");
         httpResponse.setBody("Unauthorized");
         ByteBuffer result = flatBuffersEncoder.encode(httpResponse);
         result.position(4);
@@ -161,8 +160,8 @@ class FlatBuffersEncoderTest {
         httpResponse.setReqHeader("Server", "APISIX");
 
         // set status, body, resp header means stop request
-        httpResponse.setStatus(HttpResponseStatus.UNAUTHORIZED);
-        httpResponse.setRespHeaders("code", "401");
+        httpResponse.setStatusCode(401);
+        httpResponse.setHeader("code", "401");
         httpResponse.setBody("Unauthorized");
         ByteBuffer result = flatBuffersEncoder.encode(httpResponse);
         result.position(4);
diff --git a/runner-core/src/test/java/org/apache/apisix/plugin/runner/handler/A6HttpCallHandlerTest.java b/runner-core/src/test/java/org/apache/apisix/plugin/runner/handler/A6HttpCallHandlerTest.java
index e9604ec..f55b8d1 100644
--- a/runner-core/src/test/java/org/apache/apisix/plugin/runner/handler/A6HttpCallHandlerTest.java
+++ b/runner-core/src/test/java/org/apache/apisix/plugin/runner/handler/A6HttpCallHandlerTest.java
@@ -23,7 +23,6 @@ import com.google.flatbuffers.FlatBufferBuilder;
 import io.github.api7.A6.Err.Code;
 import io.github.api7.A6.HTTPReqCall.Action;
 import io.github.api7.A6.TextEntry;
-import io.netty.handler.codec.http.HttpResponseStatus;
 import org.apache.apisix.plugin.runner.A6Conf;
 import org.apache.apisix.plugin.runner.A6ConfigRequest;
 import org.apache.apisix.plugin.runner.A6ConfigResponse;
@@ -114,7 +113,7 @@ class A6HttpCallHandlerTest {
                 logger.info("do filter: CatFilter, order: {}", getOrder());
                 logger.info("do filter: CatFilter, config: {}", request.getConfig(this));
 
-                response.setStatus(HttpResponseStatus.UNAUTHORIZED);
+                response.setStatusCode(401);
                 return chain.filter(request, response);
             }
 
diff --git a/runner-dist/src/main/bin/startup.sh b/runner-dist/src/main/bin/startup.sh
index 123ae28..825ae24 100644
--- a/runner-dist/src/main/bin/startup.sh
+++ b/runner-dist/src/main/bin/startup.sh
@@ -17,16 +17,17 @@
 # limitations under the License.
 
 RUNNER_HOME=$(dirname "$0")/..
-
-RUNNER_LOGS_DIR=${RUNNER_LOGS_DIR:-${RUNNER_HOME}/logs}
+RUNNER_DIR=${RUNNER_HOME%/bin*}
 RUNNER_HEAP=${JAVA_HEAP:-4g}
 
 JAVA_OPS="${JAVA_OPS} -Xmx${RUNNER_HEAP} -Xms${RUNNER_HEAP}"
 
-[[ -d ${RUNNER_LOGS_DIR} ]] || mkdir -p ${RUNNER_LOGS_DIR}
+APISIX_LISTEN_ADDRESS=${APISIX_LISTEN_ADDRESS}
+APISIX_LISTEN_ADDRESS=${APISIX_LISTEN_ADDRESS#*:}
+APISIX_HOME=${APISIX_LISTEN_ADDRESS%/conf*}
 
-nohup java -jar ${JAVA_OPS} ${RUNNER_HOME}/apisxi-runner-start-*.jar \
- 1>${RUNNER_LOGS_DIR}/runner.out \
- 2>${RUNNER_LOGS_DIR}/runner.err &
+nohup java -jar ${JAVA_OPS} ${RUNNER_DIR}/apisix-java-plugin-*.jar \
+ 1>${APISIX_HOME}/logs/runner-out.log \
+ 2>${APISIX_HOME}/logs/runner-err.log &
 
-echo $! > ./logs/runner.pid
+echo $! > ${APISIX_HOME}/logs/runner.pid
diff --git a/runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/HttpResponse.java b/runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/HttpResponse.java
index 651e8e0..2c861be 100644
--- a/runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/HttpResponse.java
+++ b/runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/HttpResponse.java
@@ -22,7 +22,6 @@ import io.github.api7.A6.HTTPReqCall.Resp;
 import io.github.api7.A6.HTTPReqCall.Rewrite;
 import io.github.api7.A6.HTTPReqCall.Stop;
 import io.github.api7.A6.TextEntry;
-import io.netty.handler.codec.http.HttpResponseStatus;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
@@ -54,7 +53,7 @@ public class HttpResponse implements A6Response {
 
     private String body;
 
-    private HttpResponseStatus status;
+    private Integer statusCode;
 
     private A6ErrResponse errResponse;
 
@@ -87,7 +86,7 @@ public class HttpResponse implements A6Response {
         this.path = path;
     }
 
-    public void setRespHeaders(String headerKey, String headerValue) {
+    public void setHeader(String headerKey, String headerValue) {
         actionType = ActionType.Stop;
         if (Objects.isNull(respHeaders)) {
             respHeaders = new HashMap<>();
@@ -100,15 +99,16 @@ public class HttpResponse implements A6Response {
         this.body = body;
     }
 
-    public void setStatus(HttpResponseStatus status) {
+    public void setStatusCode(int statusCode) {
         actionType = ActionType.Stop;
-        this.status = status;
+        this.statusCode = statusCode;
     }
 
     public void setErrResponse(A6ErrResponse errResponse) {
         this.errResponse = errResponse;
     }
 
+    @Override
     public A6ErrResponse getErrResponse() {
         return this.errResponse;
     }
@@ -162,8 +162,8 @@ public class HttpResponse implements A6Response {
         }
 
         Stop.startStop(builder);
-        if (!Objects.isNull(status)) {
-            Stop.addStatus(builder, status.code());
+        if (!Objects.isNull(statusCode)) {
+            Stop.addStatus(builder, statusCode);
         }
         if (-1 != headerIndex) {
             Stop.addHeaders(builder, headerIndex);
diff --git a/runner-starter/src/main/resources/application.yaml b/runner-starter/src/main/resources/application.yaml
index d330244..5f4d487 100644
--- a/runner-starter/src/main/resources/application.yaml
+++ b/runner-starter/src/main/resources/application.yaml
@@ -13,10 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-logging:
-  level:
-    root: debug
-
 cache.config:
-  expired: 3610
-  capacity: 1000
\ No newline at end of file
+  expired: ${APISIX_CONF_EXPIRE_TIME}
+  capacity: 1000
+
+socket:
+  file: ${APISIX_LISTEN_ADDRESS}
\ No newline at end of file
diff --git a/runner-starter/src/test/java/org/apache/apisix/plugin/runner/PluginRunnerApplicationTest.java b/runner-starter/src/test/java/org/apache/apisix/plugin/runner/PluginRunnerApplicationTest.java
index 0262ba1..3b0418d 100644
--- a/runner-starter/src/test/java/org/apache/apisix/plugin/runner/PluginRunnerApplicationTest.java
+++ b/runner-starter/src/test/java/org/apache/apisix/plugin/runner/PluginRunnerApplicationTest.java
@@ -2,6 +2,7 @@ package org.apache.apisix.plugin.runner;
 
 import io.netty.channel.unix.DomainSocketAddress;
 import io.netty.channel.unix.DomainSocketChannel;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Test;
 import reactor.netty.Connection;
@@ -13,6 +14,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 @DisplayName("Unix Domain Socket Listen Test")
 class PluginRunnerApplicationTest {
 
+    @BeforeEach
+    void setUp() {
+        System.setProperty("APISIX_LISTEN_ADDRESS", "unix:/tmp/runner.sock");
+        System.setProperty("APISIX_CONF_EXPIRE_TIME", String.valueOf(3600));
+    }
+
     @Test
     void testMain() {
         PluginRunnerApplication.main(new String[]{"args"});
diff --git a/sample/pom.xml b/sample/pom.xml
index db54efc..86bf052 100644
--- a/sample/pom.xml
+++ b/sample/pom.xml
@@ -41,5 +41,13 @@
             <groupId>com.google.code.gson</groupId>
             <artifactId>gson</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-core</artifactId>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/sample/src/main/java/org/apache/apisix/plugin/runner/filter/RewriteRequestDemoFilter.java b/sample/src/main/java/org/apache/apisix/plugin/runner/filter/RewriteRequestDemoFilter.java
new file mode 100644
index 0000000..7ad93da
--- /dev/null
+++ b/sample/src/main/java/org/apache/apisix/plugin/runner/filter/RewriteRequestDemoFilter.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+package org.apache.apisix.plugin.runner.filter;
+
+import org.apache.apisix.plugin.runner.HttpRequest;
+import org.apache.apisix.plugin.runner.HttpResponse;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+@Component
+public class RewriteRequestDemoFilter implements PluginFilter {
+
+    @Override
+    public String name() {
+        /* It is recommended to keep the name of the filter the same as the class name.
+         Configure the filter to be executed on apisix's routes in the following format
+
+        {
+            "uri": "/hello",
+            "plugins": {
+                "ext-plugin-pre-req": {
+                    "conf": [{
+                        "name": "RewriteRequestDemoFilter",
+                        "value": "bar"
+                    }]
+                }
+            },
+            "upstream": {
+                "nodes": {
+                    "127.0.0.1:1980": 1
+                },
+                "type": "roundrobin"
+            }
+        }
+
+        The value of name in the configuration corresponds to the value of return here.
+         */
+
+        return "RewriteRequestDemoFilter";
+    }
+
+    @Override
+    public Mono<Void> filter(HttpRequest request, HttpResponse response, PluginFilterChain chain) {
+        // note: the path to the rewrite must start with '/'
+        request.setPath("/get");
+        request.setHeader("new-header", "header_by_runner");
+        /* note: The value of the parameter is currently a string type.
+                 If you need the json type, you need the upstream service to parse the string value to json.
+                 For example, if the arg is set as follows
+                 request.setArg("new arg", "{\"key1\":\"value1\",\"key2\":2}");
+
+                 The arg received by the upstream service will be as follows
+                 "new arg": "{\"key1\":\"value1\",\"key2\":2}"
+         */
+        request.setArg("new arg", "{\"key1\":\"value1\",\"key2\":2}");
+
+        return chain.filter(request, response);
+    }
+
+    @Override
+    public int getOrder() {
+        //The order of filter execution in runner is determined by the order here, the smaller the order number, the higher the execution order.
+        return 0;
+    }
+}
diff --git a/sample/src/main/java/org/apache/apisix/plugin/runner/filter/StopRequestDemoFilter.java b/sample/src/main/java/org/apache/apisix/plugin/runner/filter/StopRequestDemoFilter.java
new file mode 100644
index 0000000..d190d02
--- /dev/null
+++ b/sample/src/main/java/org/apache/apisix/plugin/runner/filter/StopRequestDemoFilter.java
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+package org.apache.apisix.plugin.runner.filter;
+
+import org.apache.apisix.plugin.runner.HttpRequest;
+import org.apache.apisix.plugin.runner.HttpResponse;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Mono;
+
+@Component
+public class StopRequestDemoFilter implements PluginFilter {
+    @Override
+    public String name() {
+        return "StopRequestDemoFilter";
+    }
+
+    @Override
+    public Mono<Void> filter(HttpRequest request, HttpResponse response, PluginFilterChain chain) {
+        response.setStatusCode(401);
+        response.setHeader("new-header", "header_by_runner");
+        /* note: The body is currently a string type.
+                 If you need the json type, you need to escape the json content here.
+                 For example, if the body is set as follows
+                 "{\"key1\":\"value1\",\"key2\":2}"
+
+                 The body received by the client will be as follows
+                 {"key1":"value1","key2":2}
+         */
+        response.setBody("{\"key1\":\"value1\",\"key2\":2}");
+
+        /*  Using the above code, the client side receives the following
+
+            header:
+            HTTP/1.1 401 Unauthorized
+            Content-Type: text/plain; charset=utf-8
+            Connection: keep-alive
+            new-header: header_by_runner
+            Server: APISIX/2.6
+
+            body:
+            {"key1":"value1","key2":2}
+         */
+        return chain.filter(request, response);
+    }
+
+    @Override
+    public int getOrder() {
+        return 1;
+    }
+}