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/08/18 03:42:55 UTC
[apisix-python-plugin-runner] branch master updated: feat: add
config and logger module (#19)
This is an automated email from the ASF dual-hosted git repository.
spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-python-plugin-runner.git
The following commit(s) were added to refs/heads/master by this push:
new e2f32fd feat: add config and logger module (#19)
e2f32fd is described below
commit e2f32fdcc85e8585305b88cc9e7e56de082ea465
Author: 帅进超 <sh...@gmail.com>
AuthorDate: Wed Aug 18 11:42:49 2021 +0800
feat: add config and logger module (#19)
---
Makefile | 4 +
apisix/{main.py => config.yaml} | 32 +----
apisix/main.py | 11 +-
apisix/runner/plugin/core.py | 14 ++-
apisix/runner/server/config.py | 130 +++++++++++++++++++++
apisix/runner/server/handle.py | 35 +++---
apisix/runner/server/logger.py | 89 ++++++++++++++
apisix/runner/server/protocol.py | 18 +--
apisix/runner/server/response.py | 56 ++++++---
apisix/runner/server/server.py | 28 +++--
docs/en/latest/getting-started.md | 13 ++-
requirements.txt | 1 +
.../main.py => tests/runner/server/test_config.py | 36 +++---
tests/runner/server/test_handle.py | 18 +--
.../main.py => tests/runner/server/test_logger.py | 39 +++----
tests/runner/server/test_protocol.py | 12 +-
tests/runner/server/test_response.py | 24 ++--
17 files changed, 403 insertions(+), 157 deletions(-)
diff --git a/Makefile b/Makefile
index b290d94..a3fd453 100644
--- a/Makefile
+++ b/Makefile
@@ -46,3 +46,7 @@ clean:
find . -name "*.pyc" -exec rm -r {} +
+.PHONY: dev
+dev:
+ export PYTHONPATH=$PYTHONPATH:$PWD
+ python3 apisix/main.py start
diff --git a/apisix/main.py b/apisix/config.yaml
similarity index 56%
copy from apisix/main.py
copy to apisix/config.yaml
index 3da621d..5e847ab 100644
--- a/apisix/main.py
+++ b/apisix/config.yaml
@@ -14,33 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-import os
-import click
-from apisix.runner.server.server import Server as NewServer
+socket:
+ file: $env.APISIX_LISTEN_ADDRESS # Environment variable or absolute path
-RUNNER_VERSION = "0.1.0"
-RUNNER_SOCKET = os.getenv("APISIX_LISTEN_ADDRESS", "/tmp/runner.sock")
-
-
-@click.group()
-@click.version_option(version=RUNNER_VERSION)
-def runner() -> None:
- pass
-
-
-@runner.command()
-@click.option('--debug/--no-debug', help='enable or disable debug, default disable.', default=False)
-def start(debug) -> None:
- click.echo(debug)
- click.echo(RUNNER_SOCKET)
- server = NewServer(RUNNER_SOCKET)
- server.receive()
-
-
-def main() -> None:
- runner()
-
-
-if __name__ == '__main__':
- main()
+logging:
+ level: warn # error warn info debug
diff --git a/apisix/main.py b/apisix/main.py
index 3da621d..6cee8cf 100644
--- a/apisix/main.py
+++ b/apisix/main.py
@@ -14,13 +14,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-import os
import click
from apisix.runner.server.server import Server as NewServer
+from apisix.runner.server.config import Config as NewConfig
RUNNER_VERSION = "0.1.0"
-RUNNER_SOCKET = os.getenv("APISIX_LISTEN_ADDRESS", "/tmp/runner.sock")
@click.group()
@@ -30,11 +29,9 @@ def runner() -> None:
@runner.command()
-@click.option('--debug/--no-debug', help='enable or disable debug, default disable.', default=False)
-def start(debug) -> None:
- click.echo(debug)
- click.echo(RUNNER_SOCKET)
- server = NewServer(RUNNER_SOCKET)
+def start() -> None:
+ config = NewConfig()
+ server = NewServer(config)
server.receive()
diff --git a/apisix/runner/plugin/core.py b/apisix/runner/plugin/core.py
index 4ebe848..b2b6bab 100644
--- a/apisix/runner/plugin/core.py
+++ b/apisix/runner/plugin/core.py
@@ -17,18 +17,22 @@
import os
import importlib
from pkgutil import iter_modules
+from typing import Tuple
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_OK
+from apisix.runner.server.response import RESP_STATUS_CODE_SERVICE_UNAVAILABLE
-def filter(configs: dict, request, response) -> None:
+def execute(configs: dict, request, response) -> Tuple[int, str]:
for name in configs:
plugin = configs.get(name)
if not plugin:
- print("ERR: plugin `%s` undefined." % name)
- continue
+ return RESP_STATUS_CODE_SERVICE_UNAVAILABLE, "plugin `%s` undefined" % name
try:
plugin.filter(request, response)
- finally:
- print("ERR: plugin `%s` filter execute failure" % name)
+ except AttributeError:
+ return RESP_STATUS_CODE_SERVICE_UNAVAILABLE, "plugin `%s` object has no attribute `filter`" % name
+ return RESP_STATUS_CODE_OK, RESP_STATUS_MESSAGE_OK
def loading() -> dict:
diff --git a/apisix/runner/server/config.py b/apisix/runner/server/config.py
new file mode 100644
index 0000000..f3c09cf
--- /dev/null
+++ b/apisix/runner/server/config.py
@@ -0,0 +1,130 @@
+#
+# 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.
+#
+
+import os
+import yaml
+import logging
+
+
+class _ConfigSocket:
+
+ def __init__(self):
+ """
+ init socket config handler
+ """
+ self.file = "/tmp/runner.sock"
+
+ @property
+ def file(self):
+ """
+ get config file for socket
+ :return:
+ """
+ return self._file
+
+ @file.setter
+ def file(self, file: str) -> None:
+ """
+ set config file for socket
+ :param file:
+ :return:
+ """
+ self._file = file.replace("unix:", "")
+
+
+class _ConfigLogging:
+
+ def __init__(self):
+ self.level = "NOTSET"
+
+ @property
+ def level(self) -> int:
+ """
+ get config level for socket
+ :return:
+ """
+ return self._level
+
+ @level.setter
+ def level(self, level: str) -> None:
+ """
+ set config level for socket
+ :param level:
+ :return:
+ """
+ level = level.upper()
+ _name_to_level = {
+ 'ERROR': logging.ERROR,
+ 'WARN': logging.WARNING,
+ 'INFO': logging.INFO,
+ 'DEBUG': logging.DEBUG,
+ 'NOTSET': logging.NOTSET,
+ }
+ self._level = _name_to_level.get(level, logging.NOTSET)
+
+
+class Config:
+
+ def __init__(self, config_name: str = "config.yaml"):
+ """
+ init config
+ :param config_name:
+ local config file name
+ """
+ self.socket = _ConfigSocket()
+ self.logging = _ConfigLogging()
+ self._loading_config(config_name)
+
+ @staticmethod
+ def _get_env_config(config: str):
+ """
+ get the configuration in the local environment variable
+ :param config:
+ :return:
+ """
+ if isinstance(config, str) and config.find("$env.") != -1:
+ env_name = config.replace("$env.", "")
+ return os.getenv(env_name)
+ return config
+
+ def _loading_config(self, config_name: str):
+ """
+ load local configuration file
+ :param config_name:
+ :return:
+ """
+ abs_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+ cf_path = "%s/%s" % (abs_path, config_name)
+ if not os.path.exists(cf_path):
+ print("ERR: config file `%s` not exists" % cf_path)
+ exit(1)
+
+ # reading config file
+ fs = open(cf_path, encoding="UTF-8")
+ configs = yaml.load(fs, Loader=yaml.FullLoader)
+
+ # socket config
+ socket = configs.get("socket", {})
+ socket_file = self._get_env_config(socket.get("file"))
+ if socket_file:
+ self.socket.file = socket_file
+
+ # logging config
+ logger = configs.get("logging", {})
+ logger_level = self._get_env_config(logger.get("level"))
+ if logger_level:
+ self.logging.level = logger_level
diff --git a/apisix/runner/server/handle.py b/apisix/runner/server/handle.py
index 18fcb60..761c23d 100644
--- a/apisix/runner/server/handle.py
+++ b/apisix/runner/server/handle.py
@@ -15,15 +15,18 @@
# limitations under the License.
#
-from a6pluginproto.Err import Code as A6ErrCode
import apisix.runner.plugin.core as RunnerPlugin
import apisix.runner.plugin.cache as RunnerCache
from apisix.runner.http.response import Response as NewHttpResponse
from apisix.runner.http.response import RESP_MAX_DATA_SIZE
from apisix.runner.http.request import Request as NewHttpRequest
from apisix.runner.server.response import Response as NewServerResponse
-from apisix.runner.server.response import RUNNER_SUCCESS_CODE
-from apisix.runner.server.response import RUNNER_SUCCESS_MESSAGE
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_OK
+from apisix.runner.server.response import RESP_STATUS_CODE_BAD_REQUEST
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_BAD_REQUEST
+from apisix.runner.server.response import RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND
+from apisix.runner.server.response import RESP_STATUS_CODE_SERVICE_UNAVAILABLE
from apisix.runner.http.protocol import RPC_PREPARE_CONF
from apisix.runner.http.protocol import RPC_HTTP_REQ_CALL
from apisix.runner.http.protocol import RPC_UNKNOWN
@@ -79,13 +82,14 @@ class Handle:
# cache plugins config
ok = RunnerCache.set_config_by_token(token, configs)
if not ok:
- return NewServerResponse(code=A6ErrCode.Code.SERVICE_UNAVAILABLE, message="cache token failure")
+ return NewServerResponse(code=RESP_STATUS_CODE_SERVICE_UNAVAILABLE,
+ message="token `%d` cache setting failed" % token)
# init response
resp = NewHttpResponse(RPC_PREPARE_CONF)
resp.token = token
response = resp.flatbuffers()
- return NewServerResponse(code=RUNNER_SUCCESS_CODE, message=RUNNER_SUCCESS_MESSAGE, data=response.Output(),
+ return NewServerResponse(code=RESP_STATUS_CODE_OK, message=RESP_STATUS_MESSAGE_OK, data=response.Output(),
ty=self.type)
def _rpc_call(self) -> NewServerResponse:
@@ -96,22 +100,24 @@ class Handle:
# get plugins
configs = RunnerCache.get_config_by_token(token)
if len(configs) == 0:
- return NewServerResponse(code=A6ErrCode.Code.CONF_TOKEN_NOT_FOUND, message="cache token not found")
+ return NewServerResponse(code=RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND,
+ message="token `%d` cache acquisition failed" % token)
# init response
resp = NewHttpResponse(RPC_HTTP_REQ_CALL)
# execute plugins
- RunnerPlugin.filter(configs, req, resp)
+ (code, message) = RunnerPlugin.execute(configs, req, resp)
response = resp.flatbuffers()
- return NewServerResponse(code=RUNNER_SUCCESS_CODE, message=RUNNER_SUCCESS_MESSAGE, data=response.Output(),
+ return NewServerResponse(code=code, message=message, data=response.Output(),
ty=self.type)
@staticmethod
- def _rpc_unknown(err_code: int = 0) -> NewServerResponse:
+ def _rpc_unknown(err_code: int = RESP_STATUS_CODE_BAD_REQUEST,
+ err_message: str = RESP_STATUS_MESSAGE_BAD_REQUEST) -> NewServerResponse:
resp = NewHttpResponse(RPC_UNKNOWN)
resp.error_code = err_code
response = resp.flatbuffers()
- return NewServerResponse(code=RUNNER_SUCCESS_CODE, message="OK", data=response.Output(),
+ return NewServerResponse(code=err_code, message=err_message, data=response.Output(),
ty=RPC_UNKNOWN)
def dispatch(self) -> NewServerResponse:
@@ -127,11 +133,10 @@ class Handle:
return self._rpc_unknown()
size = len(resp.data)
- if (size > RESP_MAX_DATA_SIZE or size <= 0) and resp.code == 200:
- resp = NewServerResponse(A6ErrCode.Code.SERVICE_UNAVAILABLE,
- "the max length of data is %d but got %d" % (
+ if (size > RESP_MAX_DATA_SIZE or size <= 0) and resp.code == RESP_STATUS_CODE_OK:
+ resp = NewServerResponse(RESP_STATUS_CODE_SERVICE_UNAVAILABLE,
+ "The maximum length of the data is %d, the minimum is 1, but got %d" % (
RESP_MAX_DATA_SIZE, size))
if resp.code != 200:
- print("ERR: %s" % resp.message)
- resp = self._rpc_unknown(resp.code)
+ resp = self._rpc_unknown(resp.code, resp.message)
return resp
diff --git a/apisix/runner/server/logger.py b/apisix/runner/server/logger.py
new file mode 100644
index 0000000..472392b
--- /dev/null
+++ b/apisix/runner/server/logger.py
@@ -0,0 +1,89 @@
+#
+# 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.
+#
+
+import sys
+import logging
+
+
+class Logger:
+ def __init__(self, level: int = logging.NOTSET):
+ """
+ init server logger handler
+ :param level:
+ logger level
+ """
+ self.logger = logging
+ self._init(level)
+
+ def set_level(self, level: int):
+ """
+ set level and reset logger
+ :param level:
+ :return:
+ """
+ self._init(level)
+
+ def _init(self, level: int):
+ """
+ init logger
+ :param level:
+ :return:
+ """
+ self.logger = logging.getLogger()
+ self.logger.setLevel(level)
+
+ handler = logging.StreamHandler(sys.stdout)
+ handler.setLevel(level)
+ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
+ handler.setFormatter(formatter)
+ self.logger.addHandler(handler)
+
+ def info(self, message: str, *objs):
+ """
+ info level logger output
+ :param message:
+ :param objs:
+ :return:
+ """
+ self.logger.info(message.format(*objs))
+
+ def error(self, message: str, *objs):
+ """
+ error level logger output
+ :param message:
+ :param objs:
+ :return:
+ """
+ self.logger.error(message.format(*objs))
+
+ def debug(self, message: str, *objs):
+ """
+ debug level logger output
+ :param message:
+ :param objs:
+ :return:
+ """
+ self.logger.debug(message.format(*objs))
+
+ def warn(self, message: str, *objs):
+ """
+ warning level logger output
+ :param message:
+ :param objs:
+ :return:
+ """
+ self.logger.warning(message.format(*objs))
diff --git a/apisix/runner/server/protocol.py b/apisix/runner/server/protocol.py
index b2e3fc8..3343f11 100644
--- a/apisix/runner/server/protocol.py
+++ b/apisix/runner/server/protocol.py
@@ -15,9 +15,9 @@
# limitations under the License.
#
from apisix.runner.server.response import Response as NewServerResponse
-from apisix.runner.server.response import RUNNER_ERROR_CODE
-from apisix.runner.server.response import RUNNER_SUCCESS_CODE
-from apisix.runner.server.response import RUNNER_SUCCESS_MESSAGE
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_OK
+from apisix.runner.server.response import RESP_STATUS_CODE_BAD_REQUEST
class Protocol:
@@ -57,7 +57,7 @@ class Protocol:
:return:
"""
if len(self.__buffer) == 0:
- return NewServerResponse(RUNNER_ERROR_CODE, "ERR: send buffer is empty")
+ return NewServerResponse(RESP_STATUS_CODE_BAD_REQUEST, "send buffer is empty")
response_len = len(self.__buffer)
response_header = response_len.to_bytes(4, byteorder="big")
response_header = bytearray(response_header)
@@ -65,7 +65,7 @@ class Protocol:
response_header = bytes(response_header)
self.__buffer = response_header + self.__buffer
self.__length = len(self.__buffer)
- return NewServerResponse(code=RUNNER_SUCCESS_CODE, message=RUNNER_SUCCESS_MESSAGE)
+ return NewServerResponse(code=RESP_STATUS_CODE_OK, message=RESP_STATUS_MESSAGE_OK)
def decode(self) -> NewServerResponse:
"""
@@ -73,14 +73,14 @@ class Protocol:
:return:
"""
if len(self.__buffer) == 0:
- return NewServerResponse(RUNNER_ERROR_CODE, "ERR: recv buffer is empty")
+ return NewServerResponse(RESP_STATUS_CODE_BAD_REQUEST, "recv buffer is empty")
length = len(self.__buffer)
if length != 4:
- return NewServerResponse(RUNNER_ERROR_CODE,
- "ERR: recv protocol type length is 4, got %d" % length)
+ return NewServerResponse(RESP_STATUS_CODE_BAD_REQUEST,
+ "recv protocol type length is 4, got %d" % length)
buf = bytearray(self.__buffer)
self.__type = buf[0]
buf[0] = 0
self.__length = int.from_bytes(buf, byteorder="big")
- return NewServerResponse(code=RUNNER_SUCCESS_CODE, message=RUNNER_SUCCESS_MESSAGE)
+ return NewServerResponse(code=RESP_STATUS_CODE_OK, message=RESP_STATUS_MESSAGE_OK)
diff --git a/apisix/runner/server/response.py b/apisix/runner/server/response.py
index f5a2a8c..2835910 100644
--- a/apisix/runner/server/response.py
+++ b/apisix/runner/server/response.py
@@ -17,43 +17,71 @@
from a6pluginproto.Err import Code as A6ErrCode
-RUNNER_SUCCESS_CODE = 200
-RUNNER_SUCCESS_MESSAGE = "OK"
-RUNNER_ERROR_CODE = 500
-RUNNER_ERROR_MESSAGE = "ERR"
-
-errorCodes = [
- A6ErrCode.Code.CONF_TOKEN_NOT_FOUND,
- A6ErrCode.Code.BAD_REQUEST,
- A6ErrCode.Code.SERVICE_UNAVAILABLE,
-]
+RESP_STATUS_CODE_OK = 200
+RESP_STATUS_MESSAGE_OK = "OK"
+RESP_STATUS_CODE_BAD_REQUEST = A6ErrCode.Code.BAD_REQUEST
+RESP_STATUS_MESSAGE_BAD_REQUEST = "Bad Request"
+RESP_STATUS_CODE_SERVICE_UNAVAILABLE = A6ErrCode.Code.BAD_REQUEST
+RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND = A6ErrCode.Code.SERVICE_UNAVAILABLE
class Response:
def __init__(self, code: int = 0, message: str = '', data: bytes = b'', ty: int = 0):
+ """
+ init response handler
+ :param code:
+ response code
+ :param message:
+ response message
+ :param data:
+ response data
+ :param ty:
+ response type
+ """
self.__code = code
self.__message = message
self.__type = ty
self.__data = data
def __eq__(self, response) -> bool:
- return self.code == response.code and \
- self.message == response.message and \
- self.data == response.data and \
- self.type == response.type
+ """
+ compare response handler
+ :param response:
+ response handler
+ :return:
+ """
+ return (
+ self.code == response.code and self.message == response.message and self.data == response.data and
+ self.type == response.type)
@property
def code(self) -> int:
+ """
+ get code by response handler
+ :return:
+ """
return self.__code
@property
def message(self) -> str:
+ """
+ get message by response handler
+ :return:
+ """
return self.__message
@property
def data(self) -> bytes:
+ """
+ get data by response handler
+ :return:
+ """
return self.__data
@property
def type(self) -> int:
+ """
+ get type by response handler
+ :return:
+ """
return self.__type
diff --git a/apisix/runner/server/server.py b/apisix/runner/server/server.py
index 2ad741e..53ca38c 100644
--- a/apisix/runner/server/server.py
+++ b/apisix/runner/server/server.py
@@ -14,30 +14,43 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+
import os
import socket
+
from threading import Thread as NewThread
from apisix.runner.server.handle import Handle as NewServerHandle
from apisix.runner.server.protocol import Protocol as NewServerProtocol
+from apisix.runner.server.config import Config as NewServerConfig
+from apisix.runner.server.logger import Logger as NewServerLogger
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
+
+logger = NewServerLogger()
-def _threaded(conn: socket, debug: bool):
+def _threaded(conn: socket):
while True:
buffer = conn.recv(4)
protocol = NewServerProtocol(buffer, 0)
err = protocol.decode()
- if err.code != 200:
- print(err.message)
+ if err.code != RESP_STATUS_CODE_OK:
+ logger.error(err.message)
break
+ logger.info("request type:{}, len:{}", protocol.type, protocol.length)
+
buffer = conn.recv(protocol.length)
handler = NewServerHandle(protocol.type, buffer)
response = handler.dispatch()
+ if response.code != RESP_STATUS_CODE_OK:
+ logger.error(response.message)
protocol = NewServerProtocol(response.data, response.type)
protocol.encode()
response = protocol.buffer
+ logger.info("response type:{}, len:{}", protocol.type, protocol.length)
+
err = conn.sendall(response)
if err:
print(err)
@@ -47,21 +60,22 @@ def _threaded(conn: socket, debug: bool):
class Server:
- def __init__(self, fd: str, debug: bool = False):
- self.fd = fd.replace("unix:", "")
- self.debug = debug
+ def __init__(self, config: NewServerConfig):
+ self.fd = config.socket.file
if os.path.exists(self.fd):
os.remove(self.fd)
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.sock.bind(self.fd)
self.sock.listen(1024)
+
+ logger.set_level(config.logging.level)
print("listening on unix:%s" % self.fd)
def receive(self):
while True:
conn, address = self.sock.accept()
- NewThread(target=_threaded, args=(conn, self.debug)).start()
+ NewThread(target=_threaded, args=(conn,)).start()
def __del__(self):
self.sock.close()
diff --git a/docs/en/latest/getting-started.md b/docs/en/latest/getting-started.md
index 1550e46..1fdaf95 100644
--- a/docs/en/latest/getting-started.md
+++ b/docs/en/latest/getting-started.md
@@ -73,7 +73,18 @@ apisix:
key: edd1c9f034335f136f87ad84b625c8f1
role: admin
ext-plugin:
- cmd: [ "python3", "/path/to/apache/apisix-python-plugin-runner/apisix/main.py", "start" ]
+ cmd: [ "python3", "/path/to/apisix-python-plugin-runner/apisix/main.py", "start" ]
+```
+
+### Log level and socket configuration (Optional)
+
+```bash
+$ vim /path/to/apisix-python-plugin-runner/apisix/config.yaml
+socket:
+ file: $env.APISIX_LISTEN_ADDRESS # Environment variable or absolute path
+
+logging:
+ level: debug # error warn info debug
```
### Start or Restart APISIX
diff --git a/requirements.txt b/requirements.txt
index 0cd85b8..1b4de80 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
a6pluginprotos==0.1.0
click==8.0.1
minicache==0.0.1
+PyYAML==5.4.1
diff --git a/apisix/main.py b/tests/runner/server/test_config.py
similarity index 56%
copy from apisix/main.py
copy to tests/runner/server/test_config.py
index 3da621d..56df878 100644
--- a/apisix/main.py
+++ b/tests/runner/server/test_config.py
@@ -14,33 +14,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-import os
-import click
-from apisix.runner.server.server import Server as NewServer
+import logging
+from apisix.runner.server.config import Config as NewServerConfig
-RUNNER_VERSION = "0.1.0"
-RUNNER_SOCKET = os.getenv("APISIX_LISTEN_ADDRESS", "/tmp/runner.sock")
+def test_config():
+ config = NewServerConfig()
-@click.group()
-@click.version_option(version=RUNNER_VERSION)
-def runner() -> None:
- pass
+ config.logging.level = "INFO"
+ assert config.logging.level == logging.INFO
+ config.logging.level = "ERROR"
+ assert config.logging.level == logging.ERROR
-@runner.command()
-@click.option('--debug/--no-debug', help='enable or disable debug, default disable.', default=False)
-def start(debug) -> None:
- click.echo(debug)
- click.echo(RUNNER_SOCKET)
- server = NewServer(RUNNER_SOCKET)
- server.receive()
+ config.logging.level = "WARN"
+ assert config.logging.level == logging.WARNING
+ config.logging.level = "NOTSET"
+ assert config.logging.level == logging.NOTSET
-def main() -> None:
- runner()
-
-
-if __name__ == '__main__':
- main()
+ config.socket.file = "/test/runner.sock"
+ assert config.socket.file == "/test/runner.sock"
diff --git a/tests/runner/server/test_handle.py b/tests/runner/server/test_handle.py
index 56ede96..2904c21 100644
--- a/tests/runner/server/test_handle.py
+++ b/tests/runner/server/test_handle.py
@@ -20,8 +20,11 @@ from apisix.runner.http.protocol import RPC_PREPARE_CONF
from apisix.runner.http.protocol import RPC_HTTP_REQ_CALL
from apisix.runner.http.protocol import RPC_UNKNOWN
from apisix.runner.http.protocol import new_builder
-from apisix.runner.server.response import RUNNER_SUCCESS_CODE
-from apisix.runner.server.response import RUNNER_SUCCESS_MESSAGE
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_OK
+from apisix.runner.server.response import RESP_STATUS_CODE_BAD_REQUEST
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_BAD_REQUEST
+from apisix.runner.server.response import RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND
from a6pluginproto.HTTPReqCall import Req as A6HTTPReqCallReq
from a6pluginproto.PrepareConf import Req as A6PrepareConfReq
from a6pluginproto.PrepareConf import Resp as A6PrepareConfResp
@@ -71,8 +74,8 @@ def test_dispatch_config():
handle = NewServerHandle(ty=RPC_PREPARE_CONF, buf=buf)
response = handle.dispatch()
resp = A6PrepareConfResp.Resp.GetRootAs(response.data)
- assert response.code == RUNNER_SUCCESS_CODE
- assert response.message == RUNNER_SUCCESS_MESSAGE
+ assert response.code == RESP_STATUS_CODE_OK
+ assert response.message == RESP_STATUS_MESSAGE_OK
assert response.type == RPC_PREPARE_CONF
assert resp.ConfToken() != 0
@@ -118,14 +121,13 @@ def test_dispatch_call():
handle = NewServerHandle(ty=RPC_HTTP_REQ_CALL, buf=buf)
response = handle.dispatch()
- assert response.code == RUNNER_SUCCESS_CODE
- assert response.message == RUNNER_SUCCESS_MESSAGE
+ assert response.code == RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND
assert response.type == RPC_UNKNOWN
def test_dispatch_unknown():
handle = NewServerHandle(ty=RPC_UNKNOWN)
response = handle.dispatch()
- assert response.code == RUNNER_SUCCESS_CODE
- assert response.message == RUNNER_SUCCESS_MESSAGE
+ assert response.code == RESP_STATUS_CODE_BAD_REQUEST
+ assert response.message == RESP_STATUS_MESSAGE_BAD_REQUEST
assert response.type == RPC_UNKNOWN
diff --git a/apisix/main.py b/tests/runner/server/test_logger.py
similarity index 56%
copy from apisix/main.py
copy to tests/runner/server/test_logger.py
index 3da621d..941c96f 100644
--- a/apisix/main.py
+++ b/tests/runner/server/test_logger.py
@@ -14,33 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-import os
-import click
-from apisix.runner.server.server import Server as NewServer
+import logging
-RUNNER_VERSION = "0.1.0"
-RUNNER_SOCKET = os.getenv("APISIX_LISTEN_ADDRESS", "/tmp/runner.sock")
+from apisix.runner.server.logger import Logger as NewServerLogger
-@click.group()
-@click.version_option(version=RUNNER_VERSION)
-def runner() -> None:
- pass
-
-
-@runner.command()
-@click.option('--debug/--no-debug', help='enable or disable debug, default disable.', default=False)
-def start(debug) -> None:
- click.echo(debug)
- click.echo(RUNNER_SOCKET)
- server = NewServer(RUNNER_SOCKET)
- server.receive()
-
-
-def main() -> None:
- runner()
-
-
-if __name__ == '__main__':
- main()
+def test_logger(capsys):
+ logger = NewServerLogger(logging.DEBUG)
+ logger.error("test error log")
+ logger.warn("test warn log")
+ logger.info("test info log")
+ logger.debug("test debug log")
+ captured = capsys.readouterr()
+ assert captured.out.find("test error log") != -1
+ assert captured.out.find("test warn log") != -1
+ assert captured.out.find("test info log") != -1
+ assert captured.out.find("test debug log") != -1
diff --git a/tests/runner/server/test_protocol.py b/tests/runner/server/test_protocol.py
index 019f653..a38c7b7 100644
--- a/tests/runner/server/test_protocol.py
+++ b/tests/runner/server/test_protocol.py
@@ -17,8 +17,8 @@
from apisix.runner.server.protocol import Protocol as NewServerProtocol
from apisix.runner.http.protocol import RPC_PREPARE_CONF
-from apisix.runner.server.response import RUNNER_SUCCESS_CODE
-from apisix.runner.server.response import RUNNER_SUCCESS_MESSAGE
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
+from apisix.runner.server.response import RESP_STATUS_MESSAGE_OK
def test_protocol_encode():
@@ -30,8 +30,8 @@ def test_protocol_encode():
buf_arr[0] = RPC_PREPARE_CONF
buf_data = bytes(buf_arr) + buf_str
buf_len = len(buf_data)
- assert err.code == RUNNER_SUCCESS_CODE
- assert err.message == RUNNER_SUCCESS_MESSAGE
+ assert err.code == RESP_STATUS_CODE_OK
+ assert err.message == RESP_STATUS_MESSAGE_OK
assert protocol.type == RPC_PREPARE_CONF
assert protocol.buffer == buf_data
assert protocol.length == buf_len
@@ -45,7 +45,7 @@ def test_protocol_decode():
buf_data = bytes(buf_arr)
protocol = NewServerProtocol(buffer=buf_data)
err = protocol.decode()
- assert err.code == RUNNER_SUCCESS_CODE
- assert err.message == RUNNER_SUCCESS_MESSAGE
+ assert err.code == RESP_STATUS_CODE_OK
+ assert err.message == RESP_STATUS_MESSAGE_OK
assert protocol.type == RPC_PREPARE_CONF
assert protocol.length == buf_len
diff --git a/tests/runner/server/test_response.py b/tests/runner/server/test_response.py
index 1dd8ee1..8fe6652 100644
--- a/tests/runner/server/test_response.py
+++ b/tests/runner/server/test_response.py
@@ -16,18 +16,24 @@
#
from apisix.runner.server.response import Response as NewServerResponse
-from apisix.runner.server.response import RUNNER_ERROR_CODE
-from apisix.runner.server.response import RUNNER_SUCCESS_CODE
+from apisix.runner.server.response import RESP_STATUS_CODE_BAD_REQUEST
+from apisix.runner.server.response import RESP_STATUS_CODE_SERVICE_UNAVAILABLE
+from apisix.runner.server.response import RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND
+from apisix.runner.server.response import RESP_STATUS_CODE_OK
from apisix.runner.http.protocol import RPC_PREPARE_CONF
from apisix.runner.http.protocol import RPC_HTTP_REQ_CALL
from apisix.runner.http.protocol import RPC_UNKNOWN
def test_response_code():
- response = NewServerResponse(code=RUNNER_SUCCESS_CODE)
- assert response.code == RUNNER_SUCCESS_CODE
- error = NewServerResponse(code=RUNNER_ERROR_CODE)
- assert error.code == RUNNER_ERROR_CODE
+ resp = NewServerResponse(code=RESP_STATUS_CODE_OK)
+ assert resp.code == RESP_STATUS_CODE_OK
+ resp = NewServerResponse(code=RESP_STATUS_CODE_BAD_REQUEST)
+ assert resp.code == RESP_STATUS_CODE_BAD_REQUEST
+ resp = NewServerResponse(code=RESP_STATUS_CODE_SERVICE_UNAVAILABLE)
+ assert resp.code == RESP_STATUS_CODE_SERVICE_UNAVAILABLE
+ resp = NewServerResponse(code=RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND)
+ assert resp.code == RESP_STATUS_CODE_CONF_TOKEN_NOT_FOUND
def test_response_message():
@@ -50,11 +56,11 @@ def test_response_type():
def test_response_eq():
- resp1 = NewServerResponse(code=RUNNER_SUCCESS_CODE, message="Hello Python Runner",
+ resp1 = NewServerResponse(code=RESP_STATUS_CODE_OK, message="Hello Python Runner",
data="Hello Python Runner".encode(), ty=RPC_PREPARE_CONF)
- resp2 = NewServerResponse(code=RUNNER_ERROR_CODE, message="Hello Python Runner",
+ resp2 = NewServerResponse(code=RESP_STATUS_CODE_BAD_REQUEST, message="Hello Python Runner",
data="Hello Python Runner".encode(), ty=RPC_PREPARE_CONF)
- resp3 = NewServerResponse(code=RUNNER_SUCCESS_CODE, message="Hello Python Runner",
+ resp3 = NewServerResponse(code=RESP_STATUS_CODE_OK, message="Hello Python Runner",
data="Hello Python Runner".encode(), ty=RPC_PREPARE_CONF)
assert resp1 != resp2
assert resp1 == resp3