├── .chglog ├── CHANGELOG.tpl.md └── config.yml ├── .github ├── dependabot.yml └── workflows │ └── python-package.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── Makefile ├── README.md ├── make.bat ├── requirements.txt ├── run.sh └── source │ ├── conf.py │ ├── index.rst │ ├── kong.client.rst │ ├── kong.ctx.rst │ ├── kong.enterprise_edition.rst │ ├── kong.nginx.rst │ ├── kong.rst │ ├── kong.service.rst │ └── modules.rst ├── examples ├── py-hello.py └── py-image.py ├── kong-pluginserver ├── kong-pluginserver.py ├── kong_pdk ├── __init__.py ├── cli.py ├── const.py ├── exception.py ├── kong.py ├── listener.py ├── logger.py ├── module.py ├── pdk │ ├── __init__.py │ └── kong │ │ ├── __init__.py │ │ ├── client │ │ ├── __init__.py │ │ └── tls.py │ │ ├── cluster.py │ │ ├── ctx │ │ ├── __init__.py │ │ └── shared.py │ │ ├── enterprise_edition │ │ ├── __init__.py │ │ └── jwe.py │ │ ├── ip.py │ │ ├── log.py │ │ ├── nginx │ │ ├── __init__.py │ │ └── shared.py │ │ ├── node.py │ │ ├── plugin.py │ │ ├── request.py │ │ ├── response.py │ │ ├── router.py │ │ ├── service │ │ ├── __init__.py │ │ ├── request.py │ │ └── response.py │ │ ├── telemetry.py │ │ └── vault.py └── server.py ├── requirements.txt ├── scripts └── prepare_new_release.sh ├── setup.cfg └── setup.py /.chglog/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | {{ if .Versions -}} 2 | 3 | ## [Unreleased] 4 | 5 | {{ if .Unreleased.CommitGroups -}} 6 | {{ range .Unreleased.CommitGroups -}} 7 | ### {{ .Title }} 8 | {{ range .Commits -}} 9 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} 10 | {{ end }} 11 | {{ end -}} 12 | {{ end -}} 13 | {{ end -}} 14 | 15 | {{ range .Versions }} 16 | 17 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} 18 | {{ range .CommitGroups -}} 19 | ### {{ lower .Title }} 20 | {{ range .Commits -}} 21 | - {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} [{{ .Hash.Short }}]({{ $.Info.RepositoryURL }}/commit/{{ .Hash.Long }}) 22 | {{ end }} 23 | {{ end -}} 24 | 25 | {{- if .NoteGroups -}} 26 | {{ range .NoteGroups -}} 27 | ### {{ .Title }} 28 | {{ range .Notes }} 29 | {{ .Body }} 30 | {{ end }} 31 | {{ end -}} 32 | {{ end -}} 33 | {{ end -}} 34 | 35 | {{- if .Versions }} 36 | [Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD 37 | {{ range .Versions -}} 38 | {{ if .Tag.Previous -}} 39 | [{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} 40 | {{ end -}} 41 | {{ end -}} 42 | {{ end -}} 43 | -------------------------------------------------------------------------------- /.chglog/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/Kong/kong-python-pdk 6 | options: 7 | sort: "semver" 8 | commits: 9 | filters: 10 | Type: 11 | - feat 12 | - fix 13 | - refactor 14 | commit_groups: 15 | title_maps: 16 | feat: Features 17 | fix: Bug Fixes 18 | perf: Performance Improvements 19 | refactor: Code Refactoring 20 | header: 21 | pattern: "^(\\w*)(?:\\([\\w\\$\\.\\-\\*\\s\\/]*\\)|:)?:?\\s(.*)$" 22 | pattern_maps: 23 | - Type 24 | - Subject 25 | notes: 26 | keywords: 27 | - BREAKING CHANGE 28 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | --- 2 | version: 2 3 | updates: 4 | - package-ecosystem: pip 5 | directory: / 6 | schedule: 7 | interval: daily 8 | - package-ecosystem: github-actions 9 | directory: / 10 | schedule: 11 | interval: daily 12 | -------------------------------------------------------------------------------- /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | flake8-lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Check out source repository 17 | uses: actions/checkout@v3.5.3 18 | - name: Set up Python environment 19 | uses: actions/setup-python@v4.6.1 20 | with: 21 | python-version: "3.8" 22 | - name: flake8 Lint 23 | uses: py-actions/flake8@v2 24 | with: 25 | exclude: "docs,kong_pdk/pdk/kong" 26 | build: 27 | 28 | runs-on: ubuntu-latest 29 | strategy: 30 | fail-fast: false 31 | matrix: 32 | python-version: ['3.7', '3.8', '3.9', '3.10'] 33 | 34 | steps: 35 | - uses: actions/checkout@v3.5.3 36 | - name: Set up Python ${{ matrix.python-version }} 37 | uses: actions/setup-python@v4.6.1 38 | with: 39 | python-version: ${{ matrix.python-version }} 40 | - name: Cache pip 41 | uses: actions/cache@v3.3.1 42 | with: 43 | path: ~/.cache/pip 44 | key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} 45 | restore-keys: | 46 | ${{ runner.os }}-pip- 47 | - name: Install dependencies 48 | run: | 49 | python -m pip install --upgrade pip 50 | pip install -r requirements.txt 51 | 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | docs/build/html 132 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [Unreleased] 3 | 4 | 5 | 6 | ## [0.6.0] - 2024-10-10 7 | ### bug fixes 8 | - add missing file enterprise_edition [7b9d281](https://github.com/Kong/kong-python-pdk/commit/7b9d28196c8fc4718a6ad79f0164d243de57af8a) 9 | - delete message queue when they are not needed any more ([#122](https://github.com/Kong/kong-python-pdk/issues/122)) [ffeb2f2](https://github.com/Kong/kong-python-pdk/commit/ffeb2f2185a107f0e6547c4336905fe5dd01bfd0) 10 | - serialize error and disable strict_map_key to allow ([#117](https://github.com/Kong/kong-python-pdk/issues/117)) [25db61c](https://github.com/Kong/kong-python-pdk/commit/25db61cf650b5b8e86e2df066f6bd5282e7c8b48) 11 | 12 | 13 | 14 | ## [0.3.2] - 2022-11-08 15 | ### bug fixes 16 | - add version field in PluginInfo rpc ([#79](https://github.com/Kong/kong-python-pdk/issues/79)) [132f31d](https://github.com/Kong/kong-python-pdk/commit/132f31d526ff3589ac9b93dc079adb18359519cd) 17 | 18 | 19 | 20 | ## [0.3.1] - 2022-06-13 21 | ### bug fixes 22 | - plugin closure syntax correction ([#64](https://github.com/Kong/kong-python-pdk/issues/64)) [920cc26](https://github.com/Kong/kong-python-pdk/commit/920cc26acb84ac357411a5d1d7232a6a540fb9f3) 23 | - removing upper() to allow matching of attributes ([#69](https://github.com/Kong/kong-python-pdk/issues/69)) [1997a6c](https://github.com/Kong/kong-python-pdk/commit/1997a6c9991a6bc21d96d1a7f3c0141a43e01248) 24 | - [#50](https://github.com/Kong/kong-python-pdk/issues/50): return type of get_raw_bodys should be binary string [59ab367](https://github.com/Kong/kong-python-pdk/commit/59ab367c47a3fb56e85c90674d66749dcd4ab937) 25 | - catch error from PDK methods ([#53](https://github.com/Kong/kong-python-pdk/issues/53)) [7f82677](https://github.com/Kong/kong-python-pdk/commit/7f82677de3560c23c6c95bfaccaba6cd302aa571) 26 | - [#50](https://github.com/Kong/kong-python-pdk/issues/50): return type should support binary string [fdb2c9b](https://github.com/Kong/kong-python-pdk/commit/fdb2c9b51d3081cb605af056c3c49e2048061b4e) 27 | 28 | 29 | 30 | ## [0.3.0] - 2022-02-17 31 | ### bug fixes 32 | - add option to use python style error handling to be consistent with style headers [39a75bd](https://github.com/Kong/kong-python-pdk/commit/39a75bd3b060dbda9aec4e84afa01ae6c3000fed) 33 | - include correct instances list in get_status [56d7ad7](https://github.com/Kong/kong-python-pdk/commit/56d7ad762b07d780068384cc1072d3a54f373083) 34 | - exit immediately from kong.response.{error,exit} [ba3d5fa](https://github.com/Kong/kong-python-pdk/commit/ba3d5fae2b040804b1463585641919f76390feda) 35 | 36 | 37 | 38 | ## [0.2.7] - 2021-08-04 39 | ### bug fixes 40 | - correctly pass schema in embedded server [099a498](https://github.com/Kong/kong-python-pdk/commit/099a4987d06602b094274ffd523300daa7985b5a) 41 | - no longer normalize hyphens in socket name in embedded server to keep consistent with what Kong expects [20c01da](https://github.com/Kong/kong-python-pdk/commit/20c01dae1f422e577ec107904f47a57e18788508) 42 | - listener to use msgpack.Unpacker iterrator [bed56c4](https://github.com/Kong/kong-python-pdk/commit/bed56c49160d1adb0e591f69b74337ced7820dba) 43 | - use .py file for type hint ([#13](https://github.com/Kong/kong-python-pdk/issues/13)) [1bf3820](https://github.com/Kong/kong-python-pdk/commit/1bf3820e316f73d6021897b5979af4826e9f34d6) 44 | 45 | 46 | 47 | ## [0.2.4] - 2021-06-17 48 | ### bug fixes 49 | - check correct flags existence in dedicated server ([#10](https://github.com/Kong/kong-python-pdk/issues/10)) [b18dd45](https://github.com/Kong/kong-python-pdk/commit/b18dd458def039a6a2dad4c42baa7b55d64fe027) 50 | - set larger listen queue size ([#9](https://github.com/Kong/kong-python-pdk/issues/9)) [a3eb340](https://github.com/Kong/kong-python-pdk/commit/a3eb3404a42a106cdc4a164ee2c12dcafab90684) 51 | 52 | 53 | 54 | ## [0.2.3] - 2021-05-13 55 | ### bug fixes 56 | - display defaults on cli and print PluginServerException to warning [13991ec](https://github.com/Kong/kong-python-pdk/commit/13991ec5d6373463d847c5ef073543568c0894bb) 57 | - skip running cleanup timer [e10c098](https://github.com/Kong/kong-python-pdk/commit/e10c098a5f4c959f6fce4fc74c3d987443e386bc) 58 | - standarlize error on instance not found [0dfc94f](https://github.com/Kong/kong-python-pdk/commit/0dfc94f3a6cf4ffc90cd2edb8891b1264d26b27c) 59 | 60 | ### features 61 | - add response phase ([#4](https://github.com/Kong/kong-python-pdk/issues/4)) [3aca283](https://github.com/Kong/kong-python-pdk/commit/3aca2836a63eaa6bee09c76777c8cdb39a495c39) 62 | 63 | 64 | 65 | ## [0.2.2] - 2021-03-29 66 | ### bug fixes 67 | - correct license in setup.py ([#3](https://github.com/Kong/kong-python-pdk/issues/3)) [b257c98](https://github.com/Kong/kong-python-pdk/commit/b257c98298343e2911de35d89dc44c1cb0f59547) 68 | - threading mode pipe and styles [6f73ac7](https://github.com/Kong/kong-python-pdk/commit/6f73ac76c6f3fc49081ba67b62e0d9ea4547cbb1) 69 | - enable plugin server without gevent mode [a29c4d7](https://github.com/Kong/kong-python-pdk/commit/a29c4d765fb9e2dfa1a8b27fccb333864a61d529) 70 | 71 | ### features 72 | - add typed interfaces [f98e44d](https://github.com/Kong/kong-python-pdk/commit/f98e44d75271d5daceaf00f8f011ce7efaa19865) 73 | 74 | 75 | 76 | ## [0.2.1] - 2021-02-24 77 | ### bug fixes 78 | - disable gevent in multiprocessing and make it optional [5b6fb68](https://github.com/Kong/kong-python-pdk/commit/5b6fb682d9237ebb75bc653c0536678f3efe7d67) 79 | - chmod+x on examples [1f5905d](https://github.com/Kong/kong-python-pdk/commit/1f5905dc879528c519411b2914e20e2b5236e749) 80 | 81 | ### features 82 | - set friendly process title [aa59083](https://github.com/Kong/kong-python-pdk/commit/aa59083e6ede0394fdf2cb25f9925a36a7cc5aae) 83 | - multiprocessing mode [1a97d26](https://github.com/Kong/kong-python-pdk/commit/1a97d26e773c399149f12bee08943821a3dd9c7b) 84 | 85 | 86 | 87 | ## [0.2.0] - 2021-02-22 88 | ### bug fixes 89 | - sync with Kong 2.3 update [d42de7e](https://github.com/Kong/kong-python-pdk/commit/d42de7ef9565f316890aad3132e432e6a04c77f7) 90 | 91 | ### code refactoring 92 | - rename kong_pluginserver to kong_pdk [e802627](https://github.com/Kong/kong-python-pdk/commit/e802627436e4b856a16e4d68b9329914f2a3a4cc) 93 | 94 | ### features 95 | - exit server if parent is dead [0ee2183](https://github.com/Kong/kong-python-pdk/commit/0ee2183c5679d9cc255435ff98c82d28fbf22f5b) 96 | - embed server in plugin [af55deb](https://github.com/Kong/kong-python-pdk/commit/af55deb6d2f65a8a2be654cd4c8d7f13247869ee) 97 | 98 | 99 | 100 | ## [0.1.2] - 2020-02-21 101 | ### bug fixes 102 | - python2 compatibility [0e4cf1c](https://github.com/Kong/kong-python-pdk/commit/0e4cf1cda574db778e8152b30359e6e9927b0432) 103 | 104 | 105 | 106 | ## [0.1.1] - 2020-02-20 107 | 108 | 109 | ## 0.1.0 - 2020-01-03 110 | 111 | [Unreleased]: https://github.com/Kong/kong-python-pdk/compare/0.6.0...HEAD 112 | [0.6.0]: https://github.com/Kong/kong-python-pdk/compare/0.3.2...0.6.0 113 | [0.3.2]: https://github.com/Kong/kong-python-pdk/compare/0.3.1...0.3.2 114 | [0.3.1]: https://github.com/Kong/kong-python-pdk/compare/0.3.0...0.3.1 115 | [0.3.0]: https://github.com/Kong/kong-python-pdk/compare/0.2.7...0.3.0 116 | [0.2.7]: https://github.com/Kong/kong-python-pdk/compare/0.2.4...0.2.7 117 | [0.2.4]: https://github.com/Kong/kong-python-pdk/compare/0.2.3...0.2.4 118 | [0.2.3]: https://github.com/Kong/kong-python-pdk/compare/0.2.2...0.2.3 119 | [0.2.2]: https://github.com/Kong/kong-python-pdk/compare/0.2.1...0.2.2 120 | [0.2.1]: https://github.com/Kong/kong-python-pdk/compare/0.2.0...0.2.1 121 | [0.2.0]: https://github.com/Kong/kong-python-pdk/compare/0.1.2...0.2.0 122 | [0.1.2]: https://github.com/Kong/kong-python-pdk/compare/0.1.1...0.1.2 123 | [0.1.1]: https://github.com/Kong/kong-python-pdk/compare/0.1.0...0.1.1 124 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2020-2021 Kong Inc. 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kong-python-pluginserver 2 | 3 | [![PyPI version](https://badge.fury.io/py/kong-pdk.svg)](https://badge.fury.io/py/kong-pdk) 4 | 5 | Plugin server and PDK (Plugin Development Kit) for Python language support in Kong. 6 | 7 | Requires Kong >= 2.3.0. 8 | 9 | 10 | ## Documentation 11 | 12 | See in [Kong Docs](https://docs.konghq.com/gateway/latest/plugin-development/pluginserver/python/) 13 | 14 | ## Install the plugin server 15 | 16 | ```shell 17 | pip3 install kong-pdk 18 | ``` 19 | 20 | ## Usage 21 | 22 | ``` 23 | usage: kong-python-pluginserver [-h] [-p prefix] [-v] [--version] [--socket-name SOCKET_NAME] [--listen-queue-size LISTEN_QUEUE_SIZE] 24 | [--no-lua-style] [-m | -g] -d directory [--dump-plugin-info name] [--dump-all-plugins] 25 | 26 | Kong Python Plugin Server. 27 | 28 | optional arguments: 29 | -h, --help show this help message and exit 30 | -p prefix, --kong-prefix prefix, -kong-prefix prefix 31 | unix domain socket path to listen (default: /usr/local/kong/) 32 | -v, --verbose turn on verbose logging (default: 1) 33 | --version, -version show program's version number and exit 34 | --socket-name SOCKET_NAME 35 | socket name to listen on (default: python_pluginserver.sock) 36 | --listen-queue-size LISTEN_QUEUE_SIZE 37 | socket listen queue size (default: 4096) 38 | --no-lua-style turn off Lua-style "data, err" return values for PDK functions and throw exception instead (default: False) 39 | -m, --multiprocessing 40 | enable multiprocessing (default: False) 41 | -g, --gevent enable gevent (default: False) 42 | -d directory, --plugins-directory directory, -plugins-directory directory 43 | plugins directory 44 | --dump-plugin-info name, -dump-plugin-info name 45 | dump specific plugin info into stdout 46 | --dump-all-plugins, -dump-all-plugins 47 | dump all plugins info into stdout 48 | ``` 49 | 50 | ## PDK API reference 51 | 52 | The PDK (plugin developemet kit) API document can be viewed [here](https://kong.github.io/kong-python-pdk/). 53 | 54 | Reference is generated by Sphinx under `doc` folder and published to the `gh-pages` branch. 55 | To generate updated docs, use: 56 | ``` 57 | git worktree add docs/build/html gh-pages 58 | cd docs 59 | make deps && make html 60 | ``` 61 | 62 | ## Deprecation Notice 63 | 64 | In next major release of Kong Python PDK, return values will default to use Python style error handling instead of 65 | Lua style. The new style API can be turned on now with `--no-lua-style`. 66 | 67 | ```python 68 | # old lua-style PDK API 69 | host, err = kong.request.get_header("host") 70 | if err: 71 | pass # error handling 72 | 73 | # new python-style PDK API 74 | try: 75 | host = kong.request.get_header("host") 76 | # no err in return, instead they are thrown if any 77 | except Exception as ex: 78 | pass # error handling 79 | ``` 80 | 81 | ## TODO 82 | 83 | - Tests 84 | - Hot reload 85 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXAPIDOC ?= sphinx-apidoc 8 | SPHINXBUILD ?= sphinx-build 9 | SOURCEDIR = source 10 | BUILDDIR = build 11 | 12 | # Put it first so that "make" without argument is like "make help". 13 | help: 14 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 15 | 16 | .PHONY: help Makefile 17 | 18 | autodoc: 19 | @$(SPHINXAPIDOC) -o "$(SOURCEDIR)" ../kong_pdk/pdk/kong/ -f $(SPHINXOPTS) 20 | 21 | deps: 22 | pip3 install -r requirements.txt 23 | 24 | # Catch-all target: route all unknown targets to Sphinx using the new 25 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 26 | %: autodoc Makefile 27 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 28 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # kong-python-pdk autodoc 2 | 3 | The PDK (plugin developemet kit) API document can be viewed [here](https://kong.github.io/kong-python-pdk/). 4 | 5 | Python types `.pyi` files is generated using https://github.com/fffonion/kong-pdk-autogen: `resty run.lua -t=python -o=../kong/kong-python-pdk/kong_pdk/pdk` 6 | Reference is generated by Sphinx under `doc` folder and published to the `gh-pages` branch. 7 | 8 | To generate updated docs, use: 9 | ``` 10 | git worktree add docs/build/html gh-pages 11 | cd docs 12 | make deps && make html 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.https://www.sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | myst-parser 3 | sphinx_rtd_theme 4 | -------------------------------------------------------------------------------- /docs/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sphinx-apidoc -o ./source/ ../kong_pdk/pdk/kong/ -f 4 | 5 | make html 6 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | # import os 14 | # import sys 15 | # sys.path.insert(0, os.path.abspath('.')) 16 | 17 | 18 | # -- Project information ----------------------------------------------------- 19 | 20 | project = 'kong-pdk' 21 | copyright = '2024, Kong' 22 | author = 'Kong' 23 | 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = ['sphinx.ext.todo', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc'] 31 | 32 | # Add any paths that contain templates here, relative to this directory. 33 | templates_path = ['_templates'] 34 | 35 | # List of patterns, relative to source directory, that match files and 36 | # directories to ignore when looking for source files. 37 | # This pattern also affects html_static_path and html_extra_path. 38 | exclude_patterns = [] 39 | 40 | 41 | # -- Options for HTML output ------------------------------------------------- 42 | import sphinx_rtd_theme 43 | 44 | # The theme to use for HTML and HTML Help pages. See the documentation for 45 | # a list of builtin themes. 46 | # 47 | html_theme = 'sphinx_rtd_theme' 48 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 49 | 50 | # Add any paths that contain custom static files (such as style sheets) here, 51 | # relative to this directory. They are copied after the builtin static files, 52 | # so a file named "default.css" will overwrite the builtin "default.css". 53 | html_static_path = ['_static'] 54 | 55 | import os 56 | import sys 57 | 58 | sys.path.insert(0, os.path.abspath('../../kong_pdk/pdk')) 59 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. kong-pdk documentation master file, created by 2 | sphinx-quickstart on Thu Feb 17 09:21:05 2022. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to kong-pdk's documentation! 7 | ==================================== 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/source/kong.client.rst: -------------------------------------------------------------------------------- 1 | kong.client package 2 | =================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | kong.client.tls module 8 | ---------------------- 9 | 10 | .. automodule:: kong.client.tls 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: kong.client 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/kong.ctx.rst: -------------------------------------------------------------------------------- 1 | kong.ctx package 2 | ================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | kong.ctx.shared module 8 | ---------------------- 9 | 10 | .. automodule:: kong.ctx.shared 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: kong.ctx 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/kong.enterprise_edition.rst: -------------------------------------------------------------------------------- 1 | kong.enterprise\_edition package 2 | ================================ 3 | 4 | Submodules 5 | ---------- 6 | 7 | kong.enterprise\_edition.jwe module 8 | ----------------------------------- 9 | 10 | .. automodule:: kong.enterprise_edition.jwe 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: kong.enterprise_edition 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/kong.nginx.rst: -------------------------------------------------------------------------------- 1 | kong.nginx package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | kong.nginx.shared module 8 | ------------------------ 9 | 10 | .. automodule:: kong.nginx.shared 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | .. automodule:: kong.nginx 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | -------------------------------------------------------------------------------- /docs/source/kong.rst: -------------------------------------------------------------------------------- 1 | kong package 2 | ============ 3 | 4 | Subpackages 5 | ----------- 6 | 7 | .. toctree:: 8 | :maxdepth: 4 9 | 10 | kong.client 11 | kong.ctx 12 | kong.enterprise_edition 13 | kong.nginx 14 | kong.service 15 | 16 | Submodules 17 | ---------- 18 | 19 | kong.cluster module 20 | ------------------- 21 | 22 | .. automodule:: kong.cluster 23 | :members: 24 | :undoc-members: 25 | :show-inheritance: 26 | 27 | kong.ip module 28 | -------------- 29 | 30 | .. automodule:: kong.ip 31 | :members: 32 | :undoc-members: 33 | :show-inheritance: 34 | 35 | kong.log module 36 | --------------- 37 | 38 | .. automodule:: kong.log 39 | :members: 40 | :undoc-members: 41 | :show-inheritance: 42 | 43 | kong.node module 44 | ---------------- 45 | 46 | .. automodule:: kong.node 47 | :members: 48 | :undoc-members: 49 | :show-inheritance: 50 | 51 | kong.plugin module 52 | ------------------ 53 | 54 | .. automodule:: kong.plugin 55 | :members: 56 | :undoc-members: 57 | :show-inheritance: 58 | 59 | kong.request module 60 | ------------------- 61 | 62 | .. automodule:: kong.request 63 | :members: 64 | :undoc-members: 65 | :show-inheritance: 66 | 67 | kong.response module 68 | -------------------- 69 | 70 | .. automodule:: kong.response 71 | :members: 72 | :undoc-members: 73 | :show-inheritance: 74 | 75 | kong.router module 76 | ------------------ 77 | 78 | .. automodule:: kong.router 79 | :members: 80 | :undoc-members: 81 | :show-inheritance: 82 | 83 | kong.vault module 84 | ----------------- 85 | 86 | .. automodule:: kong.vault 87 | :members: 88 | :undoc-members: 89 | :show-inheritance: 90 | 91 | Module contents 92 | --------------- 93 | 94 | .. automodule:: kong 95 | :members: 96 | :undoc-members: 97 | :show-inheritance: 98 | -------------------------------------------------------------------------------- /docs/source/kong.service.rst: -------------------------------------------------------------------------------- 1 | kong.service package 2 | ==================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | kong.service.request module 8 | --------------------------- 9 | 10 | .. automodule:: kong.service.request 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | kong.service.response module 16 | ---------------------------- 17 | 18 | .. automodule:: kong.service.response 19 | :members: 20 | :undoc-members: 21 | :show-inheritance: 22 | 23 | Module contents 24 | --------------- 25 | 26 | .. automodule:: kong.service 27 | :members: 28 | :undoc-members: 29 | :show-inheritance: 30 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | kong 2 | ==== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | kong 8 | -------------------------------------------------------------------------------- /examples/py-hello.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import kong_pdk.pdk.kong as kong 4 | 5 | Schema = ( 6 | {"message": {"type": "string"}}, 7 | ) 8 | 9 | version = '0.1.0' 10 | priority = 0 11 | 12 | # This is an example plugin that add a header to the response 13 | 14 | class Plugin(object): 15 | def __init__(self, config): 16 | self.config = config 17 | 18 | def access(self, kong: kong.kong): 19 | host, err = kong.request.get_header("host") 20 | if err: 21 | pass # error handling 22 | # if run with --no-lua-style 23 | # try: 24 | # host = kong.request.get_header("host") 25 | # except Exception as ex: 26 | # pass # error handling 27 | message = "hello" 28 | if 'message' in self.config: 29 | message = self.config['message'] 30 | kong.response.set_header("x-hello-from-python", "Python says %s to %s" % (message, host)) 31 | kong.response.set_header("x-python-pid", str(os.getpid())) 32 | 33 | 34 | # add below section to allow this plugin optionally be running in a dedicated process 35 | if __name__ == "__main__": 36 | from kong_pdk.cli import start_dedicated_server 37 | start_dedicated_server("py-hello", Plugin, version, priority, Schema) 38 | -------------------------------------------------------------------------------- /examples/py-image.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from PIL import Image 4 | from PIL import ImageFont 5 | from PIL import ImageDraw 6 | import io 7 | 8 | version = '0.1.0' 9 | priority = 0 10 | 11 | # This is an example plugin that uses PIL to generate an PNG image 12 | # containing text of the request headers 13 | # Run the following commands first: 14 | ''' 15 | sudo apt install ttf-mscorefonts-installer 16 | sudo apt install font-manager 17 | sudo fc-cache -f -v 18 | python3 -m pip install Pillow 19 | ''' 20 | 21 | class Plugin(object): 22 | def __init__(self, config): 23 | self.config = config 24 | 25 | def access(self, kong): 26 | img = Image.new("RGB", (800, 200)) 27 | draw = ImageDraw.Draw(img) 28 | font = ImageFont.truetype("Comic_Sans_MS.ttf", 24) 29 | y = 0 30 | headers, _ = kong.request.get_headers() 31 | for h in headers: 32 | y = y + 32 33 | draw.text((0, y), "%s: %s" % (h, headers[h]), (255, 255, 255), font=font) 34 | b = io.BytesIO() 35 | img.save(b, format='PNG') 36 | kong.response.exit(200, 37 | b.getvalue() 38 | ) 39 | 40 | 41 | # add below section to allow this plugin optionally be running in a dedicated process 42 | if __name__ == "__main__": 43 | from kong_pdk.cli import start_dedicated_server 44 | start_dedicated_server("py-image", Plugin, version, priority, []) 45 | -------------------------------------------------------------------------------- /kong-pluginserver: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from kong_pdk import cli 4 | 5 | cli.start_server() 6 | -------------------------------------------------------------------------------- /kong-pluginserver.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from kong_pdk import cli 4 | 5 | cli.start_server() 6 | -------------------------------------------------------------------------------- /kong_pdk/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kong/kong-python-pdk/88f638a8c95f6bc31ace210e2964e19bd4e01249/kong_pdk/__init__.py -------------------------------------------------------------------------------- /kong_pdk/cli.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # Contributor: 3 | # fffonion 4 | 5 | import os 6 | import sys 7 | import argparse 8 | import msgpack 9 | import json 10 | 11 | from .server import PluginServer 12 | from .listener import UnixStreamServer, DEFAULT_SOCKET_NAME 13 | from .logger import Logger 14 | 15 | from .const import __version__, PY3K 16 | 17 | def parse(dedicated=False): 18 | parser = argparse.ArgumentParser(description='Kong Python Plugin Server.') 19 | parser.add_argument('-p', '--kong-prefix', '-kong-prefix', 20 | dest='prefix', metavar='prefix', type=str, 21 | default="/usr/local/kong/", 22 | help='unix domain socket path to listen (default: %(default)s)') 23 | parser.add_argument('-v', '--verbose', action='count', default=1, 24 | help='turn on verbose logging (default: %(default)s)') 25 | parser.add_argument('--version', '-version', action='version', 26 | version='%(prog)s {version}'.format(version=__version__)) 27 | parser.add_argument('--socket-name', type=str, dest='socket_name', default=DEFAULT_SOCKET_NAME, 28 | help='socket name to listen on (default: %(default)s)') 29 | parser.add_argument('--listen-queue-size', type=int, dest='listen_queue_size', default=4096, 30 | help='socket listen queue size (default: %(default)s)') 31 | parser.add_argument('--no-lua-style', action='store_true', dest='no_lua_style', default=False, 32 | help='turn off Lua-style "data, err" return values for PDK functions ' 33 | 'and throw exception instead (default: %(default)s)') 34 | mxg = parser.add_mutually_exclusive_group() 35 | mxg.add_argument('-m', '--multiprocessing', dest='multiprocessing', action="store_true", 36 | help='enable multiprocessing (default: %(default)s)') 37 | mxg.add_argument('-g', '--gevent', dest='gevent', action="store_true", 38 | help='enable gevent (default: %(default)s)') 39 | 40 | if not dedicated: 41 | parser.add_argument('-d', '--plugins-directory', '-plugins-directory', 42 | dest='directory', metavar='directory', type=str, required=True, 43 | help='plugins directory') 44 | parser.add_argument('--dump-plugin-info', '-dump-plugin-info', dest='dump_info', metavar='name', type=str, 45 | help='dump specific plugin info into stdout') 46 | parser.add_argument('--dump-all-plugins', '-dump-all-plugins', dest='dump_all_info', action="store_true", 47 | help='dump all plugins info into stdout') 48 | else: 49 | parser.add_argument('--dump', '-dump', dest='dump', action="store_true", 50 | help='dump current plugin info into stdout') 51 | 52 | args = parser.parse_args() 53 | 54 | if ((not dedicated and not args.dump_info and not args.dump_all_info) 55 | or (dedicated and not args.dump)) and not os.path.exists(args.prefix): 56 | raise OSError("path %s doesn't exist, can't create unix socket file" % args.prefix) 57 | 58 | return args 59 | 60 | def display_lua_style_notice(lua_style, ps): 61 | if not lua_style: 62 | ps.logger.debug("python-style return values are enabled, " 63 | "errors are thrown as exception") 64 | else: 65 | ps.logger.warn("lua-style return values are used, " 66 | "this will be deprecated in the future; instead of returning " 67 | "(data, err) tuple, only data will be returned and err will be " 68 | "thrown as PDKException; please adjust your plugin to use the " 69 | "new python-style PDK API.") 70 | 71 | def start_server(): 72 | args = parse() 73 | 74 | prefix = args.prefix 75 | 76 | ps = PluginServer(loglevel=Logger.WARNING - args.verbose, 77 | plugin_dir=args.directory, 78 | use_multiprocess=args.multiprocessing, 79 | use_gevent=args.gevent, 80 | lua_style=not args.no_lua_style) 81 | ss = UnixStreamServer(ps, prefix, 82 | sock_name=args.socket_name, 83 | use_gevent=args.gevent, 84 | listen_queue_size=args.listen_queue_size) 85 | if args.dump_info: 86 | ret, err = ps.get_plugin_info(args.dump_info) 87 | if err: 88 | raise Exception("error dump info: " + err) 89 | if PY3K: 90 | sys.stdout.buffer.write(msgpack.packb(ret)) 91 | else: 92 | sys.stdout.write(msgpack.packb(ret)) 93 | sys.exit(0) 94 | elif args.dump_all_info: 95 | ret = [] 96 | for p in ps.plugins: 97 | inf = ps.get_plugin_info(p) 98 | ret.append(inf) 99 | sys.stdout.write(json.dumps(ret)) 100 | sys.exit(0) 101 | 102 | display_lua_style_notice(not args.no_lua_style, ps) 103 | 104 | try: 105 | ss.serve_forever() 106 | except KeyboardInterrupt: 107 | ps.logger.info("polite exit requested, terminating...") 108 | 109 | ps.cleanup() 110 | 111 | def start_dedicated_server(name, plugin, _version=None, _priority=0, _schema=[]): 112 | from .module import Module 113 | 114 | args = parse(dedicated=True) 115 | 116 | ps = PluginServer(loglevel=Logger.WARNING - args.verbose, 117 | use_multiprocess=args.multiprocessing, 118 | use_gevent=args.gevent, 119 | name="%s version %s" % (name, _version or 'unknown'), 120 | lua_style=not args.no_lua_style) 121 | socket_name = args.socket_name 122 | if socket_name == DEFAULT_SOCKET_NAME: 123 | socket_name = "%s.sock" % name 124 | ss = UnixStreamServer(ps, args.prefix, 125 | sock_name=socket_name, 126 | use_gevent=args.gevent, 127 | listen_queue_size=args.listen_queue_size) 128 | 129 | class mod(object): 130 | Plugin = plugin 131 | Schema = _schema 132 | version = _version 133 | priority = _priority 134 | 135 | mod = Module(name, module=mod) 136 | ps.plugins[name] = mod 137 | 138 | if args.dump: 139 | ret = ps.get_plugin_info(name) 140 | # note a list is returned 141 | sys.stdout.write(json.dumps([ret])) 142 | sys.exit(0) 143 | 144 | display_lua_style_notice(not args.no_lua_style, ps) 145 | 146 | try: 147 | ss.serve_forever() 148 | except KeyboardInterrupt: 149 | ps.logger.info("polite exit requested, terminating...") 150 | 151 | ps.cleanup() 152 | -------------------------------------------------------------------------------- /kong_pdk/const.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # constants module 3 | # Contributor: 4 | # fffonion 5 | 6 | import os 7 | import sys 8 | import locale 9 | 10 | PY3K = sys.version_info.major == 3 11 | IRONPYTHON = sys.platform == 'cli' 12 | EXEBUNDLE = getattr(sys, 'frozen', False) 13 | LOCALE = locale.getdefaultlocale()[0] 14 | CODEPAGE = locale.getdefaultlocale()[1] or 'ascii' 15 | 16 | __version__ = 0.40 17 | 18 | # https://github.com/soimort/you-get/you-get 19 | if getattr(sys, 'frozen', False): 20 | # The application is frozen 21 | FILEPATH = os.path.dirname(os.path.realpath(sys.executable)) 22 | else: 23 | # The application is not frozen 24 | # Change this bit to match where you store your data files: 25 | FILEPATH = sys.path[0] 26 | -------------------------------------------------------------------------------- /kong_pdk/exception.py: -------------------------------------------------------------------------------- 1 | class PluginServerException(Exception): 2 | pass 3 | 4 | class PDKException(Exception): 5 | pass 6 | -------------------------------------------------------------------------------- /kong_pdk/kong.py: -------------------------------------------------------------------------------- 1 | class kong(): 2 | pass 3 | -------------------------------------------------------------------------------- /kong_pdk/listener.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import sys 4 | import time 5 | import traceback 6 | import threading 7 | import msgpack 8 | 9 | from .const import PY3K 10 | if PY3K: 11 | from socketserver import ThreadingMixIn, UnixStreamServer as sUnixStreamServer 12 | else: 13 | from SocketServer import ThreadingMixIn, UnixStreamServer as sUnixStreamServer 14 | 15 | from gevent import socket as gsocket, sleep as gsleep, spawn as gspawn 16 | from gevent.server import StreamServer as gStreamServer 17 | 18 | from .exception import PDKException, PluginServerException 19 | 20 | cmdre = re.compile("([a-z])([A-Z])") 21 | 22 | DEFAULT_SOCKET_NAME = "python_pluginserver.sock" 23 | 24 | def write_response(fd, msgid, response): 25 | fd.send(msgpack.packb([ 26 | 1, # is response 27 | msgid, 28 | None, 29 | response 30 | ])) 31 | 32 | def write_error(fd, msgid, error): 33 | fd.send(msgpack.packb([ 34 | 1, # is response 35 | msgid, 36 | error, 37 | None 38 | ])) 39 | 40 | 41 | class WrapSocket(object): 42 | def __init__(self, socket): 43 | self.socket = socket 44 | 45 | def read(self, n): 46 | return self.socket.recv(n) 47 | 48 | class Server(object): 49 | def __init__(self, plugin_server): 50 | self.ps = plugin_server 51 | self.logger = plugin_server.logger 52 | 53 | def handle(self, fd, address, *_): 54 | # can't use socket.makefile here, since it returns a blocking IO 55 | # msgpack.Unpacker only expects read() but no other semantics to exist 56 | sockf = WrapSocket(fd) 57 | unpacker = msgpack.Unpacker(sockf, strict_map_key=False) 58 | 59 | for _, msgid, method, args in unpacker: 60 | ns, cmd = method.split(".") 61 | if ns != "plugin": 62 | write_error(fd, msgid, "RPC for %s is not supported" % ns) 63 | continue 64 | 65 | cmd_r = cmd[0].lower() + cmdre.sub(lambda m: "%s_%s" % (m.group(1), m.group(2).lower()), cmd[1:]) 66 | try: 67 | self.logger.debug("rpc: #%d method: %s args: %s" % (msgid, method, args)) 68 | ret = getattr(self.ps, cmd_r)(*args) 69 | self.logger.debug("rpc: #%d return: %s" % (msgid, ret)) 70 | write_response(fd, msgid, ret) 71 | except (PluginServerException, PDKException) as ex: 72 | self.logger.warn("rpc: #%d error: %s" % (msgid, str(ex))) 73 | write_error(fd, msgid, str(ex)) 74 | except Exception as ex: 75 | self.logger.error("rpc: #%d exception: %s" % (msgid, traceback.format_exc())) 76 | write_error(fd, msgid, str(ex)) 77 | 78 | class tUnixStreamServer(ThreadingMixIn, sUnixStreamServer): 79 | pass 80 | 81 | def watchdog(sleep, logger): 82 | while True: 83 | if os.getppid() == 1: # parent dead, process adopted by init 84 | logger.info("Kong exits, terminating...") 85 | sys.exit() 86 | sleep(1) 87 | 88 | class UnixStreamServer(Server): 89 | def __init__(self, pluginserver, path, 90 | sock_name=DEFAULT_SOCKET_NAME, use_gevent=True, listen_queue_size=4096): 91 | Server.__init__(self, pluginserver) 92 | self.path = os.path.join(path, sock_name) 93 | self.use_gevent = use_gevent 94 | self.listen_queue_size = listen_queue_size 95 | 96 | def serve_forever(self): 97 | if os.path.exists(self.path): 98 | os.remove(self.path) 99 | 100 | if self.use_gevent: 101 | listener = gsocket.socket(gsocket.AF_UNIX, gsocket.SOCK_STREAM) 102 | listener.bind(self.path) 103 | listener.listen(self.listen_queue_size) 104 | 105 | self.logger.info("server (gevent) started at path " + self.path) 106 | 107 | gspawn(watchdog, gsleep, self.logger) 108 | 109 | gStreamServer(listener, self.handle).serve_forever() 110 | else: 111 | import socket 112 | self.logger.info("server started at path " + self.path) 113 | 114 | t = threading.Thread( 115 | target=watchdog, 116 | args=(time.sleep, self.logger, ), 117 | ) 118 | t.setDaemon(True) 119 | t.start() 120 | s = tUnixStreamServer(self.path, self.handle, bind_and_activate=False) 121 | s.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) 122 | s.server_bind() 123 | s.socket.listen(self.listen_queue_size) 124 | s.serve_forever() 125 | -------------------------------------------------------------------------------- /kong_pdk/logger.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # Contributor: 3 | # fffonion 4 | 5 | import os 6 | import sys 7 | import datetime 8 | import locale 9 | import traceback 10 | from threading import RLock 11 | from .const import PY3K 12 | 13 | class tz_GMT8(datetime.tzinfo): 14 | def utcoffset(self, dt): 15 | return datetime.timedelta(hours=8) 16 | 17 | def dst(self, dt): 18 | return datetime.timedelta(0) 19 | 20 | 21 | if PY3K: 22 | unicode = None 23 | 24 | def safestr(s): 25 | if (PY3K and isinstance(s, bytes)) or (not PY3K and not isinstance(s, unicode)): 26 | s = s.decode("utf-8") 27 | if PY3K: 28 | # python<=3.5 hack 29 | if sys.version_info.minor <= 5: 30 | return s \ 31 | .encode(locale.getdefaultlocale()[1] or 'utf-8', 'replace') \ 32 | .decode(locale.getdefaultlocale()[1] or 'utf-8', 'replace') 33 | return s 34 | return s.encode(locale.getdefaultlocale()[1] or 'utf-8', 'replace') 35 | # return _.decode('utf-8') if PY3K else _ 36 | 37 | 38 | if os.name == 'nt': 39 | endl = '\r\n' 40 | else: # assume posix 41 | endl = '\n' 42 | 43 | class Logger(object): 44 | # paste from goagent 45 | CRITICAL = 5 46 | FATAL = CRITICAL 47 | ERROR = 4 48 | WARNING = 3 49 | WARN = WARNING 50 | INFO = 2 51 | DEBUG = 1 52 | VERBOSE = 0 53 | 54 | def __init__(self, *args, **kwargs): 55 | # self.level = self.__class__.INFO 56 | self.logf = None 57 | self.__write = __write = lambda x: sys.stdout.write(safestr(x)) 58 | self.isatty = getattr(sys.stdout, 'isatty', lambda: False)() 59 | self.__set_error_color = lambda: None 60 | self.__set_warning_color = lambda: None 61 | self.__set_debug_color = lambda: None 62 | self.__set_verbose_color = lambda: None 63 | self.__reset_color = lambda: None 64 | if self.isatty: 65 | if os.name == 'nt': 66 | self._nt_color_lock = RLock() 67 | import ctypes 68 | SetConsoleTextAttribute = ctypes.windll.kernel32.SetConsoleTextAttribute 69 | GetStdHandle = ctypes.windll.kernel32.GetStdHandle 70 | self.__set_error_color = lambda: (self._nt_color_lock.acquire(), SetConsoleTextAttribute(GetStdHandle(-11), 0x0C)) 71 | self.__set_warning_color = lambda: (self._nt_color_lock.acquire(), SetConsoleTextAttribute(GetStdHandle(-11), 0x06)) 72 | self.__set_debug_color = lambda: (self._nt_color_lock.acquire(), SetConsoleTextAttribute(GetStdHandle(-11), 0x02)) 73 | self.__set_verbose_color = lambda: (self._nt_color_lock.acquire(), SetConsoleTextAttribute(GetStdHandle(-11), 0x08)) 74 | self.__set_bright_color = lambda: (self._nt_color_lock.acquire(), SetConsoleTextAttribute(GetStdHandle(-11), 0x0F)) 75 | self.__reset_color = lambda: (SetConsoleTextAttribute(GetStdHandle(-11), 0x07), self._nt_color_lock.release()) 76 | elif os.name == 'posix': 77 | self.__set_error_color = lambda: __write('\033[31m') 78 | self.__set_warning_color = lambda: __write('\033[33m') 79 | self.__set_debug_color = lambda: __write('\033[32m') 80 | self.__set_verbose_color = lambda: __write('\033[36m') 81 | self.__set_bright_color = lambda: __write('\033[32m') 82 | self.__reset_color = lambda: __write('\033[0m') 83 | 84 | @classmethod 85 | def getLogger(cls, *args, **kwargs): 86 | return cls(*args, **kwargs) 87 | 88 | def cleanup(self): 89 | if self.logf: 90 | _ = self.logf 91 | self.logf = None 92 | _.close() 93 | 94 | def set_logfile(self, fpath): 95 | if self.logf: 96 | self.logf.close() 97 | self.logf = open(fpath, "ab") 98 | 99 | def set_level(self, level): 100 | f = ('verbose', 'debug', 'info') 101 | lv = min(max(level, 0), 3) 102 | for p in range(lv): 103 | setattr(self, f[p], self.dummy) 104 | 105 | def log(self, level, fmt, *args, **kwargs): 106 | # fmt=du8(fmt) 107 | try: 108 | try: 109 | self.__write('%-4s - [%s] %s\n' % (level, datetime.datetime.now(tz_GMT8()).strftime('%X'), fmt % args)) 110 | except (ValueError, TypeError): 111 | fmt = fmt.replace('%', '%%') 112 | self.__write('%-4s - [%s] %s\n' % (level, datetime.datetime.now(tz_GMT8()).strftime('%X'), fmt % args)) 113 | except IOError: # fix for Windows console 114 | pass 115 | sys.stdout.flush() 116 | if self.logf: 117 | _ = ('[%s] %s%s' % (datetime.datetime.now(tz_GMT8()).strftime('%b %d %X'), fmt % args, endl)) 118 | self.logf.write(_.encode("utf-8", 'replace')) 119 | 120 | def dummy(self, *args, **kwargs): 121 | pass 122 | 123 | def debug(self, fmt, *args, **kwargs): 124 | self.__set_debug_color() 125 | self.log('DEBG', fmt, *args, **kwargs) 126 | self.__reset_color() 127 | 128 | def info(self, fmt, *args, **kwargs): 129 | self.log('INFO', fmt, *args) 130 | 131 | def verbose(self, fmt, *args, **kwargs): 132 | self.__set_verbose_color() 133 | self.log('VERB', fmt, *args, **kwargs) 134 | self.__reset_color() 135 | 136 | def warning(self, fmt, *args, **kwargs): 137 | self.__set_warning_color() 138 | self.log('WARN', fmt, *args, **kwargs) 139 | self.__reset_color() 140 | 141 | def warn(self, fmt, *args, **kwargs): 142 | self.warning(fmt, *args, **kwargs) 143 | 144 | def error(self, fmt, *args, **kwargs): 145 | self.__set_error_color() 146 | self.log('ERROR', fmt, *args, **kwargs) 147 | self.__reset_color() 148 | 149 | def exception(self, fmt, *args, **kwargs): 150 | self.error(fmt, *args, **kwargs) 151 | traceback.print_exc(file=sys.stderr) 152 | 153 | def critical(self, fmt, *args, **kwargs): 154 | self.__set_error_color() 155 | self.log('CRITICAL', fmt, *args, **kwargs) 156 | self.__reset_color() 157 | -------------------------------------------------------------------------------- /kong_pdk/module.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | from .const import PY3K, FILEPATH 5 | from .exception import PDKException 6 | if PY3K: 7 | import importlib.util 8 | 9 | def load_module(name, path): 10 | spec = importlib.util.spec_from_file_location(name, path) 11 | mod = importlib.util.module_from_spec(spec) 12 | spec.loader.exec_module(mod) 13 | sys.modules[name] = mod 14 | return mod 15 | else: 16 | import imp 17 | methods = { 18 | '.py': imp.load_source, 19 | '.pyc': imp.load_compiled, 20 | '.pyo': imp.load_compiled, 21 | '.pyd': imp.load_dynamic, 22 | '.so': imp.load_dynamic, 23 | } 24 | 25 | def load_module(name, path): 26 | ext = os.path.splitext(path)[1] 27 | mod = methods[ext](name, path) 28 | sys.modules[name] = mod 29 | return mod 30 | 31 | phases = ("certificate", "rewrite", "log", "access", "preread", "response") 32 | 33 | class Module(object): 34 | def __init__(self, name, path=None, module=None): 35 | self.name = name 36 | self.load_time = time.time() 37 | 38 | if path: 39 | mod = load_module(name, path) 40 | self.mod = mod 41 | self.mtime = os.stat(path).st_mtime 42 | elif module: 43 | mod = module 44 | self.mtime = os.stat(FILEPATH).st_mtime 45 | else: 46 | raise PDKException("either path or module needs to be passed in") 47 | 48 | self.cls = getattr(mod, "Plugin") 49 | 50 | self.phases = [] 51 | for phase in phases: 52 | if hasattr(self.cls, phase): 53 | self.phases.append(phase) 54 | 55 | self.priority = 0 56 | self.version = None 57 | 58 | for attr in ('version', 'priority'): 59 | if hasattr(mod, attr): 60 | setattr(self, attr, getattr(mod, attr)) 61 | 62 | if hasattr(mod, "Schema"): 63 | self.schema = mod.Schema 64 | else: 65 | self.schema = [] 66 | 67 | self.last_start_instance_time = 0 68 | self.last_close_instance_time = 0 69 | 70 | def new(self, config): 71 | self.last_start_instance_time = time.time() 72 | return Instance(self.name, config, self.cls, self.set_last_close_instance_time) 73 | 74 | def set_last_close_instance_time(self): 75 | self.last_close_instance_time = time.time() 76 | 77 | 78 | class Instance(object): 79 | def __init__(self, name, config, cls, close_cb): 80 | self.cls = cls(config) 81 | self.name = name 82 | self.config = config 83 | self.start_time = time.time() 84 | self.last_used_time = 0 85 | self.close_cb = close_cb 86 | 87 | def is_expired(self, ttl=60): 88 | until = time.time() - ttl 89 | return self.start_time < until and self.last_used_time < until 90 | 91 | def reset_expire_ts(self): 92 | self.last_used_time = time.time() 93 | return self.cls 94 | -------------------------------------------------------------------------------- /kong_pdk/pdk/__init__.py: -------------------------------------------------------------------------------- 1 | from ..exception import PDKException 2 | 3 | class FakeClasses(object): 4 | def __init__(self, prefix, call): 5 | self.prefix = prefix 6 | self.call = call 7 | 8 | def __call__(self, *a): 9 | return self.call(self.prefix, *a) 10 | 11 | # TODO 12 | def __str__(self): 13 | return self.call(self.prefix) 14 | 15 | def __getattr__(self, k): 16 | return FakeClasses(self.prefix + "." + k, self.call) 17 | 18 | 19 | # those methods never return, instead, they exit from current request immediately 20 | non_return_methods = set(( 21 | "kong.response.exit", 22 | "kong.response.error", 23 | )) 24 | 25 | def rpc_of(ch, lua_style): 26 | def f(m, *a): 27 | # sanitize non-serializable objects 28 | if m == "kong.log" or m.startswith("kong.log."): 29 | a = list(a) 30 | for i in range(len(a)): 31 | if type(a[i]) not in (str, int, list, dict): 32 | a[i] = str(a[i]) 33 | 34 | ch.put({ 35 | "Method": m, 36 | "Args": a, 37 | }) 38 | if m in non_return_methods: 39 | return 40 | 41 | data, err = ch.get() 42 | if lua_style: 43 | return data, err 44 | if err: 45 | raise PDKException("exception from %s: %s" % (m, err)) 46 | return data 47 | return f 48 | 49 | class Kong(object): 50 | def __init__(self, ch, lua_style=False): 51 | self.kong = FakeClasses("kong", self.bridge) 52 | self.rpc = rpc_of(ch, lua_style) 53 | 54 | def bridge(self, attr, *args): 55 | return self.rpc(attr, *args) 56 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/__init__.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | from .client import client as cls_client 13 | from .cluster import cluster as cls_cluster 14 | from .ctx import ctx as cls_ctx 15 | from .enterprise_edition import enterprise_edition as cls_enterprise_edition 16 | from .ip import ip as cls_ip 17 | from .log import log as cls_log 18 | from .nginx import nginx as cls_nginx 19 | from .node import node as cls_node 20 | from .plugin import plugin as cls_plugin 21 | from .request import request as cls_request 22 | from .response import response as cls_response 23 | from .router import router as cls_router 24 | from .service import service as cls_service 25 | from .telemetry import telemetry as cls_telemetry 26 | from .vault import vault as cls_vault 27 | 28 | class kong(): 29 | 30 | client = cls_client 31 | cluster = cls_cluster 32 | ctx = cls_ctx 33 | enterprise_edition = cls_enterprise_edition 34 | ip = cls_ip 35 | log = cls_log 36 | nginx = cls_nginx 37 | node = cls_node 38 | plugin = cls_plugin 39 | request = cls_request 40 | response = cls_response 41 | router = cls_router 42 | service = cls_service 43 | telemetry = cls_telemetry 44 | vault = cls_vault 45 | 46 | pass 47 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/client/__init__.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/client.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | from .tls import tls as cls_tls 13 | 14 | class client(): 15 | 16 | tls = cls_tls 17 | 18 | @staticmethod 19 | def authenticate(consumer: table, credential: table) -> None: 20 | """ 21 | 22 | Sets the authenticated consumer and/or credential as well 23 | as the authenticated consumer-group for the current request. 24 | While both `consumer` and `credential` can be `nil`, 25 | at least one of them must exist. Otherwise, this function will throw an 26 | error. 27 | 28 | Phases: 29 | access 30 | 31 | Example: 32 | # assuming `credential` and `consumer` have been set by some authentication code 33 | 34 | kong.client.authenticate(consumer, credentials) 35 | 36 | :parameter consumer: The consumer to set. If no 37 | value is provided, then any existing value will be cleared. 38 | :type consumer: table 39 | :parameter credential: The credential to set. If 40 | no value is provided, then any existing value will be cleared. 41 | :type credential: table 42 | 43 | """ 44 | pass 45 | 46 | @staticmethod 47 | def authenticate_consumer_group_by_consumer_id(consumer_id: str) -> None: 48 | """ 49 | 50 | If the consumer_id is neither a string nor nil, it throws an error. 51 | If the consumer group has already been authenticated, it doesn't override the group. 52 | The function performs a redis-SCAN-like lookup using a subset of the cache_key. 53 | The consumer_group_mapping is sorted by group name for deterministic behavior, 54 | but this might be changed in future releases. 55 | 56 | Phases: 57 | access 58 | 59 | Example: 60 | # assuming `consumer_id` is provided by some code 61 | 62 | kong.client.authenticate_consumer_group_by_consumer_id(consumer_id) 63 | 64 | :parameter consumer_id: The consumer id to use for setting the consumer group. 65 | If no value is provided, the current consumer group is not changed. 66 | :type consumer_id: str 67 | 68 | """ 69 | pass 70 | 71 | @staticmethod 72 | def get_consumer() -> table: 73 | """ 74 | 75 | Returns the `consumer` entity of the currently authenticated consumer. 76 | If not set yet, it returns `nil`. 77 | 78 | Phases: 79 | access, header_filter, response, body_filter, log 80 | 81 | Example: 82 | consumer = kong.client.get_consumer() 83 | 84 | if consumer: 85 | 86 | consumer_id = consumer.id 87 | 88 | else: 89 | 90 | # request not authenticated yet, or a credential 91 | 92 | # without a consumer (external auth) 93 | 94 | :return: The authenticated consumer entity. 95 | 96 | :rtype: table 97 | """ 98 | pass 99 | 100 | @staticmethod 101 | def get_consumer_group() -> table: 102 | """ 103 | 104 | This function is deprecated in favor of `get_consumer_groups`. 105 | Retrieves the authenticated consumer group for the current request. 106 | 107 | Phases: 108 | auth_and_later 109 | 110 | Example: 111 | group = kong.client.get_consumer_group() 112 | 113 | :return: The authenticated consumer group. Returns `nil` if no 114 | consumer group has been authenticated for the current request. 115 | 116 | :rtype: table 117 | """ 118 | pass 119 | 120 | @staticmethod 121 | def get_consumer_groups() -> table: 122 | """ 123 | 124 | Retrieves the authenticated consumer groups for the current request. 125 | 126 | Phases: 127 | auth_and_later 128 | 129 | Example: 130 | groups = kong.client.get_consumer_groups() 131 | 132 | :return: The authenticated consumer groups. Returns `nil` if no 133 | consumer groups has been authenticated for the current request. 134 | 135 | :rtype: table 136 | """ 137 | pass 138 | 139 | @staticmethod 140 | def get_credential() -> str: 141 | """ 142 | 143 | Returns the credentials of the currently authenticated consumer. 144 | If not set yet, it returns `nil`. 145 | 146 | Phases: 147 | access, header_filter, response, body_filter, log 148 | 149 | Example: 150 | credential = kong.client.get_credential() 151 | 152 | if credential: 153 | 154 | consumer_id = credential.consumer_id 155 | 156 | else: 157 | 158 | # request not authenticated yet 159 | 160 | :return: The authenticated credential. 161 | 162 | :rtype: str 163 | """ 164 | pass 165 | 166 | @staticmethod 167 | def get_forwarded_ip() -> str: 168 | """ 169 | 170 | Returns the remote address of the client making the request. Unlike 171 | `kong.client.get_ip`, this function will consider forwarded addresses in 172 | cases when a load balancer is in front of Kong. Whether this function 173 | returns a forwarded address or not depends on several Kong configuration 174 | parameters: 175 | * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips) 176 | * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header) 177 | * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive) 178 | 179 | Phases: 180 | certificate, rewrite, access, header_filter, response, body_filter, log 181 | 182 | Example: 183 | # Given a client with IP 127.0.0.1 making connection through 184 | 185 | # a load balancer with IP 10.0.0.1 to Kong answering the request for 186 | 187 | # https://username:password@example.com:1234/v1/movies 188 | 189 | kong.client.get_forwarded_ip() # "127.0.0.1" 190 | 191 | # Note: This example assumes that 10.0.0.1 is one of the trusted IPs, and that 192 | 193 | # the load balancer adds the right headers matching with the configuration 194 | 195 | # of `real_ip_header`, e.g. `proxy_protocol`. 196 | 197 | :return: The remote IP address of the client making the request, 198 | considering forwarded addresses. 199 | 200 | :rtype: str 201 | """ 202 | pass 203 | 204 | @staticmethod 205 | def get_forwarded_port() -> number: 206 | """ 207 | 208 | Returns the remote port of the client making the request. Unlike 209 | `kong.client.get_port`, this function will consider forwarded ports in cases 210 | when a load balancer is in front of Kong. Whether this function returns a 211 | forwarded port or not depends on several Kong configuration parameters: 212 | * [trusted\_ips](https://docs.konghq.com/gateway/latest/reference/configuration/#trusted_ips) 213 | * [real\_ip\_header](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_header) 214 | * [real\_ip\_recursive](https://docs.konghq.com/gateway/latest/reference/configuration/#real_ip_recursive) 215 | 216 | Phases: 217 | certificate, rewrite, access, header_filter, response, body_filter, log 218 | 219 | Example: 220 | # [client]:40000 <-> 80:[balancer]:30000 <-> 80:[kong]:20000 <-> 80:[service] 221 | 222 | kong.client.get_forwarded_port() # 40000 223 | 224 | # Note: This example assumes that [balancer] is one of the trusted IPs, and that 225 | 226 | # the load balancer adds the right headers matching with the configuration 227 | 228 | # of `real_ip_header`, e.g. `proxy_protocol`. 229 | 230 | :return: The remote client port, considering forwarded ports. 231 | 232 | :rtype: number 233 | """ 234 | pass 235 | 236 | @staticmethod 237 | def get_ip() -> str: 238 | """ 239 | 240 | Returns the remote address of the client making the request. This module 241 | **always** returns the address of the client directly connecting to Kong. 242 | That is, in cases when a load balancer is in front of Kong, this function 243 | returns the load balancer's address, and **not** that of the 244 | downstream client. 245 | 246 | Phases: 247 | certificate, rewrite, access, header_filter, response, body_filter, log 248 | 249 | Example: 250 | # Given a client with IP 127.0.0.1 making connection through 251 | 252 | # a load balancer with IP 10.0.0.1 to Kong answering the request for 253 | 254 | # https://example.com:1234/v1/movies 255 | 256 | kong.client.get_ip() # "10.0.0.1" 257 | 258 | :return: The remote IP address of the client making the request. 259 | 260 | :rtype: str 261 | """ 262 | pass 263 | 264 | @staticmethod 265 | def get_port() -> number: 266 | """ 267 | 268 | Returns the remote port of the client making the request. This 269 | **always** returns the port of the client directly connecting to Kong. That 270 | is, in cases when a load balancer is in front of Kong, this function 271 | returns the load balancer's port, and **not** that of the downstream client. 272 | 273 | Phases: 274 | certificate, rewrite, access, header_filter, response, body_filter, log 275 | 276 | Example: 277 | # [client]:40000 <-> 80:[balancer]:30000 <-> 80:[kong]:20000 <-> 80:[service] 278 | 279 | kong.client.get_port() # 30000 280 | 281 | :return: The remote client port. 282 | 283 | :rtype: number 284 | """ 285 | pass 286 | 287 | @staticmethod 288 | def get_protocol(allow_terminated: Optional[bool]) -> Tuple[str, err]: 289 | """ 290 | 291 | Returns the protocol matched by the current route (`"http"`, `"https"`, `"tcp"` or 292 | `"tls"`), or `nil`, if no route has been matched, which can happen when dealing with 293 | erroneous requests. 294 | 295 | Phases: 296 | access, header_filter, response, body_filter, log 297 | 298 | Example: 299 | kong.client.get_protocol() # "http" 300 | 301 | :parameter allow_terminated: If set, the `X-Forwarded-Proto` header is checked when checking for HTTPS. 302 | :type allow_terminated: bool 303 | 304 | :return: Can be one of `"http"`, `"https"`, `"tcp"`, `"tls"` or `nil`. 305 | 306 | :rtype: str 307 | :return: `nil` if successful, or an error message if it fails. 308 | 309 | :rtype: err 310 | """ 311 | pass 312 | 313 | @staticmethod 314 | def load_consumer(consumer_id: str, search_by_username: Optional[bool]) -> Tuple[table, err]: 315 | """ 316 | 317 | Returns the consumer from the datastore. 318 | Looks up the consumer by ID, and can optionally do a second search by name. 319 | 320 | Phases: 321 | access, header_filter, response, body_filter, log 322 | 323 | Example: 324 | consumer_id = "john_doe" 325 | 326 | consumer = kong.client.load_consumer(consumer_id, true) 327 | 328 | :parameter consumer_id: The consumer ID to look up. 329 | :type consumer_id: str 330 | :parameter search_by_username: If truthy, 331 | and if the consumer is not found by ID, 332 | then a second search by username will be performed. 333 | :type search_by_username: bool 334 | 335 | :return: Consumer entity or `nil`. 336 | 337 | :rtype: table 338 | :return: `nil` if successful, or an error message if it fails. 339 | 340 | :rtype: err 341 | """ 342 | pass 343 | 344 | @staticmethod 345 | def set_authenticated_consumer_group(group: table) -> None: 346 | """ 347 | 348 | This function is deprecated in favor of `set_authenticated_consumer_groups`. 349 | Explicitly sets the authenticated consumer group for the current request. 350 | Throws an error if the `group` is neither a table nor `nil`. 351 | 352 | Phases: 353 | auth_and_later 354 | 355 | Example: 356 | # assuming `group` is provided by some code 357 | 358 | kong.client.set_authenticated_consumer_group(group) 359 | 360 | :parameter group: The consumer group to set. If no 361 | value is provided, then any existing value will be cleared. 362 | this value should be a table with metadata of the group like its `id` and `name`. 363 | :type group: table 364 | 365 | """ 366 | pass 367 | 368 | @staticmethod 369 | def set_authenticated_consumer_groups(groups: table) -> None: 370 | """ 371 | 372 | Explicitly sets the authenticated consumer groups for the current request. 373 | Throws an error if the `groups` parameter is neither a table nor `nil`. 374 | 375 | Phases: 376 | auth_and_later 377 | 378 | Example: 379 | kong.client.set_authenticated_consumer_groups({ 380 | 381 | { 382 | 383 | id = "fed2bf38-10c4-404e-8d45-a2b0f521464d", 384 | 385 | name = "my-group", 386 | 387 | }, 388 | 389 | { 390 | 391 | id = "736bb9d9-98f2-46d5-97fc-d7361d9488ee", 392 | 393 | name = "my-other-group", 394 | 395 | } 396 | 397 | }) 398 | 399 | :parameter groups: The consumer groups to set. If no 400 | value is provided, then any existing value will be cleared. 401 | This value should be a sequence-like table of tables, with each item 402 | having at least an `id` and a `name`. 403 | :type groups: table 404 | 405 | """ 406 | pass 407 | 408 | pass 409 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/client/tls.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/client/tls.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class tls(): 14 | 15 | 16 | @staticmethod 17 | def disable_session_reuse() -> Tuple[bool, err]: 18 | """ 19 | 20 | Prevents the TLS session for the current connection from being reused 21 | by disabling the session ticket and session ID for the current TLS connection. 22 | 23 | Phases: 24 | certificate 25 | 26 | Example: 27 | res, err = kong.client.tls.disable_session_reuse() 28 | 29 | if not res: 30 | 31 | # do something with err 32 | 33 | :return: Returns `true` if successful, `nil` if it fails. 34 | 35 | :rtype: bool 36 | :return: Returns `nil` if successful, or an error message if it fails. 37 | 38 | :rtype: err 39 | """ 40 | pass 41 | 42 | @staticmethod 43 | def get_full_client_certificate_chain() -> Tuple[str, err]: 44 | """ 45 | 46 | Returns the PEM encoded downstream client certificate chain with the 47 | client certificate at the top and intermediate certificates 48 | (if any) at the bottom. 49 | 50 | Phases: 51 | rewrite, access, balancer, header_filter, body_filter, log 52 | 53 | Example: 54 | cert, err = kong.client.tls.get_full_client_certificate_chain() 55 | 56 | if err: 57 | 58 | # do something with errif not cert: 59 | 60 | # client did not complete mTLS# do something with cert 61 | 62 | :return: Returns a PEM-encoded client certificate if the mTLS 63 | handshake was completed, or `nil` if an error occurred or the client did 64 | not present its certificate. 65 | 66 | :rtype: str 67 | :return: Returns `nil` if successful, or an error message if it fails. 68 | 69 | :rtype: err 70 | """ 71 | pass 72 | 73 | @staticmethod 74 | def request_client_certificate(ca_certs: Optional[cdata]) -> Tuple[bool, err]: 75 | """ 76 | 77 | Requests the client to present its client-side certificate to initiate mutual 78 | TLS authentication between server and client. 79 | This function *requests*, but does not *require* the client to start 80 | the mTLS process. The TLS handshake can still complete even if the client 81 | doesn't present a client certificate. However, in that case, it becomes a 82 | TLS connection instead of an mTLS connection, as there is no mutual 83 | authentication. 84 | To find out whether the client honored the request, use 85 | `get_full_client_certificate_chain` in later phases. 86 | The `ca_certs` argument is the optional CA certificate chain opaque pointer, 87 | which can be created by the [parse_pem_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) 88 | or [resty.opensslx509.chain](https://github.com/fffonion/lua-resty-openssl#restyopensslx509chain) 89 | The Distinguished Name (DN) list hints of the CA certificates will be sent to clients. 90 | If omitted, will not send any DN list to clients. 91 | 92 | Phases: 93 | certificate 94 | 95 | Example: 96 | x509_lib = require "resty.openssl.x509" 97 | 98 | chain_lib = require "resty.openssl.x509.chain" 99 | 100 | res, err 101 | 102 | chain = chain_lib.new() 103 | 104 | # err check 105 | 106 | x509, err = x509_lib.new(pem_cert, "PEM") 107 | 108 | # err check 109 | 110 | res, err = chain:add(x509) 111 | 112 | # err check 113 | 114 | # `chain.ctx` is the raw data of the chain, i.e. `STACK_OF(X509) *` 115 | 116 | res, err = kong.client.tls.request_client_certificate(chain.ctx) 117 | 118 | if not res: 119 | 120 | # do something with err 121 | 122 | :parameter ca_certs: The CA certificate chain opaque pointer 123 | :type ca_certs: cdata 124 | 125 | :return: Returns `true` if successful, or `nil` if it fails. 126 | 127 | :rtype: bool 128 | :return: Returns `nil` if successful, or an error message if it fails. 129 | 130 | :rtype: err 131 | """ 132 | pass 133 | 134 | @staticmethod 135 | def set_client_verify() -> None: 136 | """ 137 | 138 | Overrides the client's verification result generated by the log serializer. 139 | By default, the `request.tls.client_verify` field inside the log 140 | generated by Kong's log serializer is the same as the 141 | [$ssl_client_verify](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#var_ssl_client_verify) 142 | Nginx variable. 143 | Only `"SUCCESS"`, `"NONE"`, or `"FAILED:"` are accepted values. 144 | This function does not return anything on success, and throws a Lua error 145 | in case of a failure. 146 | 147 | Phases: 148 | rewrite, access, balancer 149 | 150 | Example: 151 | kong.client.tls.set_client_verify("FAILED:unknown CA") 152 | 153 | """ 154 | pass 155 | 156 | pass 157 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/cluster.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/cluster.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class cluster(): 14 | 15 | 16 | @staticmethod 17 | def get_id() -> Tuple[str, str]: 18 | """ 19 | 20 | Returns the unique ID for this Kong cluster. If Kong 21 | is running in DB-less mode without a cluster ID explicitly defined, 22 | then this method returns `nil`. 23 | For hybrid mode, all control planes and data planes belonging to the same 24 | cluster return the same cluster ID. For traditional database-based 25 | deployments, all Kong nodes pointing to the same database also return 26 | the same cluster ID. 27 | 28 | Example: 29 | id, err = kong.cluster.get_id() 30 | 31 | if err: 32 | 33 | # handle errorif not id: 34 | 35 | # no cluster ID is available# use id here 36 | 37 | :return: The v4 UUID used by this cluster as its ID. 38 | 39 | :rtype: str 40 | :return: An error message. 41 | 42 | :rtype: str 43 | """ 44 | pass 45 | 46 | pass 47 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/ctx/__init__.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/ctx.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | from .shared import shared as cls_shared 13 | 14 | class ctx(): 15 | 16 | shared = cls_shared 17 | 18 | pass 19 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/ctx/shared.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/ctx/shared.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class shared(): 14 | 15 | 16 | @staticmethod 17 | def get(k: str) -> Any: 18 | """ 19 | 20 | get a key-value pair from Kong's shared memory 21 | 22 | :parameter k: key for the ctx data 23 | :type k: str 24 | 25 | :return: the per-request context data in ngx.ctx 26 | 27 | :rtype: Any 28 | """ 29 | pass 30 | 31 | @staticmethod 32 | def set(k: str, v: str) -> None: 33 | """ 34 | 35 | set a key-value pair in Kong's shared memory 36 | 37 | :parameter k: key for the ctx data 38 | :type k: str 39 | :parameter v: value for the ctx data 40 | :type v: str 41 | 42 | """ 43 | pass 44 | 45 | pass 46 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/enterprise_edition/__init__.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/enterprise_edition.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | from .jwe import jwe as cls_jwe 13 | 14 | class enterprise_edition(): 15 | 16 | jwe = cls_jwe 17 | 18 | pass 19 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/enterprise_edition/jwe.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/enterprise_edition/jwe.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class jwe(): 14 | 15 | 16 | @staticmethod 17 | def decode(token: str) -> Tuple[str, str]: 18 | """ 19 | 20 | This function will return a table that looks like this: 21 | ``` 22 | { 23 | [1] = protected header (as it appears in token) 24 | [2] = encrypted key (as it appears in token) 25 | [3] = initialization vector (as it appears in token) 26 | [4] = ciphertext (as it appears in token) 27 | [5] = authentication tag (as it appears in token) 28 | protected = protected key (base64url decoded and json decoded) 29 | encrypted_key = encrypted key (base64url decoded) 30 | iv = initialization vector (base64url decoded) 31 | ciphertext = ciphertext (base64url decoded) 32 | tag = authentication tag (base64url decoded) 33 | aad = protected header (as it appears in token) 34 | } 35 | ``` 36 | The original input can be reconstructed with: 37 | ``` 38 | local token = table.concat(, ".") 39 | ``` 40 | If there is not exactly 5 parts in JWT token, or any decoding fails, 41 | the error is returned. 42 | @usage 43 | local jwe = require "kong.enterprise_edition.jwe" 44 | local jwt, err = jwe.decode( 45 | "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImFwdSI6Ik1lUFhUS2oyWFR1NUktYldUSFI2bXci" .. 46 | "LCJhcHYiOiJmUHFoa2hfNkdjVFd1SG5YWFZBclVnIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYi" .. 47 | "LCJ4IjoiWWd3eF9NVXRLTW9NYUpNZXFhSjZjUFV1Z29oYkVVc0I1NndrRlpYRjVMNCIsInkiOiIxaEYzYzlR" .. 48 | "VEhELVozam1vYUp2THZwTGJqcVNaSW9KNmd4X2YtUzAtZ21RIn19..4ZrIopIhLi3LeXyE.-Ke4ofA.MI5lT" .. 49 | "kML5NIa-Twm-92F6Q") 50 | if jwt then 51 | print(jwt.protected.alg) -- outputs "ECDH-ES" 52 | end 53 | 54 | :parameter token: JWE encrypted JWT token 55 | :type token: str 56 | 57 | :return: A table containing JWT token parts decoded, or nil 58 | 59 | :rtype: str 60 | :return: Error message, or nil 61 | 62 | :rtype: str 63 | """ 64 | pass 65 | 66 | @staticmethod 67 | def decrypt(key: Any, token: str) -> Tuple[str, str]: 68 | """ 69 | 70 | Supported keys (`key` argument): 71 | * Supported key formats: 72 | * `JWK` (given as a `string` or `table`) 73 | * `PEM` (given as a `string`) 74 | * `DER` (given as a `string`) 75 | * Supported key types: 76 | * `RSA` 77 | * `EC`, supported curves: 78 | * `P-256` 79 | * `P-384` 80 | * `P-521` 81 | @usage 82 | local jwe = require "kong.enterprise_edition.jwe" 83 | local jwk = { 84 | kty = "EC", 85 | crv = "P-256", 86 | use = "enc", 87 | x = "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", 88 | y = "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", 89 | d = "870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE", 90 | } 91 | local plaintext, err = jwe.decrypt(jwk, 92 | "eyJhbGciOiJFQ0RILUVTIiwiZW5jIjoiQTI1NkdDTSIsImFwdSI6Ik1lUFhUS2oyWFR1NUktYldUSFI2bXci" .. 93 | "LCJhcHYiOiJmUHFoa2hfNkdjVFd1SG5YWFZBclVnIiwiZXBrIjp7Imt0eSI6IkVDIiwiY3J2IjoiUC0yNTYi" .. 94 | "LCJ4IjoiWWd3eF9NVXRLTW9NYUpNZXFhSjZjUFV1Z29oYkVVc0I1NndrRlpYRjVMNCIsInkiOiIxaEYzYzlR" .. 95 | "VEhELVozam1vYUp2THZwTGJqcVNaSW9KNmd4X2YtUzAtZ21RIn19..4ZrIopIhLi3LeXyE.-Ke4ofA.MI5lT" .. 96 | "kML5NIa-Twm-92F6Q") 97 | if plaintext then 98 | print(plaintext) -- outputs "hello" 99 | end 100 | 101 | :parameter key: Private key 102 | :type key: Any 103 | :parameter token: JWE encrypted JWT token 104 | :type token: str 105 | 106 | :return: JWT token payload in plaintext, or nil 107 | 108 | :rtype: str 109 | :return: Error message, or nil 110 | 111 | :rtype: str 112 | """ 113 | pass 114 | 115 | @staticmethod 116 | def encrypt(alg: str, enc: str, key: Any, plaintext: str, options: Optional[table]) -> Tuple[str, str]: 117 | """ 118 | 119 | Supported algorithms (`alg` argument): 120 | * `"RSA-OAEP"` 121 | * `"ECDH-ES"` 122 | Supported encryption algorithms (`enc` argument): 123 | * `"A256GCM"` 124 | Supported keys (`key` argument): 125 | * Supported key formats: 126 | * `JWK` (given as a `string` or `table`) 127 | * `PEM` (given as a `string`) 128 | * `DER` (given as a `string`) 129 | * Supported key types: 130 | * `RSA` 131 | * `EC`, supported curves: 132 | * `P-256` 133 | * `P-384` 134 | * `P-521` 135 | Supported options (`options` argument): 136 | * `{ zip = "DEF" }`: whether to deflate the plaintext before encrypting 137 | * `{ apu = }`: Agreement PartyUInfo header parameter 138 | * `{ apv = }`: Agreement PartyVInfo header parameter 139 | The `apu` and `apv` can also be set to `false` to prevent them from 140 | being auto-generated (sixteen random bytes) and added to ephemeral 141 | public key. 142 | @usage 143 | local jwe = require "kong.enterprise_edition.jwe" 144 | local jwk = { 145 | kty = "EC", 146 | crv = "P-256", 147 | use = "enc", 148 | x = "MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", 149 | y = "4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", 150 | } 151 | local token, err = jwe.encrypt("ECDH-ES", "A256GCM", jwk, "hello", { 152 | zip = "DEF, 153 | }) 154 | if token then 155 | print(token) 156 | end 157 | 158 | :parameter alg: Algorithm used for key management 159 | :type alg: str 160 | :parameter enc: Encryption algorithm used for content encryption 161 | :type enc: str 162 | :parameter key: Public key 163 | :type key: Any 164 | :parameter plaintext: Plaintext 165 | :type plaintext: str 166 | :parameter options: Options (optional), default: nil 167 | :type options: table 168 | 169 | :return: JWE encrypted JWT token, or nil 170 | 171 | :rtype: str 172 | :return: Error message, or nil 173 | 174 | :rtype: str 175 | """ 176 | pass 177 | 178 | pass 179 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/ip.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/ip.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class ip(): 14 | 15 | 16 | @staticmethod 17 | def is_trusted(address: str) -> bool: 18 | """ 19 | 20 | Depending on the `trusted_ips` configuration property, 21 | this function returns whether a given IP is trusted or not. 22 | Both ipv4 and ipv6 are supported. 23 | 24 | Phases: 25 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 26 | 27 | Example: 28 | if kong.ip.is_trusted("1.1.1.1"): 29 | 30 | kong.log("The IP is trusted") 31 | 32 | :parameter address: A string representing an IP address. 33 | :type address: str 34 | 35 | :return: `true` if the IP is trusted, `false` otherwise. 36 | 37 | :rtype: bool 38 | """ 39 | pass 40 | 41 | pass 42 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/log.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/log.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class log(): 14 | 15 | 16 | @staticmethod 17 | def alert(*args: Any) -> None: 18 | """ 19 | 20 | Similar to `kong.log()`, but the produced log has the severity given by 21 | ``, instead of `notice`. The supported levels are: 22 | * `kong.log.alert()` 23 | * `kong.log.crit()` 24 | * `kong.log.err()` 25 | * `kong.log.warn()` 26 | * `kong.log.notice()` 27 | * `kong.log.info()` 28 | * `kong.log.debug()` 29 | Logs have the same format as that of `kong.log()`. For 30 | example, the following call: 31 | ``` lua 32 | kong.log.err("hello ", "world") 33 | ``` 34 | would, within the core, produce a log line similar to: 35 | ``` plain 36 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 37 | ``` 38 | If invoked from within a plugin (for example, `key-auth`) it would include the 39 | namespace prefix: 40 | ``` plain 41 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 42 | ``` 43 | 44 | Phases: 45 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 46 | 47 | Example: 48 | kong.log.warn("something require attention") 49 | 50 | kong.log.err("something failed: ", err) 51 | 52 | kong.log.alert("something requires immediate action") 53 | 54 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 55 | :type *args: Any 56 | 57 | :return: Throws an error on invalid inputs. 58 | 59 | :rtype: None 60 | """ 61 | pass 62 | 63 | @staticmethod 64 | def crit(*args: Any) -> None: 65 | """ 66 | 67 | Similar to `kong.log()`, but the produced log has the severity given by 68 | ``, instead of `notice`. The supported levels are: 69 | * `kong.log.alert()` 70 | * `kong.log.crit()` 71 | * `kong.log.err()` 72 | * `kong.log.warn()` 73 | * `kong.log.notice()` 74 | * `kong.log.info()` 75 | * `kong.log.debug()` 76 | Logs have the same format as that of `kong.log()`. For 77 | example, the following call: 78 | ``` lua 79 | kong.log.err("hello ", "world") 80 | ``` 81 | would, within the core, produce a log line similar to: 82 | ``` plain 83 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 84 | ``` 85 | If invoked from within a plugin (for example, `key-auth`) it would include the 86 | namespace prefix: 87 | ``` plain 88 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 89 | ``` 90 | 91 | Phases: 92 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 93 | 94 | Example: 95 | kong.log.warn("something require attention") 96 | 97 | kong.log.err("something failed: ", err) 98 | 99 | kong.log.alert("something requires immediate action") 100 | 101 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 102 | :type *args: Any 103 | 104 | :return: Throws an error on invalid inputs. 105 | 106 | :rtype: None 107 | """ 108 | pass 109 | 110 | @staticmethod 111 | def debug(*args: Any) -> None: 112 | """ 113 | 114 | Similar to `kong.log()`, but the produced log has the severity given by 115 | ``, instead of `notice`. The supported levels are: 116 | * `kong.log.alert()` 117 | * `kong.log.crit()` 118 | * `kong.log.err()` 119 | * `kong.log.warn()` 120 | * `kong.log.notice()` 121 | * `kong.log.info()` 122 | * `kong.log.debug()` 123 | Logs have the same format as that of `kong.log()`. For 124 | example, the following call: 125 | ``` lua 126 | kong.log.err("hello ", "world") 127 | ``` 128 | would, within the core, produce a log line similar to: 129 | ``` plain 130 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 131 | ``` 132 | If invoked from within a plugin (for example, `key-auth`) it would include the 133 | namespace prefix: 134 | ``` plain 135 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 136 | ``` 137 | 138 | Phases: 139 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 140 | 141 | Example: 142 | kong.log.warn("something require attention") 143 | 144 | kong.log.err("something failed: ", err) 145 | 146 | kong.log.alert("something requires immediate action") 147 | 148 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 149 | :type *args: Any 150 | 151 | :return: Throws an error on invalid inputs. 152 | 153 | :rtype: None 154 | """ 155 | pass 156 | 157 | @staticmethod 158 | def deprecation(*args: Any) -> None: 159 | """ 160 | 161 | Arguments given to this function can be of any type, but table arguments 162 | are converted to strings via `tostring` (thus potentially calling a 163 | table's `__tostring` metamethod if set). When the last argument is a table, 164 | it is considered as a deprecation metadata. The table can include the 165 | following properties: 166 | ``` lua 167 | { 168 | after = "2.5.0", -- deprecated after Kong version 2.5.0 (defaults to `nil`) 169 | removal = "3.0.0", -- about to be removed with Kong version 3.0.0 (defaults to `nil`) 170 | trace = true, -- writes stack trace along with the deprecation message (defaults to `nil`) 171 | } 172 | ``` 173 | For example, the following call: 174 | ``` lua 175 | kong.log.deprecation("hello ", "world") 176 | ``` 177 | would, within the core, produce a log line similar to: 178 | ``` plain 179 | 2017/07/09 19:36:25 [warn] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 180 | ``` 181 | If invoked from within a plugin (for example, `key-auth`) it would include the 182 | namespace prefix: 183 | ``` plain 184 | 2017/07/09 19:36:25 [warn] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 185 | ``` 186 | And with metatable, the following call: 187 | ``` lua 188 | kong.log.deprecation("hello ", "world", { after = "2.5.0", removal = "3.0.0" }) 189 | ``` 190 | would, within the core, produce a log line similar to: 191 | ``` plain 192 | 2017/07/09 19:36:25 [warn] 25932#0: *1 [kong] some_file.lua:54 hello world (deprecated after 2.5.0, scheduled for removal in 3.0.0), client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 193 | ``` 194 | 195 | Phases: 196 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 197 | 198 | Example: 199 | kong.log.deprecation("hello ", "world") 200 | 201 | kong.log.deprecation("hello ", "world", { after = "2.5.0" }) 202 | 203 | kong.log.deprecation("hello ", "world", { removal = "3.0.0" }) 204 | 205 | kong.log.deprecation("hello ", "world", { after = "2.5.0", removal = "3.0.0" }) 206 | 207 | kong.log.deprecation("hello ", "world", { trace = true }) 208 | 209 | :parameter *args: all params will be concatenated and stringified before being sent to the log 210 | (if the last param is a table, it is considered as a deprecation metadata) 211 | :type *args: Any 212 | 213 | :return: throws an error on invalid inputs. 214 | 215 | :rtype: None 216 | """ 217 | pass 218 | 219 | @staticmethod 220 | def err(*args: Any) -> None: 221 | """ 222 | 223 | Similar to `kong.log()`, but the produced log has the severity given by 224 | ``, instead of `notice`. The supported levels are: 225 | * `kong.log.alert()` 226 | * `kong.log.crit()` 227 | * `kong.log.err()` 228 | * `kong.log.warn()` 229 | * `kong.log.notice()` 230 | * `kong.log.info()` 231 | * `kong.log.debug()` 232 | Logs have the same format as that of `kong.log()`. For 233 | example, the following call: 234 | ``` lua 235 | kong.log.err("hello ", "world") 236 | ``` 237 | would, within the core, produce a log line similar to: 238 | ``` plain 239 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 240 | ``` 241 | If invoked from within a plugin (for example, `key-auth`) it would include the 242 | namespace prefix: 243 | ``` plain 244 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 245 | ``` 246 | 247 | Phases: 248 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 249 | 250 | Example: 251 | kong.log.warn("something require attention") 252 | 253 | kong.log.err("something failed: ", err) 254 | 255 | kong.log.alert("something requires immediate action") 256 | 257 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 258 | :type *args: Any 259 | 260 | :return: Throws an error on invalid inputs. 261 | 262 | :rtype: None 263 | """ 264 | pass 265 | 266 | @staticmethod 267 | def info(*args: Any) -> None: 268 | """ 269 | 270 | Similar to `kong.log()`, but the produced log has the severity given by 271 | ``, instead of `notice`. The supported levels are: 272 | * `kong.log.alert()` 273 | * `kong.log.crit()` 274 | * `kong.log.err()` 275 | * `kong.log.warn()` 276 | * `kong.log.notice()` 277 | * `kong.log.info()` 278 | * `kong.log.debug()` 279 | Logs have the same format as that of `kong.log()`. For 280 | example, the following call: 281 | ``` lua 282 | kong.log.err("hello ", "world") 283 | ``` 284 | would, within the core, produce a log line similar to: 285 | ``` plain 286 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 287 | ``` 288 | If invoked from within a plugin (for example, `key-auth`) it would include the 289 | namespace prefix: 290 | ``` plain 291 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 292 | ``` 293 | 294 | Phases: 295 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 296 | 297 | Example: 298 | kong.log.warn("something require attention") 299 | 300 | kong.log.err("something failed: ", err) 301 | 302 | kong.log.alert("something requires immediate action") 303 | 304 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 305 | :type *args: Any 306 | 307 | :return: Throws an error on invalid inputs. 308 | 309 | :rtype: None 310 | """ 311 | pass 312 | 313 | @staticmethod 314 | def notice(*args: Any) -> None: 315 | """ 316 | 317 | Similar to `kong.log()`, but the produced log has the severity given by 318 | ``, instead of `notice`. The supported levels are: 319 | * `kong.log.alert()` 320 | * `kong.log.crit()` 321 | * `kong.log.err()` 322 | * `kong.log.warn()` 323 | * `kong.log.notice()` 324 | * `kong.log.info()` 325 | * `kong.log.debug()` 326 | Logs have the same format as that of `kong.log()`. For 327 | example, the following call: 328 | ``` lua 329 | kong.log.err("hello ", "world") 330 | ``` 331 | would, within the core, produce a log line similar to: 332 | ``` plain 333 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 334 | ``` 335 | If invoked from within a plugin (for example, `key-auth`) it would include the 336 | namespace prefix: 337 | ``` plain 338 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 339 | ``` 340 | 341 | Phases: 342 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 343 | 344 | Example: 345 | kong.log.warn("something require attention") 346 | 347 | kong.log.err("something failed: ", err) 348 | 349 | kong.log.alert("something requires immediate action") 350 | 351 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 352 | :type *args: Any 353 | 354 | :return: Throws an error on invalid inputs. 355 | 356 | :rtype: None 357 | """ 358 | pass 359 | 360 | @staticmethod 361 | def serialize() -> None: 362 | """ 363 | 364 | """ 365 | pass 366 | 367 | @staticmethod 368 | def set_serialize_value(key: str, value: Any, options: table) -> table: 369 | """ 370 | 371 | Sets a value to be used on the `serialize` custom table. 372 | Logging plugins use the output of `kong.log.serialize()` as a base for their logs. 373 | This function lets you customize the log output. 374 | It can be used to replace existing values in the output, or to delete 375 | existing values by passing `nil`. 376 | **Note:** The type-checking of the `value` parameter can take some time, so 377 | it is deferred to the `serialize()` call, which happens in the log 378 | phase in most real-usage cases. 379 | 380 | Phases: 381 | certificate, rewrite, access, header_filter, response, body_filter, log 382 | 383 | Example: 384 | # Adds a new value to the serialized table 385 | 386 | kong.log.set_serialize_value("my_new_value", 1) 387 | 388 | assert(kong.log.serialize().my_new_value == 1) 389 | 390 | # Value can be a table 391 | 392 | kong.log.set_serialize_value("my", { new = { value = 2 } }) 393 | 394 | assert(kong.log.serialize().my.new.value == 2) 395 | 396 | # It is possible to change an existing serialized value 397 | 398 | kong.log.set_serialize_value("my_new_value", 3) 399 | 400 | assert(kong.log.serialize().my_new_value == 3) 401 | 402 | # Unset an existing value by setting it to nil 403 | 404 | kong.log.set_serialize_value("my_new_value", nil) 405 | 406 | assert(kong.log.serialize().my_new_value == nil) 407 | 408 | # Dots in the key are interpreted as table accesses 409 | 410 | kong.log.set_serialize_value("my.new.value", 4) 411 | 412 | assert(kong.log.serialize().my.new_value == 4) 413 | 414 | :parameter key: The name of the field. 415 | :type key: str 416 | :parameter value: Value to be set. When a table is used, its keys must be numbers, strings, or booleans, and its values can be numbers, strings, or other tables like itself, recursively. 417 | :type value: Any 418 | :parameter options: Can contain two entries: options.mode can be `set` (the default, always sets), `add` (only add if entry does not already exist) and `replace` (only change value if it already exists). 419 | :type options: table 420 | 421 | :return: The request information table. 422 | 423 | :rtype: table 424 | """ 425 | pass 426 | 427 | @staticmethod 428 | def warn(*args: Any) -> None: 429 | """ 430 | 431 | Similar to `kong.log()`, but the produced log has the severity given by 432 | ``, instead of `notice`. The supported levels are: 433 | * `kong.log.alert()` 434 | * `kong.log.crit()` 435 | * `kong.log.err()` 436 | * `kong.log.warn()` 437 | * `kong.log.notice()` 438 | * `kong.log.info()` 439 | * `kong.log.debug()` 440 | Logs have the same format as that of `kong.log()`. For 441 | example, the following call: 442 | ``` lua 443 | kong.log.err("hello ", "world") 444 | ``` 445 | would, within the core, produce a log line similar to: 446 | ``` plain 447 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 448 | ``` 449 | If invoked from within a plugin (for example, `key-auth`) it would include the 450 | namespace prefix: 451 | ``` plain 452 | 2017/07/09 19:36:25 [error] 25932#0: *1 [kong] some_file.lua:54 [key-auth] hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" 453 | ``` 454 | 455 | Phases: 456 | init_worker, certificate, rewrite, access, header_filter, response, body_filter, log 457 | 458 | Example: 459 | kong.log.warn("something require attention") 460 | 461 | kong.log.err("something failed: ", err) 462 | 463 | kong.log.alert("something requires immediate action") 464 | 465 | :parameter *args: All params will be concatenated and stringified before being sent to the log. 466 | :type *args: Any 467 | 468 | :return: Throws an error on invalid inputs. 469 | 470 | :rtype: None 471 | """ 472 | pass 473 | 474 | pass 475 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/nginx/__init__.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/nginx.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | from .shared import shared as cls_shared 13 | 14 | class nginx(): 15 | 16 | shared = cls_shared 17 | 18 | @staticmethod 19 | def get_ctx(k: str) -> Any: 20 | """ 21 | 22 | get a key-value pair from Kong's per-request context 23 | 24 | :parameter k: key for the ctx data 25 | :type k: str 26 | 27 | :return: the per-request context data in ngx.ctx 28 | 29 | :rtype: Any 30 | """ 31 | pass 32 | 33 | @staticmethod 34 | def get_statistics() -> table: 35 | """ 36 | 37 | Returns various connection and request metrics exposed by 38 | Nginx, similar to those reported by the 39 | [ngx_http_stub_status_module](https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#data). 40 | The following fields are included in the returned table: 41 | * `connections_active` - the current number of active client connections including `connections_waiting`. 42 | * `connections_reading` - the current number of connections where nginx is reading the request header. 43 | * `connections_writing` - the current number of connections where nginx is writing the response back to the client. 44 | * `connections_waiting` - the current number of idle client connections waiting for a request. 45 | * `connections_accepted` - the total number of accepted client connections. 46 | * `connections_handled` - the total number of handled connections. Same as `connections_accepted` unless some resource limits have been reached 47 | (for example, the [`worker_connections`](https://nginx.org/en/docs/ngx_core_module.html#worker_connections) limit). 48 | * `total_requests` - the total number of client requests. 49 | 50 | Example: 51 | nginx_statistics = kong.nginx.get_statistics() 52 | 53 | :return: Nginx connections and requests statistics 54 | 55 | :rtype: table 56 | """ 57 | pass 58 | 59 | @staticmethod 60 | def get_subsystem() -> str: 61 | """ 62 | 63 | :return: the subsystem name 64 | 65 | :rtype: str 66 | """ 67 | pass 68 | 69 | @staticmethod 70 | def get_tls1_version_str() -> str: 71 | """ 72 | 73 | :return: the TLSv1 version string 74 | 75 | :rtype: str 76 | """ 77 | pass 78 | 79 | @staticmethod 80 | def get_var() -> str: 81 | """ 82 | 83 | :return: get NGINX variable value 84 | 85 | :rtype: str 86 | """ 87 | pass 88 | 89 | @staticmethod 90 | def req_start_time() -> number: 91 | """ 92 | 93 | get the current request's start timestamp 94 | 95 | :return: req_start_time 96 | 97 | :rtype: number 98 | """ 99 | pass 100 | 101 | @staticmethod 102 | def set_ctx(k: str, any: str) -> None: 103 | """ 104 | 105 | set a key-value pair in Kong's per-request context 106 | 107 | :parameter k: key for the ctx data 108 | :type k: str 109 | :parameter any: value for the ctx data 110 | :type any: str 111 | 112 | """ 113 | pass 114 | 115 | pass 116 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/nginx/shared.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/nginx/shared.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class shared(): 14 | 15 | 16 | @staticmethod 17 | def get(k: str) -> Any: 18 | """ 19 | 20 | get a key-value pair from Kong's shared memory 21 | 22 | :parameter k: key for the ctx data 23 | :type k: str 24 | 25 | :return: the per-request context data in ngx.ctx 26 | 27 | :rtype: Any 28 | """ 29 | pass 30 | 31 | @staticmethod 32 | def set(k: str, v: str) -> None: 33 | """ 34 | 35 | set a key-value pair in Kong's shared memory 36 | 37 | :parameter k: key for the ctx data 38 | :type k: str 39 | :parameter v: value for the ctx data 40 | :type v: str 41 | 42 | """ 43 | pass 44 | 45 | pass 46 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/node.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/node.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class node(): 14 | 15 | 16 | @staticmethod 17 | def get_hostname() -> str: 18 | """ 19 | 20 | Returns the name used by the local machine. 21 | 22 | Example: 23 | hostname = kong.node.get_hostname() 24 | 25 | :return: The local machine hostname. 26 | 27 | :rtype: str 28 | """ 29 | pass 30 | 31 | @staticmethod 32 | def get_id() -> str: 33 | """ 34 | 35 | Returns the ID used by this node to describe itself. 36 | 37 | Example: 38 | id = kong.node.get_id() 39 | 40 | :return: The v4 UUID used by this node as its ID. 41 | 42 | :rtype: str 43 | """ 44 | pass 45 | 46 | @staticmethod 47 | def get_memory_stats(unit: Optional[str], scale: Optional[number]) -> table: 48 | """ 49 | 50 | Returns memory usage statistics about this node. 51 | 52 | Example: 53 | res = kong.node.get_memory_stats() 54 | 55 | # res will have the following structure: 56 | 57 | { 58 | 59 | lua_shared_dicts = { 60 | 61 | kong = { 62 | 63 | allocated_slabs = 12288, 64 | 65 | capacity = 24576 66 | 67 | }, 68 | 69 | kong_db_cache = { 70 | 71 | allocated_slabs = 12288, 72 | 73 | capacity = 12288 74 | 75 | } 76 | 77 | }, 78 | 79 | workers_lua_vms = { 80 | 81 | { 82 | 83 | http_allocated_gc = 1102, 84 | 85 | pid = 18004 86 | 87 | }, 88 | 89 | { 90 | 91 | http_allocated_gc = 1102, 92 | 93 | pid = 18005 94 | 95 | } 96 | 97 | } 98 | 99 | } 100 | 101 | res = kong.node.get_memory_stats("k", 1) 102 | 103 | # res will have the following structure: 104 | 105 | { 106 | 107 | lua_shared_dicts = { 108 | 109 | kong = { 110 | 111 | allocated_slabs = "12.0 KiB", 112 | 113 | capacity = "24.0 KiB", 114 | 115 | }, 116 | 117 | kong_db_cache = { 118 | 119 | allocated_slabs = "12.0 KiB", 120 | 121 | capacity = "12.0 KiB", 122 | 123 | } 124 | 125 | }, 126 | 127 | workers_lua_vms = { 128 | 129 | { 130 | 131 | http_allocated_gc = "1.1 KiB", 132 | 133 | pid = 18004 134 | 135 | }, 136 | 137 | { 138 | 139 | http_allocated_gc = "1.1 KiB", 140 | 141 | pid = 18005 142 | 143 | } 144 | 145 | } 146 | 147 | } 148 | 149 | :parameter unit: The unit that memory is reported in. Can be 150 | any of `b/B`, `k/K`, `m/M`, or `g/G` for bytes, kibibytes, mebibytes, 151 | or gibibytes, respectively. Defaults to `b` (bytes). 152 | :type unit: str 153 | :parameter scale: The number of digits to the right of the decimal 154 | point. Defaults to 2. 155 | :type scale: number 156 | 157 | :return: A table containing memory usage statistics for this node. 158 | If `unit` is `b/B` (the default), reported values are Lua numbers. 159 | Otherwise, reported values are strings with the unit as a suffix. 160 | 161 | :rtype: table 162 | """ 163 | pass 164 | 165 | pass 166 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/plugin.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/plugin.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class plugin(): 14 | 15 | 16 | @staticmethod 17 | def get_id() -> str: 18 | """ 19 | 20 | Returns the instance ID of the plugin. 21 | 22 | Phases: 23 | rewrite, access, header_filter, response, body_filter, log 24 | 25 | Example: 26 | kong.plugin.get_id() # "123e4567-e89b-12d3-a456-426614174000" 27 | 28 | :return: The ID of the running plugin 29 | 30 | :rtype: str 31 | """ 32 | pass 33 | 34 | pass 35 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/response.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/response.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class response(): 14 | 15 | 16 | @staticmethod 17 | def add_header(name: str, of: table) -> None: 18 | """ 19 | 20 | Adds a response header with the given value. Unlike 21 | `kong.response.set_header()`, this function does not remove any existing 22 | header with the same name. Instead, another header with the same name is 23 | added to the response. If no header with this name already exists on 24 | the response, then it is added with the given value, similarly to 25 | `kong.response.set_header().` 26 | 27 | Phases: 28 | rewrite, access, header_filter, response, admin_api 29 | 30 | Example: 31 | kong.response.add_header("Cache-Control", "no-cache") 32 | 33 | kong.response.add_header("Cache-Control", "no-store") 34 | 35 | :parameter name: The header name. 36 | :type name: str 37 | :parameter of: strings|string|number|boolean value The header value. 38 | :type of: table 39 | 40 | :return: throws an error on invalid input. 41 | 42 | :rtype: None 43 | """ 44 | pass 45 | 46 | @staticmethod 47 | def clear_header(name: str) -> None: 48 | """ 49 | 50 | Removes all occurrences of the specified header in the response sent to 51 | the client. 52 | 53 | Phases: 54 | rewrite, access, header_filter, response, admin_api 55 | 56 | Example: 57 | kong.response.set_header("X-Foo", "foo") 58 | 59 | kong.response.add_header("X-Foo", "bar") 60 | 61 | kong.response.clear_header("X-Foo") 62 | 63 | # from here onwards, no X-Foo headers will exist in the response 64 | 65 | :parameter name: The name of the header to be cleared 66 | :type name: str 67 | 68 | :return: throws an error on invalid input. 69 | 70 | :rtype: None 71 | """ 72 | pass 73 | 74 | @staticmethod 75 | def error(status: number, message: Optional[str], headers: Optional[table]) -> None: 76 | """ 77 | 78 | This function interrupts the current processing and produces an error 79 | response. 80 | It is recommended to use this function in conjunction with the `return` 81 | operator, to better reflect its meaning: 82 | ```lua 83 | return kong.response.error(500, "Error", {["Content-Type"] = "text/html"}) 84 | ``` 85 | 1. The `status` argument sets the status code of the response that 86 | is seen by the client. The status code must an error code, that is, 87 | greater than 399. 88 | 2. The optional `message` argument sets the message describing 89 | the error, which is written in the body. 90 | 3. The optional `headers` argument can be a table specifying response 91 | headers to send. If specified, its behavior is similar to 92 | `kong.response.set_headers()`. 93 | This method sends the response formatted in JSON, XML, HTML or plaintext. 94 | The actual format is determined using one of the following options, in 95 | this order: 96 | - Manually specified in the `headers` argument using the `Content-Type` 97 | header. 98 | - Conforming to the `Accept` header from the request. 99 | - If there is no setting in the `Content-Type` or `Accept` header, the 100 | response defaults to JSON format. Also see the `Content-Length` 101 | header in the produced response for convenience. 102 | 103 | Phases: 104 | rewrite, access, admin_api, header_filter, only, if, body, is, nil 105 | 106 | Example: 107 | return kong.response.error(403, "Access Forbidden", { 108 | 109 | ["Content-Type"] = "text/plain", 110 | 111 | ["WWW-Authenticate"] = "Basic" 112 | 113 | }) 114 | 115 | # - 116 | 117 | return kong.response.error(403, "Access Forbidden") 118 | 119 | # - 120 | 121 | return kong.response.error(403) 122 | 123 | :parameter status: The status to be used (>399). 124 | :type status: number 125 | :parameter message: The error message to be used. 126 | :type message: str 127 | :parameter headers: The headers to be used. 128 | :type headers: table 129 | 130 | :return: throws an error on invalid input. 131 | 132 | :rtype: None 133 | """ 134 | pass 135 | 136 | @staticmethod 137 | def exit(status: number, body: Optional[bytes], headers: Optional[table]) -> None: 138 | """ 139 | 140 | This function interrupts the current processing and produces a response. 141 | It is typical to see plugins using it to produce a response before Kong 142 | has a chance to proxy the request (e.g. an authentication plugin rejecting 143 | a request, or a caching plugin serving a cached response). 144 | It is recommended to use this function in conjunction with the `return` 145 | operator, to better reflect its meaning: 146 | ```lua 147 | return kong.response.exit(200, "Success") 148 | ``` 149 | Calling `kong.response.exit()` interrupts the execution flow of 150 | plugins in the current phase. Subsequent phases will still be invoked. 151 | For example, if a plugin calls `kong.response.exit()` in the `access` 152 | phase, no other plugin is executed in that phase, but the 153 | `header_filter`, `body_filter`, and `log` phases are still executed, 154 | along with their plugins. Plugins should be programmed defensively 155 | against cases when a request is **not** proxied to the Service, but 156 | instead is produced by Kong itself. 157 | 1. The first argument `status` sets the status code of the response that 158 | is seen by the client. 159 | In L4 proxy mode, the `status` code provided is primarily for logging 160 | and statistical purposes, and is not visible to the client directly. 161 | In this mode, only the following status codes are supported: 162 | * 200 - OK 163 | * 400 - Bad request 164 | * 403 - Forbidden 165 | * 500 - Internal server error 166 | * 502 - Bad gateway 167 | * 503 - Service unavailable 168 | 2. The second, optional, `body` argument sets the response body. If it is 169 | a string, no special processing is done, and the body is sent 170 | as-is. It is the caller's responsibility to set the appropriate 171 | `Content-Type` header via the third argument. 172 | As a convenience, `body` can be specified as a table. In that case, 173 | the `body` is JSON-encoded and has the `application/json` Content-Type 174 | header set. 175 | On gRPC, we cannot send the `body` with this function, so 176 | it sends `"body"` in the `grpc-message` header instead. 177 | * If the body is a table, it looks for the `message` field in the body, 178 | and uses that as a `grpc-message` header. 179 | * If you specify `application/grpc` in the `Content-Type` header, the 180 | body is sent without needing the `grpc-message` header. 181 | In L4 proxy mode, `body` can only be `nil` or a string. Automatic JSON 182 | encoding is not available. When `body` is provided, depending on the 183 | value of `status`, the following happens: 184 | * When `status` is 500, 502 or 503, then `body` is logged in the Kong 185 | error log file. 186 | * When the `status` is anything else, `body` is sent back to the L4 client. 187 | 3. The third, optional, `headers` argument can be a table specifying 188 | response headers to send. If specified, its behavior is similar to 189 | `kong.response.set_headers()`. This argument is ignored in L4 proxy mode. 190 | Unless manually specified, this method automatically sets the 191 | `Content-Length` header in the produced response for convenience. 192 | 193 | Phases: 194 | preread, rewrite, access, admin_api, header_filter, only, if, body, is, nil 195 | 196 | Example: 197 | return kong.response.exit(403, "Access Forbidden", { 198 | 199 | ["Content-Type"] = "text/plain", 200 | 201 | ["WWW-Authenticate"] = "Basic" 202 | 203 | }) 204 | 205 | # - 206 | 207 | return kong.response.exit(403, [[{"message":"Access Forbidden"}]], { 208 | 209 | ["Content-Type"] = "application/json", 210 | 211 | ["WWW-Authenticate"] = "Basic" 212 | 213 | }) 214 | 215 | # - 216 | 217 | return kong.response.exit(403, { message = "Access Forbidden" }, { 218 | 219 | ["WWW-Authenticate"] = "Basic" 220 | 221 | }) 222 | 223 | # - 224 | 225 | # In L4 proxy mode 226 | 227 | return kong.response.exit(200, "Success") 228 | 229 | :parameter status: The status to be used. 230 | :type status: number 231 | :parameter body: The body to be used. 232 | :type body: bytes 233 | :parameter headers: The headers to be used. 234 | :type headers: table 235 | 236 | :return: throws an error on invalid input. 237 | 238 | :rtype: None 239 | """ 240 | pass 241 | 242 | @staticmethod 243 | def get_header(name: str) -> str: 244 | """ 245 | 246 | Returns the value of the specified response header, as would be seen by 247 | the client once received. 248 | The list of headers returned by this function can consist of both response 249 | headers from the proxied Service _and_ headers added by Kong (e.g. via 250 | `kong.response.add_header()`). 251 | The return value is either a `string`, or can be `nil` if a header with 252 | `name` is not found in the response. If a header with the same name is 253 | present multiple times in the request, this function returns the value 254 | of the first occurrence of this header. 255 | 256 | Phases: 257 | header_filter, response, body_filter, log, admin_api 258 | 259 | Example: 260 | # Given a response with the following headers: 261 | 262 | # X-Custom-Header: bla 263 | 264 | # X-Another: foo bar 265 | 266 | # X-Another: baz 267 | 268 | kong.response.get_header("x-custom-header") # "bla" 269 | 270 | kong.response.get_header("X-Another") # "foo bar" 271 | 272 | kong.response.get_header("X-None") # nil 273 | 274 | :parameter name: The name of the header. 275 | Header names are case-insensitive and dashes (`-`) can be written as 276 | underscores (`_`). For example, the header `X-Custom-Header` can also be 277 | retrieved as `x_custom_header`. 278 | :type name: str 279 | 280 | :return: The value of the header. 281 | 282 | :rtype: str 283 | """ 284 | pass 285 | 286 | @staticmethod 287 | def get_headers(max_headers: Optional[number]) -> Tuple[table, str]: 288 | """ 289 | 290 | Returns a Lua table holding the response headers. Keys are header names. 291 | Values are either a string with the header value, or an array of strings 292 | if a header was sent multiple times. Header names in this table are 293 | case-insensitive and are normalized to lowercase, and dashes (`-`) can be 294 | written as underscores (`_`). For example, the header `X-Custom-Header` can 295 | also be retrieved as `x_custom_header`. 296 | A response initially has no headers. Headers are added when a plugin 297 | short-circuits the proxying by producing a header 298 | (e.g. an authentication plugin rejecting a request), or if the request has 299 | been proxied, and one of the latter execution phases is currently running. 300 | Unlike `kong.service.response.get_headers()`, this function returns *all* 301 | headers as the client would see them upon reception, including headers 302 | added by Kong itself. 303 | By default, this function returns up to **100** headers (or what has been 304 | configured using `lua_max_resp_headers`). The optional `max_headers` argument 305 | can be specified to customize this limit, but must be greater than **1** and 306 | equal to or less than **1000**. 307 | 308 | Phases: 309 | header_filter, response, body_filter, log, admin_api 310 | 311 | Example: 312 | # Given an response from the Service with the following headers: 313 | 314 | # X-Custom-Header: bla 315 | 316 | # X-Another: foo bar 317 | 318 | # X-Another: baz 319 | 320 | headers = kong.response.get_headers() 321 | 322 | headers.x_custom_header # "bla" 323 | 324 | headers.x_another[1] # "foo bar" 325 | 326 | headers["X-Another"][2] # "baz" 327 | 328 | :parameter max_headers: Limits the number of headers parsed. 329 | :type max_headers: number 330 | 331 | :return: headers A table representation of the headers in the 332 | response. 333 | 334 | :rtype: table 335 | :return: err If more headers than `max_headers` were present, 336 | returns a string with the error `"truncated"`. 337 | 338 | :rtype: str 339 | """ 340 | pass 341 | 342 | @staticmethod 343 | def get_source() -> str: 344 | """ 345 | 346 | This function helps determine where the current response originated 347 | from. Since Kong is a reverse proxy, it can short-circuit a request and 348 | produce a response of its own, or the response can come from the proxied 349 | Service. 350 | Returns a string with three possible values: 351 | * `"exit"` is returned when, at some point during the processing of the 352 | request, there has been a call to `kong.response.exit()`. This happens 353 | when the request was short-circuited by a plugin or by Kong 354 | itself (e.g. invalid credentials). 355 | * `"error"` is returned when an error has happened while processing the 356 | request. For example, a timeout while connecting to the upstream 357 | service. 358 | * `"service"` is returned when the response was originated by successfully 359 | contacting the proxied Service. 360 | 361 | Phases: 362 | header_filter, response, body_filter, log, admin_api 363 | 364 | Example: 365 | if kong.response.get_source() == "service": 366 | 367 | kong.log("The response comes from the Service") 368 | 369 | elseif kong.response.get_source() == "error": 370 | 371 | kong.log("There was an error while processing the request") 372 | 373 | elseif kong.response.get_source() == "exit": 374 | 375 | kong.log("There was an early exit while processing the request") 376 | 377 | :return: The source. 378 | 379 | :rtype: str 380 | """ 381 | pass 382 | 383 | @staticmethod 384 | def get_status() -> number: 385 | """ 386 | 387 | Returns the HTTP status code currently set for the downstream response (as 388 | a Lua number). 389 | If the request was proxied (as per `kong.response.get_source()`), the 390 | return value is the response from the Service (identical to 391 | `kong.service.response.get_status()`). 392 | If the request was _not_ proxied and the response was produced by Kong 393 | itself (i.e. via `kong.response.exit()`), the return value is 394 | returned as-is. 395 | 396 | Phases: 397 | header_filter, response, body_filter, log, admin_api 398 | 399 | Example: 400 | kong.response.get_status() # 200 401 | 402 | :return: status The HTTP status code currently set for the 403 | downstream response. 404 | 405 | :rtype: number 406 | """ 407 | pass 408 | 409 | @staticmethod 410 | def set_header(name: str, of: table) -> None: 411 | """ 412 | 413 | Sets a response header with the given value. This function overrides any 414 | existing header with the same name. 415 | Note: Underscores in header names are automatically transformed into dashes 416 | by default. If you want to deactivate this behavior, set the 417 | `lua_transform_underscores_in_response_headers` Nginx config option to `off`. 418 | This setting can be set in the Kong Config file: 419 | nginx_http_lua_transform_underscores_in_response_headers = off 420 | Be aware that changing this setting might break any plugins that 421 | rely on the automatic underscore conversion. 422 | You cannot set Transfer-Encoding header with this function. It will be ignored. 423 | 424 | Phases: 425 | rewrite, access, header_filter, response, admin_api 426 | 427 | Example: 428 | kong.response.set_header("X-Foo", "value") 429 | 430 | :parameter name: The name of the header 431 | :type name: str 432 | :parameter of: strings|string|number|boolean value The new value for the header. 433 | :type of: table 434 | 435 | :return: throws an error on invalid input. 436 | 437 | :rtype: None 438 | """ 439 | pass 440 | 441 | @staticmethod 442 | def set_headers(headers: table) -> None: 443 | """ 444 | 445 | Sets the headers for the response. Unlike `kong.response.set_header()`, 446 | the `headers` argument must be a table in which each key is a string 447 | corresponding to a header's name, and each value is a string, or an 448 | array of strings. 449 | The resulting headers are produced in lexicographical order. The order of 450 | entries with the same name (when values are given as an array) is 451 | retained. 452 | This function overrides any existing header bearing the same name as those 453 | specified in the `headers` argument. Other headers remain unchanged. 454 | You cannot set Transfer-Encoding header with this function. It will be ignored. 455 | 456 | Phases: 457 | rewrite, access, header_filter, response, admin_api 458 | 459 | Example: 460 | kong.response.set_headers({ 461 | 462 | ["Bla"] = "boo", 463 | 464 | ["X-Foo"] = "foo3", 465 | 466 | ["Cache-Control"] = { "no-store", "no-cache" } 467 | 468 | }) 469 | 470 | # Will add the following headers to the response, in this order: 471 | 472 | # X-Bar: bar1 473 | 474 | # Bla: boo 475 | 476 | # Cache-Control: no-store 477 | 478 | # Cache-Control: no-cache 479 | 480 | # X-Foo: foo3 481 | 482 | :parameter headers: 483 | :type headers: table 484 | 485 | :return: throws an error on invalid input. 486 | 487 | :rtype: None 488 | """ 489 | pass 490 | 491 | @staticmethod 492 | def set_status(status: number) -> None: 493 | """ 494 | 495 | Allows changing the downstream response HTTP status code before sending it 496 | to the client. 497 | 498 | Phases: 499 | rewrite, access, header_filter, response, admin_api 500 | 501 | Example: 502 | kong.response.set_status(404) 503 | 504 | :parameter status: The new status. 505 | :type status: number 506 | 507 | :return: throws an error on invalid input. 508 | 509 | :rtype: None 510 | """ 511 | pass 512 | 513 | pass 514 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/router.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/router.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class router(): 14 | 15 | 16 | @staticmethod 17 | def get_route() -> table: 18 | """ 19 | 20 | Returns the current `route` entity. The request is matched against this 21 | route. 22 | 23 | Phases: 24 | access, header_filter, response, body_filter, log 25 | 26 | Example: 27 | route = kong.router.get_route() 28 | 29 | protocols = route.protocols 30 | 31 | :return: The `route` entity. 32 | 33 | :rtype: table 34 | """ 35 | pass 36 | 37 | @staticmethod 38 | def get_service() -> table: 39 | """ 40 | 41 | Returns the current `service` entity. The request is targeted to this 42 | upstream service. 43 | 44 | Phases: 45 | access, header_filter, response, body_filter, log 46 | 47 | Example: 48 | if kong.router.get_service(): 49 | 50 | # routed by route & service entities 51 | 52 | else: 53 | 54 | # routed by a route without a service 55 | 56 | :return: The `service` entity. 57 | 58 | :rtype: table 59 | """ 60 | pass 61 | 62 | pass 63 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/service/__init__.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/service.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | from .request import request as cls_request 13 | from .response import response as cls_response 14 | 15 | class service(): 16 | 17 | request = cls_request 18 | response = cls_response 19 | 20 | @staticmethod 21 | def set_retries(retries: number) -> None: 22 | """ 23 | 24 | Sets the retries count for the current request. This will override the 25 | default retries count set in the Upstream entity. 26 | The `retries` argument expects an integer between 0 and 32767. 27 | 28 | Phases: 29 | access 30 | 31 | Example: 32 | kong.service.set_retries(233) 33 | 34 | :parameter retries: 35 | :type retries: number 36 | 37 | """ 38 | pass 39 | 40 | @staticmethod 41 | def set_target(host: str, port: number) -> None: 42 | """ 43 | 44 | Sets the host and port on which to connect to for proxying the request. 45 | Using this method is equivalent to ask Kong to not run the load-balancing 46 | phase for this request, and consider it manually overridden. 47 | Load-balancing components such as retries and health-checks will also be 48 | ignored for this request. Use `kong.service.set_retries` to overwrite 49 | retries count. 50 | The `host` argument expects the hostname or IP address of the upstream 51 | server, and the `port` expects a port number. 52 | 53 | Phases: 54 | access 55 | 56 | Example: 57 | kong.service.set_target("service.local", 443) 58 | 59 | kong.service.set_target("192.168.130.1", 80) 60 | 61 | :parameter host: 62 | :type host: str 63 | :parameter port: 64 | :type port: number 65 | 66 | """ 67 | pass 68 | 69 | @staticmethod 70 | def set_timeouts(connect_timeout: number, write_timeout: number, read_timeout: number) -> None: 71 | """ 72 | 73 | Sets the timeouts for the current request. This will override the 74 | default timeouts set in the Upstream entity. 75 | 76 | The `connect_timeout`, `write_timeout`, and `read_timeout` arguments expect 77 | an integer between 1 and 2147483646. 78 | 79 | Phases: 80 | access 81 | 82 | Example: 83 | kong.service.set_timeouts(233, 233, 233) 84 | 85 | :parameter connect_timeout: 86 | :type connect_timeout: number 87 | :parameter write_timeout: 88 | :type write_timeout: number 89 | :parameter read_timeout: 90 | :type read_timeout: number 91 | 92 | """ 93 | pass 94 | 95 | @staticmethod 96 | def set_tls_verify(on: bool) -> Tuple[bool, str]: 97 | """ 98 | 99 | Sets whether TLS verification is enabled while handshaking with the Service. 100 | The `on` argument is a boolean flag, where `true` means upstream verification 101 | is enabled and `false` disables it. 102 | This call affects only the current request. If the trusted certificate store is 103 | not set already (via [proxy_ssl_trusted_certificate](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_trusted_certificate) 104 | or [kong.service.set_upstream_ssl_trusted_store](#kongserviceset_upstream_ssl_trusted_store)), 105 | then TLS verification will always fail with "unable to get local issuer certificate" error. 106 | 107 | Phases: 108 | rewrite, access, balancer, preread 109 | 110 | Example: 111 | ok, err = kong.service.set_tls_verify(true) 112 | 113 | if not ok: 114 | 115 | # do something with error 116 | 117 | :parameter on: Whether to enable TLS certificate verification for the current request 118 | :type on: bool 119 | 120 | :return: `true` if the operation succeeded, `nil` if an error occurred 121 | 122 | :rtype: bool 123 | :return: An error message describing the error if there was one 124 | 125 | :rtype: str 126 | """ 127 | pass 128 | 129 | @staticmethod 130 | def set_tls_verify_depth(depth: number) -> Tuple[bool, str]: 131 | """ 132 | 133 | Sets the maximum depth of verification when validating upstream server's TLS certificate. 134 | This call affects only the current request. For the depth to be actually used the verification 135 | has to be enabled with either the [proxy_ssl_verify](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ssl_verify) 136 | directive or using the [kong.service.set_tls_verify](#kongserviceset_tls_verify) function. 137 | 138 | Phases: 139 | rewrite, access, balancer, preread 140 | 141 | Example: 142 | ok, err = kong.service.set_tls_verify_depth(3) 143 | 144 | if not ok: 145 | 146 | # do something with error 147 | 148 | :parameter depth: Depth to use when validating. Must be non-negative 149 | :type depth: number 150 | 151 | :return: `true` if the operation succeeded, `nil` if an error occurred 152 | 153 | :rtype: bool 154 | :return: An error message describing the error if there was one 155 | 156 | :rtype: str 157 | """ 158 | pass 159 | 160 | @staticmethod 161 | def set_upstream(host: str) -> Tuple[bool, str]: 162 | """ 163 | 164 | Sets the desired Upstream entity to handle the load-balancing step for 165 | this request. Using this method is equivalent to creating a Service with a 166 | `host` property equal to that of an Upstream entity (in which case, the 167 | request would be proxied to one of the Targets associated with that 168 | Upstream). 169 | The `host` argument should receive a string equal to the name of one of the 170 | Upstream entities currently configured. 171 | 172 | Phases: 173 | access 174 | 175 | Example: 176 | ok, err = kong.service.set_upstream("service.prod") 177 | 178 | if not ok: 179 | 180 | kong.log.err(err) 181 | 182 | return 183 | 184 | :parameter host: 185 | :type host: str 186 | 187 | :return: `true` on success, or `nil` if no upstream entities 188 | where found 189 | 190 | :rtype: bool 191 | :return: An error message describing the error if there was 192 | one. 193 | 194 | :rtype: str 195 | """ 196 | pass 197 | 198 | pass 199 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/service/request.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/service/request.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class request(): 14 | 15 | 16 | @staticmethod 17 | def add_header(header: str, of: table) -> None: 18 | """ 19 | 20 | Adds a request header with the given value to the request to the Service. Unlike 21 | `kong.service.request.set_header()`, this function doesn't remove any existing 22 | headers with the same name. Instead, several occurrences of the header will be 23 | present in the request. The order in which headers are added is retained. 24 | 25 | Phases: 26 | rewrite, access 27 | 28 | Example: 29 | kong.service.request.add_header("Cache-Control", "no-cache") 30 | 31 | kong.service.request.add_header("Cache-Control", "no-store") 32 | 33 | :parameter header: The header name. Example: "Cache-Control". 34 | :type header: str 35 | :parameter of: strings|string|number|boolean value The header value. Example: "no-cache". 36 | :type of: table 37 | 38 | :return: throws an error on invalid inputs. 39 | 40 | :rtype: None 41 | """ 42 | pass 43 | 44 | @staticmethod 45 | def clear_header(header: str) -> None: 46 | """ 47 | 48 | Removes all occurrences of the specified header from the request to the Service. 49 | 50 | Phases: 51 | rewrite, access 52 | 53 | Example: 54 | kong.service.request.set_header("X-Foo", "foo") 55 | 56 | kong.service.request.add_header("X-Foo", "bar") 57 | 58 | kong.service.request.clear_header("X-Foo") 59 | 60 | # from here onwards, no X-Foo headers will exist in the request 61 | 62 | :parameter header: The header name. Example: "X-Foo". 63 | :type header: str 64 | 65 | :return: throws an error on invalid inputs. 66 | The function does not throw an error if no header was removed. 67 | 68 | :rtype: None 69 | """ 70 | pass 71 | 72 | @staticmethod 73 | def disable_tls() -> Tuple[bool, str]: 74 | """ 75 | 76 | Disables the TLS handshake to upstream for [ngx\_stream\_proxy\_module](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html). 77 | This overrides the [proxy\_ssl](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_ssl) directive, effectively setting it to `off` 78 | for the current stream session. 79 | Once this function has been called, it is not possible to re-enable TLS handshake for the current session. 80 | 81 | Phases: 82 | preread, balancer 83 | 84 | Example: 85 | ok, err = kong.service.request.disable_tls() 86 | 87 | if not ok: 88 | 89 | # do something with error 90 | 91 | :return: `true` if the operation succeeded, `nil` if an error occurred. 92 | 93 | :rtype: bool 94 | :return: An error message describing the error if there was one. 95 | 96 | :rtype: str 97 | """ 98 | pass 99 | 100 | @staticmethod 101 | def enable_buffering() -> None: 102 | """ 103 | 104 | Enables buffered proxying, which allows plugins to access Service body and 105 | response headers at the same time. 106 | 107 | Phases: 108 | rewrite, access, balancer 109 | 110 | Example: 111 | kong.service.request.enable_buffering() 112 | 113 | :return: 114 | 115 | :rtype: None 116 | """ 117 | pass 118 | 119 | @staticmethod 120 | def set_body(args: table, mimetype: Optional[str]) -> Tuple[bool, str]: 121 | """ 122 | 123 | Sets the body of the request to the Service. Unlike 124 | `kong.service.request.set_raw_body()`, the `args` argument must be a table, and 125 | is encoded with a MIME type. The encoding MIME type can be specified in 126 | the optional `mimetype` argument, or if left unspecified, is chosen based 127 | on the `Content-Type` header of the client's request. 128 | Behavior based on MIME type in the `Content-Type` header: 129 | * `application/x-www-form-urlencoded`: Encodes the arguments as 130 | form-encoded. Keys are produced in lexicographical 131 | order. The order of entries within the same key (when values are 132 | given as an array) is retained. Any string values given are URL-encoded. 133 | * `multipart/form-data`: Encodes the arguments as multipart form data. 134 | * `application/json`: Encodes the arguments as JSON (same as 135 | `kong.service.request.set_raw_body(json.encode(args))`). Lua types are 136 | converted to matching JSON types. 137 | If the MIME type is none of the above, this function returns `nil` and 138 | an error message indicating the body could not be encoded. 139 | If the `mimetype` argument is specified, the `Content-Type` header is 140 | set accordingly in the request to the Service. 141 | If further control of the body generation is needed, a raw body can be given as 142 | a string with `kong.service.request.set_raw_body()`. 143 | 144 | Phases: 145 | rewrite, access, balancer 146 | 147 | Example: 148 | kong.service.set_header("application/json") 149 | 150 | ok, err = kong.service.request.set_body({ 151 | 152 | name = "John Doe", 153 | 154 | age = 42, 155 | 156 | numbers = {1, 2, 3} 157 | 158 | }) 159 | 160 | # Produces the following JSON body: 161 | 162 | # { "name": "John Doe", "age": 42, "numbers":[1, 2, 3] } 163 | 164 | ok, err = kong.service.request.set_body({ 165 | 166 | foo = "hello world", 167 | 168 | bar = {"baz", "bla", true}, 169 | 170 | zzz = true, 171 | 172 | blo = "" 173 | 174 | }, "application/x-www-form-urlencoded") 175 | 176 | # Produces the following body: 177 | 178 | # bar=baz&bar=bla&bar&blo=&foo=hello%20world&zzz 179 | 180 | :parameter args: A table with data to be converted to the appropriate format 181 | and stored in the body. 182 | :type args: table 183 | :parameter mimetype: can be one of: 184 | :type mimetype: str 185 | 186 | :return: `true` on success, `nil` otherwise. 187 | 188 | :rtype: bool 189 | :return: `nil` on success, an error message in case of error. 190 | Throws an error on invalid inputs. 191 | 192 | :rtype: str 193 | """ 194 | pass 195 | 196 | @staticmethod 197 | def set_header(header: str, of: table) -> None: 198 | """ 199 | 200 | Sets a header in the request to the Service with the given value. Any existing header 201 | with the same name will be overridden. 202 | If the `header` argument is `"host"` (case-insensitive), then this also 203 | sets the SNI of the request to the Service. 204 | 205 | Phases: 206 | rewrite, access, balancer 207 | 208 | Example: 209 | kong.service.request.set_header("X-Foo", "value") 210 | 211 | :parameter header: The header name. Example: "X-Foo". 212 | :type header: str 213 | :parameter of: strings|string|boolean|number value The header value. Example: "hello world". 214 | :type of: table 215 | 216 | :return: throws an error on invalid inputs. 217 | 218 | :rtype: None 219 | """ 220 | pass 221 | 222 | @staticmethod 223 | def set_headers(headers: table) -> None: 224 | """ 225 | 226 | Sets the headers of the request to the Service. Unlike 227 | `kong.service.request.set_header()`, the `headers` argument must be a table in 228 | which each key is a string (corresponding to a header's name), and each value 229 | is a string, or an array of strings. 230 | The resulting headers are produced in lexicographical order. The order of 231 | entries with the same name (when values are given as an array) is retained. 232 | This function overrides any existing header bearing the same name as those 233 | specified in the `headers` argument. Other headers remain unchanged. 234 | If the `"Host"` header is set (case-insensitive), then this also sets 235 | the SNI of the request to the Service. 236 | 237 | Phases: 238 | rewrite, access 239 | 240 | Example: 241 | kong.service.request.set_header("X-Foo", "foo1") 242 | 243 | kong.service.request.add_header("X-Foo", "foo2") 244 | 245 | kong.service.request.set_header("X-Bar", "bar1") 246 | 247 | kong.service.request.set_headers({ 248 | 249 | ["X-Foo"] = "foo3", 250 | 251 | ["Cache-Control"] = { "no-store", "no-cache" }, 252 | 253 | ["Bla"] = "boo" 254 | 255 | }) 256 | 257 | # Will add the following headers to the request, in this order: 258 | 259 | # X-Bar: bar1 260 | 261 | # Bla: boo 262 | 263 | # Cache-Control: no-store 264 | 265 | # Cache-Control: no-cache 266 | 267 | # X-Foo: foo3 268 | 269 | :parameter headers: A table where each key is a string containing a header name 270 | and each value is either a string or an array of strings. 271 | :type headers: table 272 | 273 | :return: throws an error on invalid inputs. 274 | 275 | :rtype: None 276 | """ 277 | pass 278 | 279 | @staticmethod 280 | def set_method(method: str) -> None: 281 | """ 282 | 283 | Sets the HTTP method for the request to the service. 284 | 285 | Phases: 286 | rewrite, access 287 | 288 | Example: 289 | kong.service.request.set_method("DELETE") 290 | 291 | :parameter method: The method string, which must be in all 292 | uppercase. Supported values are: `"GET"`, `"HEAD"`, `"PUT"`, `"POST"`, 293 | `"DELETE"`, `"OPTIONS"`, `"MKCOL"`, `"COPY"`, `"MOVE"`, `"PROPFIND"`, 294 | `"PROPPATCH"`, `"LOCK"`, `"UNLOCK"`, `"PATCH"`, or `"TRACE"`. 295 | :type method: str 296 | 297 | :return: throws an error on invalid inputs. 298 | 299 | :rtype: None 300 | """ 301 | pass 302 | 303 | @staticmethod 304 | def set_path(path: str) -> None: 305 | """ 306 | 307 | Sets the path component for the request to the service. 308 | The input accepts any valid *normalized* URI (including UTF-8 characters) 309 | and this API will perform necessary escaping according to the RFC 310 | to make the request valid. 311 | Input should **not** include the query string. 312 | 313 | Phases: 314 | access, rewrite, balancer 315 | 316 | Example: 317 | kong.service.request.set_path("/v2/movies") 318 | 319 | :parameter path: The path string. Special characters and UTF-8 320 | characters are allowed, for example: `"/v2/movies"` or `"/foo/😀"`. 321 | :type path: str 322 | 323 | :return: throws an error on invalid inputs. 324 | 325 | :rtype: None 326 | """ 327 | pass 328 | 329 | @staticmethod 330 | def set_query(args: table) -> None: 331 | """ 332 | 333 | Set the query string of the request to the Service. 334 | Unlike `kong.service.request.set_raw_query()`, the `query` argument must be a 335 | table in which each key is a string (corresponding to an argument's name), and 336 | each value is either a boolean, a string, or an array of strings or booleans. 337 | Additionally, all string values will be URL-encoded. 338 | The resulting query string contains keys in their lexicographical order. The 339 | order of entries within the same key (when values are given as an array) is 340 | retained. 341 | If further control of the query string generation is needed, a raw query 342 | string can be given as a string with `kong.service.request.set_raw_query()`. 343 | 344 | Phases: 345 | rewrite, access 346 | 347 | Example: 348 | kong.service.request.set_query({ 349 | 350 | foo = "hello world", 351 | 352 | bar = {"baz", "bla", true}, 353 | 354 | zzz = true, 355 | 356 | blo = "" 357 | 358 | }) 359 | 360 | # Produces the following query string: 361 | 362 | # bar=baz&bar=bla&bar&blo=&foo=hello%20world&zzz 363 | 364 | :parameter args: A table where each key is a string (corresponding to an 365 | argument name), and each value is either a boolean, a string, or an array of 366 | strings or booleans. Any string values given are URL-encoded. 367 | :type args: table 368 | 369 | :return: throws an error on invalid inputs. 370 | 371 | :rtype: None 372 | """ 373 | pass 374 | 375 | @staticmethod 376 | def set_raw_body(body: str) -> None: 377 | """ 378 | 379 | Sets the body of the request to the Service. 380 | The `body` argument must be a string and will not be processed in any way. 381 | This function also sets the `Content-Length` header appropriately. To set an 382 | empty body, you can provide an empty string (`""`) to this function. 383 | For a higher-level function to set the body based on the request content type, 384 | see `kong.service.request.set_body()`. 385 | 386 | Phases: 387 | rewrite, access, balancer 388 | 389 | Example: 390 | kong.service.request.set_raw_body("Hello, world!") 391 | 392 | :parameter body: The raw body. 393 | :type body: str 394 | 395 | :return: throws an error on invalid inputs. 396 | 397 | :rtype: None 398 | """ 399 | pass 400 | 401 | @staticmethod 402 | def set_raw_query(query: str) -> None: 403 | """ 404 | 405 | Sets the query string of the request to the Service. The `query` argument is a 406 | string (without the leading `?` character), and is not processed in any 407 | way. 408 | For a higher-level function to set the query string from a Lua table of 409 | arguments, see `kong.service.request.set_query()`. 410 | 411 | Phases: 412 | rewrite, access 413 | 414 | Example: 415 | kong.service.request.set_raw_query("zzz&bar=baz&bar=bla&bar&blo=&foo=hello%20world") 416 | 417 | :parameter query: The raw querystring. Example: 418 | `"foo=bar&bla&baz=hello%20world"`. 419 | :type query: str 420 | 421 | :return: throws an error on invalid inputs. 422 | 423 | :rtype: None 424 | """ 425 | pass 426 | 427 | @staticmethod 428 | def set_scheme(scheme: str) -> None: 429 | """ 430 | 431 | Sets the protocol to use when proxying the request to the Service. 432 | 433 | Phases: 434 | access, rewrite, balancer 435 | 436 | Example: 437 | kong.service.request.set_scheme("https") 438 | 439 | :parameter scheme: The scheme to be used. Supported values are `"http"` or `"https"`. 440 | :type scheme: str 441 | 442 | :return: throws an error on invalid inputs. 443 | 444 | :rtype: None 445 | """ 446 | pass 447 | 448 | pass 449 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/service/response.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/service/response.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class response(): 14 | 15 | 16 | @staticmethod 17 | def get_body(mimetype: Optional[str], max_args: Optional[number]) -> str: 18 | """ 19 | 20 | Returns the decoded buffered body. 21 | 22 | Phases: 23 | header_filter, body_filter, log 24 | 25 | Example: 26 | # Plugin needs to call kong.service.request.enable_buffering() on `rewrite` 27 | 28 | # or `access` phase prior calling this function. 29 | 30 | body = kong.service.response.get_body() 31 | 32 | :parameter mimetype: The MIME type of the response (if known). 33 | :type mimetype: str 34 | :parameter max_args: Sets a limit on the maximum number of (what?) 35 | that can be parsed. 36 | :type max_args: number 37 | 38 | :return: The decoded buffered body 39 | 40 | :rtype: str 41 | """ 42 | pass 43 | 44 | @staticmethod 45 | def get_header(name: str) -> str: 46 | """ 47 | 48 | Returns the value of the specified response header. 49 | Unlike `kong.response.get_header()`, this function only returns a header 50 | if it is present in the response from the Service (ignoring headers added by Kong 51 | itself). 52 | 53 | Phases: 54 | header_filter, body_filter, log 55 | 56 | Example: 57 | # Given a response with the following headers: 58 | 59 | # X-Custom-Header: bla 60 | 61 | # X-Another: foo bar 62 | 63 | # X-Another: baz 64 | 65 | kong.log.inspect(kong.service.response.get_header("x-custom-header")) # "bla" 66 | 67 | kong.log.inspect(kong.service.response.get_header("X-Another")) # "foo bar" 68 | 69 | :parameter name: The name of the header. 70 | Header names in are case-insensitive and are normalized to lowercase, and 71 | dashes (`-`) can be written as underscores (`_`); that is, the header 72 | `X-Custom-Header` can also be retrieved as `x_custom_header`. 73 | :type name: str 74 | 75 | :return: The value of the header, or `nil` if a header with 76 | `name` is not found in the response. If a header with the same name is present 77 | multiple times in the response, this function returns the value of the 78 | first occurrence of this header. 79 | 80 | :rtype: str 81 | """ 82 | pass 83 | 84 | @staticmethod 85 | def get_headers(max_headers: Optional[number]) -> Tuple[table, str]: 86 | """ 87 | 88 | Returns a Lua table holding the headers from the Service response. Keys are 89 | header names. Values are either a string with the header value, or an array of 90 | strings if a header was sent multiple times. Header names in this table are 91 | case-insensitive and dashes (`-`) can be written as underscores (`_`); that is, 92 | the header `X-Custom-Header` can also be retrieved as `x_custom_header`. 93 | Unlike `kong.response.get_headers()`, this function only returns headers that 94 | are present in the response from the Service (ignoring headers added by Kong itself). 95 | If the request is not proxied to a Service (e.g. an authentication plugin rejected 96 | a request and produced an HTTP 401 response), then the returned `headers` value 97 | might be `nil`, since no response from the Service has been received. 98 | By default, this function returns up to **100** headers. The optional 99 | `max_headers` argument can be specified to customize this limit, but must be 100 | greater than **1** and not greater than **1000**. 101 | 102 | Phases: 103 | header_filter, body_filter, log 104 | 105 | Example: 106 | # Given a response with the following headers: 107 | 108 | # X-Custom-Header: bla 109 | 110 | # X-Another: foo bar 111 | 112 | # X-Another: baz 113 | 114 | headers = kong.service.response.get_headers() 115 | 116 | if headers: 117 | 118 | kong.log.inspect(headers.x_custom_header) # "bla" 119 | 120 | kong.log.inspect(headers.x_another[1]) # "foo bar" 121 | 122 | kong.log.inspect(headers["X-Another"][2]) # "baz"Note that this function returns a proxy table 123 | 124 | which cannot be iterated with `pairs` or used as operand of `#`. 125 | 126 | :parameter max_headers: Sets a limit on the maximum number of 127 | headers that can be parsed. 128 | :type max_headers: number 129 | 130 | :return: The response headers in table form. 131 | 132 | :rtype: table 133 | :return: If more headers than `max_headers` are present, returns 134 | a string with the error `"truncated"`. 135 | 136 | :rtype: str 137 | """ 138 | pass 139 | 140 | @staticmethod 141 | def get_raw_body() -> bytes: 142 | """ 143 | 144 | Returns the raw buffered body. 145 | 146 | Phases: 147 | header_filter, body_filter, log 148 | 149 | Example: 150 | # Plugin needs to call kong.service.request.enable_buffering() on `rewrite` 151 | 152 | # or `access` phase prior calling this function. 153 | 154 | body = kong.service.response.get_raw_body() 155 | 156 | :return: The raw buffered body. 157 | 158 | :rtype: bytes 159 | """ 160 | pass 161 | 162 | @staticmethod 163 | def get_status() -> number: 164 | """ 165 | 166 | Returns the HTTP status code of the response from the Service as a Lua number. 167 | 168 | Phases: 169 | header_filter, body_filter, log 170 | 171 | Example: 172 | kong.log.inspect(kong.service.response.get_status()) # 418 173 | 174 | :return: The status code from the response from the Service, or `nil` 175 | if the request was not proxied (that is, if `kong.response.get_source()` returned 176 | anything other than `"service"`). 177 | 178 | :rtype: number 179 | """ 180 | pass 181 | 182 | pass 183 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/telemetry.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/telemetry.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class telemetry(): 14 | 15 | 16 | @staticmethod 17 | def log(plugin_name: str, plugin_config: table, message_type: str, message: str, attributes: table) -> None: 18 | """ 19 | 20 | Records a structured log entry, to be reported via the OpenTelemetry plugin. 21 | This function has a dependency on the OpenTelemetry plugin, which must be 22 | configured to report OpenTelemetry logs. 23 | 24 | Phases: 25 | rewrite, access, balancer, timer, header_filter, response, body_filter, log 26 | 27 | Example: 28 | attributes = { 29 | 30 | http_method = kong.request.get_method() 31 | 32 | ["node.id"] = kong.node.get_id(), 33 | 34 | hostname = kong.node.get_hostname(), 35 | 36 | } 37 | 38 | ok, err = kong.telemetry.log("my_plugin", conf, "result", "successful operation", attributes) 39 | 40 | :parameter plugin_name: the name of the plugin 41 | :type plugin_name: str 42 | :parameter plugin_config: the plugin configuration 43 | :type plugin_config: table 44 | :parameter message_type: the type of the log message, useful to categorize 45 | the log entry 46 | :type message_type: str 47 | :parameter message: the log message 48 | :type message: str 49 | :parameter attributes: structured information to be included in the 50 | `attributes` field of the log entry 51 | :type attributes: table 52 | 53 | """ 54 | pass 55 | 56 | pass 57 | -------------------------------------------------------------------------------- /kong_pdk/pdk/kong/vault.py: -------------------------------------------------------------------------------- 1 | # AUTO GENERATED BASED ON Kong 3.8.x, DO NOT EDIT 2 | # Original source path: kong/pdk/vault.lua 3 | 4 | from typing import TypeVar, Any, Union, List, Mapping, Tuple, Optional 5 | 6 | number = TypeVar('number', int, float) 7 | table = TypeVar('table', List[Any], Mapping[str, Any]) 8 | # XXX 9 | cdata = Any 10 | err = str 11 | 12 | 13 | class vault(): 14 | 15 | 16 | @staticmethod 17 | def flush() -> None: 18 | """ 19 | 20 | Flush vault LRU cache and start a timer to rotate secrets. 21 | @local 22 | 23 | Example: 24 | kong.vault.flush() 25 | 26 | """ 27 | pass 28 | 29 | @staticmethod 30 | def get(reference: str) -> Tuple[str, str]: 31 | """ 32 | 33 | Resolves the passed in reference and returns the value of it. 34 | 35 | Example: 36 | value, err = kong.vault.get("{vault://env/cert/key}") 37 | 38 | :parameter reference: reference to resolve 39 | :type reference: str 40 | 41 | :return: resolved value of the reference 42 | 43 | :rtype: str 44 | :return: error message on failure, otherwise `nil` 45 | 46 | :rtype: str 47 | """ 48 | pass 49 | 50 | @staticmethod 51 | def init_worker() -> None: 52 | """ 53 | 54 | Initializes vault. 55 | Registers event handlers (on non-dbless nodes) and starts a recurring secrets 56 | rotation timer. Does nothing on control planes. 57 | @local 58 | 59 | """ 60 | pass 61 | 62 | @staticmethod 63 | def is_reference(reference: str) -> bool: 64 | """ 65 | 66 | Checks if the passed in reference looks like a reference. 67 | Valid references start with '{vault://' and end with '}'. 68 | If you need more thorough validation, 69 | use `kong.vault.parse_reference`. 70 | 71 | Example: 72 | kong.vault.is_reference("{vault://env/key}") # true 73 | 74 | kong.vault.is_reference("not a reference") # false 75 | 76 | :parameter reference: reference to check 77 | :type reference: str 78 | 79 | :return: `true` is the passed in reference looks like a reference, otherwise `false` 80 | 81 | :rtype: bool 82 | """ 83 | pass 84 | 85 | @staticmethod 86 | def parse_reference(reference: str) -> Tuple[table, str]: 87 | """ 88 | 89 | Parses and decodes the passed in reference and returns a table 90 | containing its components. 91 | Given a following resource: 92 | ```lua 93 | "{vault://env/cert/key?prefix=SSL_#1}" 94 | ``` 95 | This function will return following table: 96 | ```lua 97 | { 98 | name = "env", -- name of the Vault entity or Vault strategy 99 | resource = "cert", -- resource where secret is stored 100 | key = "key", -- key to lookup if the resource is secret object 101 | config = { -- if there are any config options specified 102 | prefix = "SSL_" 103 | }, 104 | version = 1 -- if the version is specified 105 | } 106 | ``` 107 | 108 | Example: 109 | ref, err = kong.vault.parse_reference("{vault://env/cert/key?prefix=SSL_#1}") # table 110 | 111 | :parameter reference: reference to parse 112 | :type reference: str 113 | 114 | :return: a table containing each component of the reference, or `nil` on error 115 | 116 | :rtype: table 117 | :return: error message on failure, otherwise `nil` 118 | 119 | :rtype: str 120 | """ 121 | pass 122 | 123 | @staticmethod 124 | def update(options: table) -> table: 125 | """ 126 | 127 | Helper function for secret rotation based on TTLs. Currently experimental. 128 | 129 | Example: 130 | options = kong.vault.update({ 131 | 132 | cert = "# # -BEGIN CERTIFICATE# # -...", 133 | 134 | key = "# # -BEGIN RSA PRIVATE KEY# # -...", 135 | 136 | cert_alt = "# # -BEGIN CERTIFICATE# # -...", 137 | 138 | key_alt = "# # -BEGIN EC PRIVATE KEY# # -...", 139 | 140 | ["$refs"] = { 141 | 142 | cert = "{vault://aws/cert}", 143 | 144 | key = "{vault://aws/key}", 145 | 146 | cert_alt = "{vault://aws/cert-alt}", 147 | 148 | key_alt = "{vault://aws/key-alt}", 149 | 150 | } 151 | 152 | }) 153 | 154 | # or 155 | 156 | options = { 157 | 158 | cert = "# # -BEGIN CERTIFICATE# # -...", 159 | 160 | key = "# # -BEGIN RSA PRIVATE KEY# # -...", 161 | 162 | cert_alt = "# # -BEGIN CERTIFICATE# # -...", 163 | 164 | key_alt = "# # -BEGIN EC PRIVATE KEY# # -...", 165 | 166 | ["$refs"] = { 167 | 168 | cert = "{vault://aws/cert}", 169 | 170 | key = "{vault://aws/key}", 171 | 172 | cert_alt = "{vault://aws/cert-alt}", 173 | 174 | key_alt = "{vault://aws/key-alt}", 175 | 176 | } 177 | 178 | } 179 | 180 | kong.vault.update(options) 181 | 182 | :parameter options: options containing secrets and references (this function modifies the input options) 183 | :type options: table 184 | 185 | :return: options with updated secret values 186 | 187 | :rtype: table 188 | """ 189 | pass 190 | 191 | @staticmethod 192 | def warmup() -> None: 193 | """ 194 | 195 | Warmups vault caches from config. 196 | @local 197 | 198 | """ 199 | pass 200 | 201 | pass 202 | -------------------------------------------------------------------------------- /kong_pdk/server.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import json 4 | 5 | from .const import PY3K 6 | 7 | import threading 8 | if PY3K: 9 | from queue import Queue 10 | else: 11 | from Queue import Queue 12 | 13 | import multiprocessing 14 | # patch connection API so it share with gevent.queue.Channel 15 | if PY3K: 16 | from multiprocessing import connection 17 | connection.Connection.get = connection.Connection.recv 18 | connection.Connection.put = connection.Connection.send 19 | 20 | from gevent import sleep as gsleep, spawn as gspawn 21 | from gevent.lock import Semaphore as gSemaphore 22 | from gevent.queue import Channel as gChannel 23 | 24 | try: 25 | import setproctitle 26 | except: # noqa: E722 do not use bare 'except 27 | setproctitle = None 28 | 29 | from .pdk import Kong 30 | from .module import Module 31 | from .exception import PluginServerException 32 | from .logger import Logger 33 | 34 | exts = ('.py', '.pyd', '.so') 35 | entities = ('service', 'consumer', 'route', 'plugin', 'credential', 'memory_stats') 36 | 37 | MSG_RET = 'ret' 38 | 39 | terminal_methods = set(( 40 | "kong.response.exit", 41 | "kong.response.error", 42 | )) 43 | 44 | def locked_by(lock_name): 45 | def f(fn): 46 | def wrapper(*args, **kwargs): 47 | self = args[0] 48 | lock = getattr(self, lock_name) 49 | lock.acquire() 50 | try: 51 | r = fn(*args, **kwargs) 52 | except Exception as ex: 53 | lock.release() 54 | raise ex 55 | lock.release() 56 | return r 57 | return wrapper 58 | 59 | return f 60 | 61 | def _handler_event_func(cls_phase, ch, lua_style): 62 | cls_phase(Kong(ch, lua_style).kong) 63 | ch.put(MSG_RET) 64 | 65 | def _multiprocessing_init(pool_name): 66 | p = multiprocessing.current_process() 67 | p.name = "%s: %s (ppid: %d)" % (pool_name, p.name, os.getppid()) 68 | if setproctitle: 69 | setproctitle.setproctitle(p.name) 70 | 71 | class PluginServer(object): 72 | def __init__(self, loglevel=Logger.WARNING, expire_ttl=60, plugin_dir=None, 73 | use_multiprocess=False, use_gevent=False, name=None, lua_style=True): 74 | if use_multiprocess: 75 | sem = multiprocessing.Semaphore 76 | elif use_gevent: 77 | sem = gSemaphore 78 | else: 79 | sem = threading.Semaphore 80 | 81 | self.plugin_dir = plugin_dir 82 | self.plugins = {} 83 | self.instances = {} 84 | self.instance_id = 0 85 | self.i_lock = sem() 86 | self.events = {} 87 | self.event_id = 0 88 | self.e_lock = sem() 89 | 90 | self.logger = Logger() 91 | self.logger.set_level(loglevel) 92 | 93 | if plugin_dir: 94 | self._load_plugins() 95 | 96 | title = "Kong Python Plugin Server" 97 | if name: 98 | title = "%s \"%s\"" % (title, name) 99 | 100 | self.use_multiprocess = use_multiprocess 101 | self.use_gevent = use_gevent 102 | 103 | self.lua_style = lua_style 104 | 105 | if use_multiprocess: 106 | if not PY3K: 107 | raise NotImplementedError("multiprocessing mode is only supported in Python3") 108 | 109 | self._process_pool = multiprocessing.Pool( 110 | os.cpu_count(), 111 | _multiprocessing_init, 112 | (title, ), 113 | ) 114 | self.logger.debug("plugin server is in multiprocessing mode") 115 | 116 | # start cleanup timer 117 | if use_gevent: 118 | self.logger.debug("plugin server is in gevent mode") 119 | # gspawn(self._clear_expired_plugins, expire_ttl) 120 | else: 121 | pass 122 | # t = threading.Thread( 123 | # target=self._clear_expired_plugins, 124 | # args=(expire_ttl, ), 125 | # ) 126 | # t.setDaemon(True) 127 | # t.start() 128 | 129 | if setproctitle: 130 | ppid = os.getppid() 131 | if use_multiprocess: 132 | setproctitle.setproctitle("%s: Manager (ppid: %d)" % (title, ppid)) 133 | else: 134 | setproctitle.setproctitle("%s (ppid: %d)" % (title, ppid)) 135 | 136 | def _clear_expired_plugins(self, ttl): 137 | while True: 138 | if self.use_gevent: 139 | gsleep(ttl) 140 | else: 141 | time.sleep(ttl) 142 | 143 | self.i_lock.acquire() 144 | keys = list(self.instances.keys()) 145 | for iid in keys: 146 | instance = self.instances[iid] 147 | if instance.is_expired(ttl): 148 | self.logger.debug("cleanup instance #%d of %s" % (iid, instance.name)) 149 | del self.instances[iid] 150 | self.i_lock.release() 151 | 152 | def cleanup(self): 153 | if self.use_multiprocess: 154 | self._process_pool.terminate() 155 | self._process_pool.join() 156 | 157 | def _load_plugins(self): 158 | if not self.plugin_dir: 159 | raise PluginServerException("plugin server is not initialized, call SetPluginDir first") 160 | 161 | for p in os.listdir(self.plugin_dir): 162 | n, ext = os.path.splitext(p) 163 | if ext in exts: 164 | path = os.path.join(self.plugin_dir, p) 165 | try: 166 | mod = Module(n, path=path) 167 | except Exception as ex: 168 | self.logger.warn("error loading plugin \"%s\": %s" % (n, ex)) 169 | else: 170 | self.logger.debug("loaded plugin \"%s\" from %s" % (n, path)) 171 | self.plugins[n] = mod 172 | 173 | def set_plugin_dir(self, dir): 174 | if not os.path.exists(dir): 175 | raise PluginServerException("%s not exists" % dir) 176 | self.plugin_dir = dir 177 | return "ok" 178 | 179 | @locked_by("i_lock") 180 | def get_status(self, *_): 181 | plugin_status = {} 182 | for name in self.plugins: 183 | instances = [] 184 | for iid in self.instances: 185 | if self.instances[iid].name == name: 186 | i = self.instance_status(iid) 187 | instances.append(i) 188 | plugin = self.plugins[name] 189 | plugin_status[name] = { 190 | "Name": name, 191 | "Modtime": plugin.mtime, 192 | "LoadTime": plugin.load_time, 193 | "Instances": instances, 194 | "LastStartInstance": plugin.last_start_instance_time, 195 | "LastCloseInstance": plugin.last_close_instance_time, 196 | } 197 | return { 198 | "Pid": os.getpid(), 199 | "Plugins": plugin_status, 200 | } 201 | 202 | def get_plugin_info(self, name): 203 | if name not in self.plugins: 204 | raise PluginServerException("%s not initizlied" % name) 205 | 206 | plugin = self.plugins[name] 207 | 208 | info = { 209 | "Name": name, 210 | "Phases": plugin.phases, 211 | "Priority": plugin.priority, 212 | "Version": plugin.version, 213 | "Schema": { 214 | "name": name, 215 | "fields": [{ 216 | "config": { 217 | "type": "record", 218 | "fields": plugin.schema, 219 | } 220 | }], 221 | }, 222 | } 223 | return info 224 | 225 | @locked_by("i_lock") 226 | def start_instance(self, cfg): 227 | name = cfg['Name'] 228 | if name not in self.plugins: 229 | raise PluginServerException("%s not initizlied" % name) 230 | plugin = self.plugins[name] 231 | 232 | config = json.loads(cfg['Config']) 233 | iid = self.instance_id 234 | self.instances[iid] = plugin.new(config) 235 | self.instance_id = iid + 1 236 | 237 | self.logger.info("instance #%d of %s started" % (iid, name)) 238 | 239 | return { 240 | "Name": name, 241 | "Id": iid, 242 | "Config": config, 243 | "StartTime": time.time() 244 | } 245 | 246 | def instance_status(self, iid): 247 | if iid not in self.instances: 248 | # Note: Kong expect the error to start with "no plugin instance" 249 | raise PluginServerException("no plugin instance #%s" % iid) 250 | 251 | ins = self.instances[iid] 252 | 253 | return { 254 | "Name": ins.name, 255 | "Id": iid, 256 | "Config": ins.config, 257 | "StartTime": ins.start_time, 258 | } 259 | 260 | @locked_by("i_lock") 261 | def close_instance(self, iid): 262 | if iid not in self.instances: 263 | # Note: Kong expect the error to start with "no plugin instance" 264 | raise PluginServerException("no plugin instance #%s" % iid) 265 | 266 | ins = self.instances[iid] 267 | ins.close_cb() 268 | del self.instances[iid] 269 | 270 | return { 271 | "Name": ins.name, 272 | "Id": iid, 273 | "Config": ins.config, 274 | } 275 | 276 | @locked_by("e_lock") 277 | def handle_event(self, event): 278 | iid = event['InstanceId'] 279 | if iid not in self.instances: 280 | # Note: Kong expect the error to start with "no plugin instance" 281 | raise PluginServerException("no plugin instance #%s" % iid) 282 | 283 | instance = self.instances[iid] 284 | instance.reset_expire_ts() 285 | cls = instance.cls 286 | phase = event['EventName'] 287 | 288 | eid = self.event_id 289 | self.event_id = eid + 1 290 | 291 | if self.use_multiprocess: 292 | ch, child_ch = multiprocessing.Pipe(duplex=True) 293 | self._process_pool.apply_async( 294 | _handler_event_func, 295 | (getattr(cls, phase), child_ch, self.lua_style, ), 296 | ) 297 | elif self.use_gevent: 298 | # plugin communites to Kong (RPC client) in a reverse way 299 | ch = gChannel() 300 | 301 | gspawn(_handler_event_func, 302 | getattr(cls, phase), ch, self.lua_style, 303 | ) 304 | else: # normal threading mode 305 | ch = Queue() 306 | child_ch = Queue() 307 | ch.get, child_ch.get = child_ch.get, ch.get 308 | t = threading.Thread( 309 | target=_handler_event_func, 310 | args=(getattr(cls, phase), child_ch, self.lua_style, ), 311 | ) 312 | t.setDaemon(True) 313 | t.start() 314 | 315 | r = ch.get() 316 | if r != MSG_RET: 317 | self.events[eid] = ch 318 | 319 | instance.reset_expire_ts() 320 | 321 | return { 322 | "Data": r, 323 | "EventId": eid, 324 | } 325 | 326 | def _step(self, data, is_error): 327 | eid = data['EventId'] 328 | if eid not in self.events: 329 | raise PluginServerException("event id %s not found" % eid) 330 | dd = None 331 | if 'Data' in data: 332 | dd = data['Data'] 333 | ch = self.events[eid] 334 | if is_error: 335 | ch.put(( 336 | None, dd 337 | )) 338 | else: 339 | ch.put(( 340 | dd, None 341 | )) 342 | 343 | ret = ch.get() 344 | 345 | if ret == MSG_RET or (isinstance(ret, dict) and ret.get("Method", None) in terminal_methods): 346 | del self.events[eid] 347 | 348 | return { 349 | "Data": ret, 350 | "EventId": eid, 351 | } 352 | 353 | def step(self, data): 354 | return self._step(data, False) 355 | 356 | def step_error(self, data): 357 | return self._step(data, True) 358 | 359 | 360 | for entity in entities: 361 | setattr(PluginServer, 'step_' + entity, PluginServer.step) 362 | 363 | setattr(PluginServer, 'step_multi_map', PluginServer.step) 364 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | gevent 2 | msgpack 3 | setproctitle 4 | -------------------------------------------------------------------------------- /scripts/prepare_new_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -v 2 | 3 | new_v=$1 4 | if [[ -z $1 ]]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | if [[ $(uname) == "Darwin" ]]; then 10 | SED=gsed 11 | else 12 | SED=sed 13 | fi 14 | 15 | git reset 16 | old_v=$(python3 -c 'from kong_pdk.const import __version__ as v; print("%.1f.%d" % (v, v*100%10))') 17 | if [[ -z "$old_v" ]]; then 18 | echo "Unknown old version" 19 | exit 1 20 | fi 21 | 22 | echo "Creating new release $new_v from $old_v" 23 | git branch -D release/${new_v} 24 | git checkout -b release/${new_v} 25 | 26 | new_v_py=$(python3 -c "print('$new_v'.split('.')[0] + '.'+''.join('$new_v'.split('.')[1:]))") 27 | # file 28 | $SED -i "s/__version__ = .*/__version__ = $new_v_py/g" kong_pdk/const.py 29 | git add -u 30 | 31 | # changelog 32 | git commit -m "release: $new_v" 33 | git tag "$new_v" 34 | git-chglog --output CHANGELOG.md 35 | git add -u 36 | git tag -d "$new_v" 37 | git commit --amend -m "release: $new_v" 38 | 39 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E226,E302,E41,W503 3 | max-line-length = 160 4 | exclude = build,dist,kong_pdk/pdk/__init__.py,kong_pdk/pdk/kong/* 5 | max-complexity = 10 6 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import imp 4 | from setuptools import setup 5 | 6 | PROJ_NAME = 'kong-pdk' 7 | PACKAGE_NAME = 'kong_pdk' 8 | 9 | PROJ_METADATA = '%s.json' % PROJ_NAME 10 | 11 | here = os.path.abspath(os.path.dirname(__file__)) 12 | 13 | try: 14 | README = open(os.path.join(here, 'README.md')).read() 15 | except: # noqa: E722 do not use bare 'except 16 | README = "" 17 | try: 18 | CHANGELOG = open(os.path.join(here, 'CHANGELOG.md')).read() 19 | except: # noqa: E722 do not use bare 'except 20 | CHANGELOG = "" 21 | VERSION = "%.2f" % imp.load_source('version', os.path.join(here, '%s/const.py' % PACKAGE_NAME)).__version__ 22 | 23 | packages = [ 24 | 'kong_pdk', 25 | 'kong_pdk/pdk', 26 | 'kong_pdk/pdk/kong', 27 | 'kong_pdk/pdk/kong/client', 28 | 'kong_pdk/pdk/kong/ctx', 29 | 'kong_pdk/pdk/kong/nginx', 30 | 'kong_pdk/pdk/kong/service', 31 | 'kong_pdk/pdk/kong/enterprise_edition', 32 | ] 33 | requires = ['gevent', 'msgpack'] 34 | 35 | setup( 36 | name=PACKAGE_NAME, 37 | version=VERSION, 38 | description='Kong PDK for Python and Plugin Server', 39 | long_description=README + '\n\n' + CHANGELOG, 40 | long_description_content_type="text/markdown", 41 | author='Kong', 42 | url='https://github.com/Kong/kong-python-pdk', 43 | packages=packages, 44 | package_dir={'requests': 'requests'}, 45 | include_package_data=True, 46 | install_requires=requires, 47 | license="Apache-2.0", 48 | license_files=('LICENSE',), 49 | zip_safe=False, 50 | classifiers=( 51 | 'License :: OSI Approved :: Apache Software License', 52 | 'Programming Language :: Python', 53 | 'Programming Language :: Python :: 2.7', 54 | 'Programming Language :: Python :: 3', 55 | 'Programming Language :: Python :: 3.6', 56 | 'Programming Language :: Python :: 3.7', 57 | 'Programming Language :: Python :: 3.8', 58 | 'Programming Language :: Python :: 3.9', 59 | 'Programming Language :: Python :: Implementation :: CPython' 60 | ), 61 | requires=requires, 62 | entry_points={'console_scripts': ["kong-python-pluginserver = kong_pdk.cli:start_server"]}, 63 | package_data={"kong_pdk": ["*.pyi", "**/*.pyi", "**/**/*.pyi", "**/**/**/*.pyi"]} 64 | ) 65 | --------------------------------------------------------------------------------