appmesh 1.4.2__py3-none-any.whl → 1.4.4__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.
- appmesh/http_client.py +21 -111
- {appmesh-1.4.2.dist-info → appmesh-1.4.4.dist-info}/METADATA +15 -3
- {appmesh-1.4.2.dist-info → appmesh-1.4.4.dist-info}/RECORD +5 -5
- {appmesh-1.4.2.dist-info → appmesh-1.4.4.dist-info}/WHEEL +1 -1
- {appmesh-1.4.2.dist-info → appmesh-1.4.4.dist-info}/top_level.txt +0 -0
appmesh/http_client.py
CHANGED
@@ -7,7 +7,7 @@ import os
|
|
7
7
|
from datetime import datetime
|
8
8
|
from enum import Enum, unique
|
9
9
|
from http import HTTPStatus
|
10
|
-
from typing import Tuple, Union
|
10
|
+
from typing import Optional, Tuple, Union
|
11
11
|
from urllib import parse
|
12
12
|
import aniso8601
|
13
13
|
import requests
|
@@ -107,6 +107,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
107
107
|
DEFAULT_SSL_CLIENT_CERT_PATH = "/opt/appmesh/ssl/client.pem"
|
108
108
|
DEFAULT_SSL_CLIENT_KEY_PATH = "/opt/appmesh/ssl/client-key.pem"
|
109
109
|
|
110
|
+
DEFAULT_JWT_AUDIENCE = "appmesh-service"
|
111
|
+
|
110
112
|
JSON_KEY_MESSAGE = "message"
|
111
113
|
HTTP_USER_AGENT = "appmesh/python"
|
112
114
|
HTTP_HEADER_KEY_USER_AGENT = "User-Agent"
|
@@ -251,7 +253,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
251
253
|
########################################
|
252
254
|
# Security
|
253
255
|
########################################
|
254
|
-
def login(self, user_name: str, user_pwd: str, totp_code="", timeout_seconds=DURATION_ONE_WEEK_ISO) -> str:
|
256
|
+
def login(self, user_name: str, user_pwd: str, totp_code: Optional[str] = "", timeout_seconds: Union[str, int] = DURATION_ONE_WEEK_ISO, audience: Optional[str] = None) -> str:
|
255
257
|
"""Login with user name and password
|
256
258
|
|
257
259
|
Args:
|
@@ -259,6 +261,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
259
261
|
user_pwd (str): the password of the user.
|
260
262
|
totp_code (str, optional): the TOTP code if enabled for the user.
|
261
263
|
timeout_seconds (int | str, optional): token expire timeout of seconds. support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P1W').
|
264
|
+
audience (str, optional): The audience of the JWT token, should be available by JWT service configuration (default is 'appmesh-service').
|
262
265
|
|
263
266
|
Returns:
|
264
267
|
str: JWT token.
|
@@ -270,6 +273,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
270
273
|
header={
|
271
274
|
"Authorization": "Basic " + base64.b64encode((user_name + ":" + user_pwd).encode()).decode(),
|
272
275
|
"Expire-Seconds": self._parse_duration(timeout_seconds),
|
276
|
+
**({"Audience": audience} if audience else {}),
|
273
277
|
},
|
274
278
|
)
|
275
279
|
if resp.status_code == HTTPStatus.OK:
|
@@ -308,11 +312,11 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
308
312
|
self.jwt_token = None
|
309
313
|
return resp.status_code == HTTPStatus.OK
|
310
314
|
|
311
|
-
def authentication(self, token: str, permission=None) -> bool:
|
315
|
+
def authentication(self, token: str, permission: Optional[str] = None, audience: Optional[str] = None) -> bool:
|
312
316
|
"""Deprecated: Use authenticate() instead."""
|
313
317
|
return self.authenticate(token, permission)
|
314
318
|
|
315
|
-
def authenticate(self, token: str, permission: str = None) -> bool:
|
319
|
+
def authenticate(self, token: str, permission: Optional[str] = None, audience: Optional[str] = None) -> bool:
|
316
320
|
"""Authenticate with a token and verify permission if specified.
|
317
321
|
|
318
322
|
Args:
|
@@ -321,15 +325,17 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
321
325
|
permission ID can be:
|
322
326
|
- pre-defined by App Mesh from security.yaml (e.g 'app-view', 'app-delete')
|
323
327
|
- defined by input from role_update() or security.yaml
|
328
|
+
audience (str, optional):The audience of the JWT token used to verify the target service.
|
324
329
|
|
325
330
|
Returns:
|
326
331
|
bool: authentication success or failure.
|
327
332
|
"""
|
328
333
|
old_token = self.jwt_token
|
329
334
|
self.jwt_token = token
|
330
|
-
headers = {
|
331
|
-
|
332
|
-
|
335
|
+
headers = {
|
336
|
+
**({"Audience": audience} if audience else {}),
|
337
|
+
**({"Auth-Permission": permission} if permission else {}),
|
338
|
+
}
|
333
339
|
resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/auth", header=headers)
|
334
340
|
if resp.status_code != HTTPStatus.OK:
|
335
341
|
self.jwt_token = old_token
|
@@ -343,7 +349,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
343
349
|
timeout_seconds (int | str, optional): token expire timeout of seconds. support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P1W').
|
344
350
|
|
345
351
|
Returns:
|
346
|
-
str: The new JWT token if renew success,
|
352
|
+
str: The new JWT token if renew success, the old token will be blocked.
|
347
353
|
"""
|
348
354
|
assert self.jwt_token
|
349
355
|
resp = self._request_http(
|
@@ -378,16 +384,19 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
378
384
|
totp_code (str): TOTP code
|
379
385
|
|
380
386
|
Returns:
|
381
|
-
|
387
|
+
str: The new JWT token if setup success, the old token will be blocked.
|
382
388
|
"""
|
383
389
|
resp = self._request_http(
|
384
390
|
method=AppMeshClient.Method.POST,
|
385
391
|
path="/appmesh/totp/setup",
|
386
392
|
header={"Totp": totp_code},
|
387
393
|
)
|
388
|
-
if resp.status_code
|
394
|
+
if resp.status_code == HTTPStatus.OK:
|
395
|
+
if "Access-Token" in resp.json():
|
396
|
+
self.jwt_token = resp.json()["Access-Token"]
|
397
|
+
return self.jwt_token
|
398
|
+
else:
|
389
399
|
raise Exception(resp.text)
|
390
|
-
return resp.status_code == HTTPStatus.OK
|
391
400
|
|
392
401
|
def disable_totp(self, user: str = "self") -> bool:
|
393
402
|
"""Disable 2FA for the specified user.
|
@@ -574,105 +583,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
574
583
|
raise Exception(resp.text)
|
575
584
|
return resp.status_code == HTTPStatus.OK
|
576
585
|
|
577
|
-
########################################
|
578
|
-
# Cloud management
|
579
|
-
########################################
|
580
|
-
def view_all_cloud_apps(self) -> dict:
|
581
|
-
"""Get information about all cloud applications.
|
582
|
-
|
583
|
-
Returns:
|
584
|
-
dict: cloud applications in JSON format.
|
585
|
-
"""
|
586
|
-
resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/cloud/applications")
|
587
|
-
if resp.status_code != HTTPStatus.OK:
|
588
|
-
raise Exception(resp.text)
|
589
|
-
return resp.json()
|
590
|
-
|
591
|
-
def view_cloud_app(self, app_name: str) -> dict:
|
592
|
-
"""Get information about a specific cloud application.
|
593
|
-
|
594
|
-
Args:
|
595
|
-
app_name (str): the application name.
|
596
|
-
|
597
|
-
Returns:
|
598
|
-
dict: application in JSON format.
|
599
|
-
"""
|
600
|
-
resp = self._request_http(AppMeshClient.Method.GET, path=f"/appmesh/cloud/app/{app_name}")
|
601
|
-
if resp.status_code != HTTPStatus.OK:
|
602
|
-
raise Exception(resp.text)
|
603
|
-
return resp.json()
|
604
|
-
|
605
|
-
def get_cloud_app_output(self, app_name: str, host_name: str, stdout_position: int = 0, stdout_index: int = 0, stdout_maxsize: int = 10240, process_uuid: str = ""):
|
606
|
-
"""Get the stdout/stderr of a cloud application.
|
607
|
-
|
608
|
-
Args:
|
609
|
-
app_name (str): the application name
|
610
|
-
host_name (str): the target host name where the application is running
|
611
|
-
stdout_position (int, optional): start read position, 0 means start from beginning.
|
612
|
-
stdout_index (int, optional): index of history process stdout, 0 means get from current running process,
|
613
|
-
the stdout number depends on 'stdout_cache_size' of the application.
|
614
|
-
stdout_maxsize (int, optional): max buffer size to read.
|
615
|
-
process_uuid (str, optional): used to get the specified process.
|
616
|
-
|
617
|
-
Returns:
|
618
|
-
bool: success or failure.
|
619
|
-
str: output string.
|
620
|
-
int or None: current read position.
|
621
|
-
int or None: process exit code.
|
622
|
-
"""
|
623
|
-
resp = self._request_http(
|
624
|
-
AppMeshClient.Method.GET,
|
625
|
-
path=f"/appmesh/cloud/app/{app_name}/output/{host_name}",
|
626
|
-
query={
|
627
|
-
"stdout_position": str(stdout_position),
|
628
|
-
"stdout_index": str(stdout_index),
|
629
|
-
"stdout_maxsize": str(stdout_maxsize),
|
630
|
-
"process_uuid": process_uuid,
|
631
|
-
},
|
632
|
-
)
|
633
|
-
out_position = int(resp.headers["Output-Position"]) if "Output-Position" in resp.headers else None
|
634
|
-
exit_code = int(resp.headers["Exit-Code"]) if "Exit-Code" in resp.headers else None
|
635
|
-
return (resp.status_code == HTTPStatus.OK), resp.text, out_position, exit_code
|
636
|
-
|
637
|
-
def delete_cloud_app(self, app_name: str) -> bool:
|
638
|
-
"""Delete a cloud application.
|
639
|
-
|
640
|
-
Args:
|
641
|
-
app_name (str): The application name for cloud
|
642
|
-
|
643
|
-
Returns:
|
644
|
-
bool: success or failure.
|
645
|
-
"""
|
646
|
-
resp = self._request_http(AppMeshClient.Method.DELETE, path=f"/appmesh/cloud/app/{app_name}")
|
647
|
-
if resp.status_code != HTTPStatus.OK:
|
648
|
-
raise Exception(resp.text)
|
649
|
-
return resp.status_code == HTTPStatus.OK
|
650
|
-
|
651
|
-
def add_cloud_app(self, app_json: dict) -> dict:
|
652
|
-
"""Add a new cloud application.
|
653
|
-
|
654
|
-
Args:
|
655
|
-
app_json (dict): the cloud application definition with replication, condition and resource requirement
|
656
|
-
|
657
|
-
Returns:
|
658
|
-
dict: cluster application json.
|
659
|
-
"""
|
660
|
-
resp = self._request_http(AppMeshClient.Method.PUT, path=f"/appmesh/cloud/app/{app_json['content']['name']}", body=app_json)
|
661
|
-
if resp.status_code != HTTPStatus.OK:
|
662
|
-
raise Exception(resp.text)
|
663
|
-
return resp.json()
|
664
|
-
|
665
|
-
def view_cloud_nodes(self) -> dict:
|
666
|
-
"""Get a list of cluster nodes.
|
667
|
-
|
668
|
-
Returns:
|
669
|
-
dict: cluster node list json.
|
670
|
-
"""
|
671
|
-
resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/cloud/nodes")
|
672
|
-
if resp.status_code != HTTPStatus.OK:
|
673
|
-
raise Exception(resp.text)
|
674
|
-
return resp.json()
|
675
|
-
|
676
586
|
########################################
|
677
587
|
# Configuration
|
678
588
|
########################################
|
@@ -885,7 +795,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
885
795
|
|
886
796
|
Args:
|
887
797
|
role_name (str): the role name.
|
888
|
-
role_permission_json (dict): role permission definition array, e.g: ["app-control", "app-delete"
|
798
|
+
role_permission_json (dict): role permission definition array, e.g: ["app-control", "app-delete"]
|
889
799
|
|
890
800
|
Returns:
|
891
801
|
bool: success or failure.
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: appmesh
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.4
|
4
4
|
Summary: Client SDK for App Mesh
|
5
5
|
Home-page: https://github.com/laoshanxi/app-mesh
|
6
6
|
Author: laoshanxi
|
@@ -16,6 +16,17 @@ Requires-Dist: requests
|
|
16
16
|
Requires-Dist: msgpack
|
17
17
|
Requires-Dist: requests_toolbelt
|
18
18
|
Requires-Dist: aniso8601
|
19
|
+
Dynamic: author
|
20
|
+
Dynamic: author-email
|
21
|
+
Dynamic: classifier
|
22
|
+
Dynamic: description
|
23
|
+
Dynamic: description-content-type
|
24
|
+
Dynamic: home-page
|
25
|
+
Dynamic: keywords
|
26
|
+
Dynamic: license
|
27
|
+
Dynamic: requires-dist
|
28
|
+
Dynamic: requires-python
|
29
|
+
Dynamic: summary
|
19
30
|
|
20
31
|
[![language.badge]][language.url] [![standard.badge]][standard.url] [![release.badge]][release.url] [![pypi.badge]][pypi.url] [![unittest.badge]][unittest.url] [![docker.badge]][docker.url] [![cockpit.badge]][cockpit.url]
|
21
32
|
[](https://app-mesh.readthedocs.io/en/latest/?badge=latest) [](https://gitter.im/app-mesh/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
@@ -52,7 +63,7 @@ Refer to the [Installation doc](https://app-mesh.readthedocs.io/en/latest/Instal
|
|
52
63
|
- [Read the Docs](https://app-mesh.readthedocs.io/)
|
53
64
|
- [REST API](https://app-mesh.readthedocs.io/en/latest/Development.html#rest-apis)
|
54
65
|
- [Command lines](https://app-mesh.readthedocs.io/en/latest/CLI.html)
|
55
|
-
- [Security](https://app-mesh.readthedocs.io/en/latest/
|
66
|
+
- [Security](https://app-mesh.readthedocs.io/en/latest/Security.html)
|
56
67
|
|
57
68
|
## Comparison
|
58
69
|
|
@@ -111,6 +122,7 @@ Refer to the [Installation doc](https://app-mesh.readthedocs.io/en/latest/Instal
|
|
111
122
|
- [Remote execute](https://app-mesh.readthedocs.io/en/latest/success/remote_run_cli_and_python.html)
|
112
123
|
- [Python parallel run](https://app-mesh.readthedocs.io/en/latest/success/python_parallel_run.html)
|
113
124
|
- [Secure consul cluster](https://app-mesh.readthedocs.io/en/latest/success/secure_consul_cluster.html)
|
125
|
+
- [JWT service with REST and UI](https://github.com/laoshanxi/app-mesh/blob/main/script/docker-compose-auth-service.yaml)
|
114
126
|
|
115
127
|
---
|
116
128
|
|
@@ -3,11 +3,11 @@ appmesh/app.py,sha256=9Q-SOOej-MH13BU5Dv2iTa-p-sECCJQp6ZX9DjWWmwE,10526
|
|
3
3
|
appmesh/app_output.py,sha256=JK_TMKgjvaw4n_ys_vmN5S4MyWVZpmD7NlKz_UyMIM8,1015
|
4
4
|
appmesh/app_run.py,sha256=9ISKGZ3k3kkbQvSsPfRfkOLqD9xhbqNOM7ork9F4w9c,1712
|
5
5
|
appmesh/appmesh_client.py,sha256=0ltkqHZUq094gKneYmC0bEZCP0X9kHTp9fccKdWFWP0,339
|
6
|
-
appmesh/http_client.py,sha256=
|
6
|
+
appmesh/http_client.py,sha256=wd-H4vyHlLSCy1N8znHMf3-Zwgs7ow6-voWUludtMdA,44364
|
7
7
|
appmesh/tcp_client.py,sha256=RkHl5s8jE333BJOgxJqJ_fvjbdRQza7ciV49vLT6YO4,10923
|
8
8
|
appmesh/tcp_messages.py,sha256=w1Kehz_aX4X2CYAUsy9mFVJRhxnLQwwc6L58W4YkQqs,969
|
9
9
|
appmesh/tcp_transport.py,sha256=UMGby2oKV4k7lyXZUMSOe2Je34fb1w7nTkxEpatKLKg,7256
|
10
|
-
appmesh-1.4.
|
11
|
-
appmesh-1.4.
|
12
|
-
appmesh-1.4.
|
13
|
-
appmesh-1.4.
|
10
|
+
appmesh-1.4.4.dist-info/METADATA,sha256=lV4XJMIWhe2jKNV5NOv_q6SFdVrzN1BZLoVrvEd90Is,11501
|
11
|
+
appmesh-1.4.4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
12
|
+
appmesh-1.4.4.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
13
|
+
appmesh-1.4.4.dist-info/RECORD,,
|
File without changes
|