aio-kong 3.6.0__py3-none-any.whl → 3.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aio_kong-3.6.0.dist-info → aio_kong-3.7.0.dist-info}/LICENSE +1 -1
- {aio_kong-3.6.0.dist-info → aio_kong-3.7.0.dist-info}/METADATA +3 -2
- {aio_kong-3.6.0.dist-info → aio_kong-3.7.0.dist-info}/RECORD +9 -9
- kong/__init__.py +1 -1
- kong/cli.py +167 -33
- kong/client.py +9 -7
- kong/services.py +6 -2
- {aio_kong-3.6.0.dist-info → aio_kong-3.7.0.dist-info}/WHEEL +0 -0
- {aio_kong-3.6.0.dist-info → aio_kong-3.7.0.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: aio-kong
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.7.0
|
4
4
|
Summary: Asynchronous Kong Client
|
5
5
|
License: BSD-3-Clause
|
6
6
|
Author: Luca Sbardella
|
@@ -16,6 +16,7 @@ Provides-Extra: cli
|
|
16
16
|
Requires-Dist: PyYAML (>=6.0) ; extra == "cli"
|
17
17
|
Requires-Dist: aiohttp (>=3.9.5)
|
18
18
|
Requires-Dist: click (>=8.1.3) ; extra == "cli"
|
19
|
+
Requires-Dist: rich (>=14.0.0,<15.0.0) ; extra == "cli"
|
19
20
|
Project-URL: Issues, https://github.com/quantmind/aio-kong/issues
|
20
21
|
Project-URL: Repository, https://github.com/quantmind/aio-kong
|
21
22
|
Description-Content-Type: text/markdown
|
@@ -109,7 +110,7 @@ pip install aio-kong[cli]
|
|
109
110
|
and to run the cli tool, you can use the following command:
|
110
111
|
|
111
112
|
```
|
112
|
-
kongfig --
|
113
|
+
kongfig --help
|
113
114
|
```
|
114
115
|
|
115
116
|
[kong]: https://github.com/Kong/kong
|
@@ -1,19 +1,19 @@
|
|
1
|
-
kong/__init__.py,sha256=
|
1
|
+
kong/__init__.py,sha256=eqr9UIVWumESkCzgs9mvIiJ_8VyEtp4do1jmLBlkLrM,54
|
2
2
|
kong/acls.py,sha256=1HR66CKp6SVOmtauXOnj77moLMeHfL7gsfBRwlbJK1U,127
|
3
3
|
kong/auths.py,sha256=1aNSQ6Sw5rjh8lbJppH9GOXVMG6KL7-bO4P75MsFKJU,2337
|
4
4
|
kong/certificates.py,sha256=7QYS0BLg5QKyjdi1dUDGErXBZHQK4ARv_iYFluXX3RM,275
|
5
|
-
kong/cli.py,sha256=
|
6
|
-
kong/client.py,sha256=
|
5
|
+
kong/cli.py,sha256=9_HiFC2FxhNpCufkg86E00k1nKjorp4O8Bss6ZmLdx8,5649
|
6
|
+
kong/client.py,sha256=T8cTcpCMZ4Lm_BFta56sFintV3vqgQFr5_4kwUi7LDc,4010
|
7
7
|
kong/components.py,sha256=ZT3bSsfFzKOH-ipXFDFAsMCjWydqqCGsakbhB26CBfM,5471
|
8
8
|
kong/consumers.py,sha256=SDR9W6zY3PAIq_iC0EOSKbn0lyTl4C7WbsyM7MA7hLs,2715
|
9
9
|
kong/plugins.py,sha256=GmuL-EnrpHeZEzv0bjDvXE0oTtG3DYWpGi0AZHMmY7E,2730
|
10
10
|
kong/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
11
|
kong/routes.py,sha256=e1n5hIIirwkAVacbFnJ_C1AwQN_IC10gISyXU8ex-g0,1493
|
12
|
-
kong/services.py,sha256=
|
12
|
+
kong/services.py,sha256=fVArH4m7DfTfgBD7n1OGUArE-P6ZNJUP_zPPM1sBNRo,2616
|
13
13
|
kong/snis.py,sha256=QxjHFUtMGvlBcfCdiye5hQ9n8D1PRSQQThqaB-OekLI,716
|
14
14
|
kong/utils.py,sha256=Uoe5DRclN-t1DX8AvwgidYn8GMMvLUXVjMgzqs6mUAE,932
|
15
|
-
aio_kong-3.
|
16
|
-
aio_kong-3.
|
17
|
-
aio_kong-3.
|
18
|
-
aio_kong-3.
|
19
|
-
aio_kong-3.
|
15
|
+
aio_kong-3.7.0.dist-info/LICENSE,sha256=hTYbUZ810IUK9Cr9n0_PpfL7rpjDPSC9_CaS2014bdg,1466
|
16
|
+
aio_kong-3.7.0.dist-info/METADATA,sha256=WZipQ802pCcb_VOJBVz0NQZzHi2br_HF3R7z2U4S44I,3257
|
17
|
+
aio_kong-3.7.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
18
|
+
aio_kong-3.7.0.dist-info/entry_points.txt,sha256=Wp_emFiShNNMtqwMxwwdo7qQDiLMxYqZwk9sP4YbEp4,41
|
19
|
+
aio_kong-3.7.0.dist-info/RECORD,,
|
kong/__init__.py
CHANGED
kong/cli.py
CHANGED
@@ -4,59 +4,167 @@ from typing import Any, cast
|
|
4
4
|
|
5
5
|
import click
|
6
6
|
import yaml as _yaml
|
7
|
+
from rich.console import Console
|
8
|
+
from rich.table import Table
|
7
9
|
|
8
10
|
from . import __version__
|
9
|
-
from .client import Kong, KongError
|
11
|
+
from .client import Kong, KongError, default_admin_url
|
12
|
+
from .components import KongEntity
|
10
13
|
from .consumers import Consumer
|
11
14
|
from .utils import local_ip
|
12
15
|
|
16
|
+
admin_url = click.option(
|
17
|
+
"--url", default=default_admin_url(), help="Kong Admin URL", show_default=True
|
18
|
+
)
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@click.
|
18
|
-
|
20
|
+
as_json = click.option("--json", default=False, is_flag=True, help="Output as JSON")
|
21
|
+
|
22
|
+
|
23
|
+
@click.group()
|
24
|
+
@click.version_option(version=__version__)
|
25
|
+
def kong() -> None:
|
26
|
+
"""Kong CLI - Manage Kong Gateway configurations."""
|
27
|
+
pass
|
28
|
+
|
29
|
+
|
30
|
+
@kong.command()
|
31
|
+
@click.argument(
|
32
|
+
"yaml",
|
33
|
+
type=click.File("r"),
|
19
34
|
)
|
20
|
-
@click.option("--yaml", type=click.File("r"), help="Yaml configuration to upload")
|
21
35
|
@click.option(
|
22
|
-
"--clear",
|
36
|
+
"--clear",
|
37
|
+
default=False,
|
38
|
+
is_flag=True,
|
39
|
+
help="Clear objects not in configuration",
|
23
40
|
)
|
24
|
-
@
|
25
|
-
def
|
26
|
-
|
27
|
-
version: bool,
|
28
|
-
ip: bool,
|
29
|
-
key_auth: str,
|
30
|
-
yaml: click.File | None,
|
41
|
+
@admin_url
|
42
|
+
def yaml(
|
43
|
+
yaml: click.File,
|
31
44
|
clear: bool,
|
45
|
+
url: str,
|
32
46
|
) -> None:
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
click.echo(ctx.get_help())
|
47
|
+
"Upload a configuration from a yaml file"
|
48
|
+
asyncio.run(_yml(yaml, clear, url))
|
49
|
+
|
50
|
+
|
51
|
+
@kong.command()
|
52
|
+
def ip() -> None:
|
53
|
+
"Show local IP address"
|
54
|
+
click.echo(local_ip())
|
55
|
+
|
43
56
|
|
57
|
+
@kong.command()
|
58
|
+
@admin_url
|
59
|
+
@as_json
|
60
|
+
def services(url: str, json: bool) -> None:
|
61
|
+
"Display services"
|
62
|
+
asyncio.run(_services(url, as_json=json))
|
44
63
|
|
45
|
-
def _run(coro: Any) -> None:
|
46
|
-
asyncio.get_event_loop().run_until_complete(coro)
|
47
64
|
|
65
|
+
@kong.command()
|
66
|
+
@click.argument("service")
|
67
|
+
@admin_url
|
68
|
+
@as_json
|
69
|
+
def routes(service: str, url: str, json: bool) -> None:
|
70
|
+
"Display routes for a service"
|
71
|
+
asyncio.run(_routes(service, url, as_json=json))
|
48
72
|
|
49
|
-
|
50
|
-
|
73
|
+
|
74
|
+
@kong.command()
|
75
|
+
@admin_url
|
76
|
+
@as_json
|
77
|
+
def consumers(url: str, json: bool) -> None:
|
78
|
+
"Display consumers"
|
79
|
+
asyncio.run(_consumers(url, as_json=json))
|
80
|
+
|
81
|
+
|
82
|
+
@kong.command()
|
83
|
+
@click.argument("consumer")
|
84
|
+
@admin_url
|
85
|
+
def key_auth(consumer: str, url: str) -> None:
|
86
|
+
"Create or display an authentication key for a consumer"
|
87
|
+
asyncio.run(_auth_key(consumer, url))
|
88
|
+
|
89
|
+
|
90
|
+
async def _yml(yaml: Any, clear: bool, url: str) -> None:
|
91
|
+
async with Kong(url=url) as cli:
|
51
92
|
try:
|
52
93
|
result = await cli.apply_json(_yaml.safe_load(yaml), clear=clear)
|
53
|
-
|
94
|
+
display_json(result)
|
54
95
|
except KongError as exc:
|
55
96
|
raise click.ClickException(str(exc)) from None
|
56
97
|
|
57
98
|
|
58
|
-
async def
|
59
|
-
async with Kong() as cli:
|
99
|
+
async def _services(url: str, as_json: bool = False) -> None:
|
100
|
+
async with Kong(url=url) as cli:
|
101
|
+
try:
|
102
|
+
services = await cli.services.get_full_list()
|
103
|
+
except KongError as exc:
|
104
|
+
raise click.ClickException(str(exc)) from None
|
105
|
+
if as_json:
|
106
|
+
display_json(services)
|
107
|
+
return
|
108
|
+
table = Table(title="Services")
|
109
|
+
columns = ["Name", "Host", "Port", "Protocol", "Path", "Tags", "ID"]
|
110
|
+
for column in columns:
|
111
|
+
table.add_column(column)
|
112
|
+
for s in sorted(services, key=lambda s: s.name):
|
113
|
+
table.add_row(*[str_value(s.data, column) for column in columns])
|
114
|
+
console = Console()
|
115
|
+
console.print(table)
|
116
|
+
|
117
|
+
|
118
|
+
async def _routes(service: str, url: str, as_json: bool = False) -> None:
|
119
|
+
async with Kong(url=url) as cli:
|
120
|
+
try:
|
121
|
+
svc = await cli.services.get(service)
|
122
|
+
routes = await svc.routes.get_full_list()
|
123
|
+
except KongError as exc:
|
124
|
+
raise click.ClickException(str(exc)) from None
|
125
|
+
if as_json:
|
126
|
+
display_json(routes)
|
127
|
+
return
|
128
|
+
table = Table(title="Services")
|
129
|
+
columns = [
|
130
|
+
"Name",
|
131
|
+
"Hosts",
|
132
|
+
"Protocols",
|
133
|
+
"Path",
|
134
|
+
"Tags",
|
135
|
+
"Strip Path",
|
136
|
+
"Preserve Host",
|
137
|
+
"ID",
|
138
|
+
]
|
139
|
+
for column in columns:
|
140
|
+
table.add_column(column)
|
141
|
+
for s in sorted(routes, key=lambda s: s.name):
|
142
|
+
table.add_row(*[str_value(s.data, column) for column in columns])
|
143
|
+
console = Console()
|
144
|
+
console.print(table)
|
145
|
+
|
146
|
+
|
147
|
+
async def _consumers(url: str, as_json: bool = False) -> None:
|
148
|
+
async with Kong(url=url) as cli:
|
149
|
+
try:
|
150
|
+
consumers = await cli.consumers.get_full_list()
|
151
|
+
except KongError as exc:
|
152
|
+
raise click.ClickException(str(exc)) from None
|
153
|
+
if as_json:
|
154
|
+
display_json(consumers)
|
155
|
+
return
|
156
|
+
table = Table(title="Consumers")
|
157
|
+
columns = ["Username", "ID", "Custom ID", "Tags"]
|
158
|
+
for column in columns:
|
159
|
+
table.add_column(column)
|
160
|
+
for c in sorted(consumers, key=lambda s: s.name):
|
161
|
+
table.add_row(*[str_value(c.data, column) for column in columns])
|
162
|
+
console = Console()
|
163
|
+
console.print(table)
|
164
|
+
|
165
|
+
|
166
|
+
async def _auth_key(consumer: str, admin_url: str) -> None:
|
167
|
+
async with Kong(url=admin_url) as cli:
|
60
168
|
try:
|
61
169
|
c = cast(Consumer, await cli.consumers.get(consumer))
|
62
170
|
keys = await c.keyauths.get_list()
|
@@ -64,6 +172,32 @@ async def _auth_key(consumer: str) -> None:
|
|
64
172
|
key = keys[0]
|
65
173
|
else:
|
66
174
|
key = await c.keyauths.create()
|
67
|
-
|
175
|
+
display_json(key)
|
68
176
|
except KongError as exc:
|
69
177
|
raise click.ClickException(str(exc)) from None
|
178
|
+
|
179
|
+
|
180
|
+
def str_value(data: dict, key: str) -> str:
|
181
|
+
key = key.lower().replace(" ", "_")
|
182
|
+
value = data.get(key)
|
183
|
+
if value is None:
|
184
|
+
return ""
|
185
|
+
elif isinstance(value, bool):
|
186
|
+
return ":white_check_mark:" if value else "[red]:x:"
|
187
|
+
elif isinstance(value, list):
|
188
|
+
return ", ".join(str(v) for v in value)
|
189
|
+
else:
|
190
|
+
return str(value)
|
191
|
+
|
192
|
+
|
193
|
+
def display_json(data: Any) -> None:
|
194
|
+
"""Display data as JSON."""
|
195
|
+
click.echo(json.dumps(data, indent=2, default=kong_entity))
|
196
|
+
|
197
|
+
|
198
|
+
def kong_entity(obj: Any) -> Any:
|
199
|
+
if isinstance(obj, KongEntity):
|
200
|
+
return obj.data
|
201
|
+
raise TypeError(
|
202
|
+
f"Cannot serialize {type(obj).__name__} to JSON"
|
203
|
+
) # pragma: no cover
|
kong/client.py
CHANGED
@@ -9,7 +9,7 @@ from aiohttp import ClientResponse, ClientSession
|
|
9
9
|
from . import __version__
|
10
10
|
from .acls import Acl, Acls
|
11
11
|
from .certificates import Certificate, Certificates
|
12
|
-
from .components import KongError, KongResponseError
|
12
|
+
from .components import CrudComponent, KongError, KongResponseError
|
13
13
|
from .consumers import Consumer, Consumers
|
14
14
|
from .plugins import Plugin, Plugins
|
15
15
|
from .routes import Route, Routes
|
@@ -23,22 +23,24 @@ DEFAULT_USER_AGENT = (
|
|
23
23
|
)
|
24
24
|
|
25
25
|
|
26
|
+
def default_admin_url() -> str:
|
27
|
+
"""Return the default Kong admin URL."""
|
28
|
+
return os.getenv("KONG_ADMIN_URL", os.getenv("KONG_URL", "http://127.0.0.1:8001"))
|
29
|
+
|
30
|
+
|
26
31
|
class Kong:
|
27
32
|
"""Kong client"""
|
28
33
|
|
29
|
-
url: str = os.getenv(
|
30
|
-
"KONG_ADMIN_URL", os.getenv("KONG_URL", "http://127.0.0.1:8001")
|
31
|
-
)
|
32
34
|
content_type: str = "application/json, text/*; q=0.5"
|
33
35
|
|
34
36
|
def __init__(
|
35
37
|
self,
|
36
|
-
url: str =
|
38
|
+
url: str | None = None,
|
37
39
|
session: ClientSession | None = None,
|
38
40
|
request_kwargs: dict | None = None,
|
39
41
|
user_agent: str = DEFAULT_USER_AGENT,
|
40
42
|
) -> None:
|
41
|
-
self.url = url or
|
43
|
+
self.url = url or default_admin_url()
|
42
44
|
self.session = session
|
43
45
|
self.user_agent = user_agent
|
44
46
|
self.request_kwargs = request_kwargs or {}
|
@@ -107,7 +109,7 @@ class Kong:
|
|
107
109
|
if not isinstance(data, list):
|
108
110
|
data = [data]
|
109
111
|
o = getattr(self, name)
|
110
|
-
if not o:
|
112
|
+
if not isinstance(o, CrudComponent):
|
111
113
|
raise KongError("Kong object %s not available" % name)
|
112
114
|
result[name] = await o.apply_json(data, clear=clear)
|
113
115
|
return result
|
kong/services.py
CHANGED
@@ -3,7 +3,7 @@ from typing import cast
|
|
3
3
|
from .components import UUID, CrudComponent, JsonType, KongError
|
4
4
|
from .plugins import KongEntityWithPlugins
|
5
5
|
from .routes import Route, Routes
|
6
|
-
from .utils import local_ip
|
6
|
+
from .utils import local_ip, uid
|
7
7
|
|
8
8
|
REMOVE = frozenset(("absent", "remove"))
|
9
9
|
LOCAL_HOST = frozenset(("localhost", "127.0.0.1"))
|
@@ -20,12 +20,16 @@ class Service(KongEntityWithPlugins):
|
|
20
20
|
def host(self) -> str:
|
21
21
|
return self.data.get("host", "")
|
22
22
|
|
23
|
+
@property
|
24
|
+
def protocol(self) -> str:
|
25
|
+
return self.data.get("protocol", "")
|
26
|
+
|
23
27
|
|
24
28
|
class Services(CrudComponent[Service]):
|
25
29
|
"""Kong Services"""
|
26
30
|
|
27
31
|
async def delete(self, id_: str | UUID) -> bool:
|
28
|
-
srv = cast(Service, self.wrap({"id": id_}))
|
32
|
+
srv = cast(Service, self.wrap({"id": uid(id_)}))
|
29
33
|
await srv.routes.delete_all()
|
30
34
|
await srv.plugins.delete_all()
|
31
35
|
return await super().delete(id_)
|
File without changes
|
File without changes
|