appmesh 1.2.6__py3-none-any.whl → 1.3.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.
- appmesh/appmesh_client.py +33 -25
- {appmesh-1.2.6.dist-info → appmesh-1.3.0.dist-info}/METADATA +3 -3
- appmesh-1.3.0.dist-info/RECORD +6 -0
- {appmesh-1.2.6.dist-info → appmesh-1.3.0.dist-info}/WHEEL +1 -1
- appmesh-1.2.6.dist-info/RECORD +0 -6
- {appmesh-1.2.6.dist-info → appmesh-1.3.0.dist-info}/top_level.txt +0 -0
appmesh/appmesh_client.py
CHANGED
@@ -13,7 +13,7 @@ import uuid
|
|
13
13
|
from enum import Enum, unique
|
14
14
|
from datetime import datetime
|
15
15
|
from http import HTTPStatus
|
16
|
-
from typing import Optional
|
16
|
+
from typing import Optional, Tuple, final
|
17
17
|
from urllib import parse
|
18
18
|
|
19
19
|
import aniso8601
|
@@ -31,7 +31,11 @@ _SSL_CA_PEM_FILE = "/opt/appmesh/ssl/ca.pem"
|
|
31
31
|
_SSL_CLIENT_PEM_FILE = "/opt/appmesh/ssl/client.pem"
|
32
32
|
_SSL_CLIENT_PEM_KEY_FILE = "/opt/appmesh/ssl/client-key.pem"
|
33
33
|
HTTP_USER_AGENT_HEADER_NAME = "User-Agent"
|
34
|
-
HTTP_USER_AGENT = "
|
34
|
+
HTTP_USER_AGENT = "appmesh/python"
|
35
|
+
HTTP_USER_AGENT_TCP = "appmesh/python/tcp"
|
36
|
+
HTTP_HEADER_KEY_X_SEND_FILE_SOCKET = "X-Send-File-Socket"
|
37
|
+
HTTP_HEADER_KEY_X_RECV_FILE_SOCKET = "X-Recv-File-Socket"
|
38
|
+
HTTP_HEADER_KEY_X_TARGET_HOST = "X-Target-Host"
|
35
39
|
|
36
40
|
|
37
41
|
def _get_str_item(data: dict, key):
|
@@ -296,7 +300,7 @@ class App(object):
|
|
296
300
|
return output
|
297
301
|
|
298
302
|
|
299
|
-
class
|
303
|
+
class AppRun(object):
|
300
304
|
"""
|
301
305
|
Application run object indicate to a remote run from run_async()
|
302
306
|
"""
|
@@ -397,6 +401,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
397
401
|
self._jwt_token = token
|
398
402
|
|
399
403
|
@property
|
404
|
+
@final
|
400
405
|
def delegate_host(self) -> str:
|
401
406
|
"""property for delegate_host
|
402
407
|
|
@@ -406,6 +411,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
406
411
|
return self._delegate_host
|
407
412
|
|
408
413
|
@delegate_host.setter
|
414
|
+
@final
|
409
415
|
def delegate_host(self, host: str) -> None:
|
410
416
|
"""setter for delegate_host
|
411
417
|
|
@@ -1241,13 +1247,13 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1241
1247
|
)
|
1242
1248
|
if resp.status_code != HTTPStatus.OK:
|
1243
1249
|
raise Exception(resp.text)
|
1244
|
-
return
|
1250
|
+
return AppRun(self, resp.json()["name"], resp.json()["process_uuid"])
|
1245
1251
|
|
1246
|
-
def run_async_wait(self, run:
|
1252
|
+
def run_async_wait(self, run: AppRun, stdout_print: bool = True, timeout: int = 0) -> int:
|
1247
1253
|
"""Wait for an async run to be finished
|
1248
1254
|
|
1249
1255
|
Args:
|
1250
|
-
run (
|
1256
|
+
run (AppRun): asyncrized run result from run_async().
|
1251
1257
|
stdout_print (bool, optional): print remote stdout to local or not.
|
1252
1258
|
timeout (int, optional): wait max timeout seconds and return if not finished, 0 means wait until finished
|
1253
1259
|
|
@@ -1282,7 +1288,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1282
1288
|
stdout_print: bool = True,
|
1283
1289
|
max_time_seconds=DEFAULT_RUN_APP_TIMEOUT_SECONDS,
|
1284
1290
|
life_cycle_seconds=DEFAULT_RUN_APP_LIFECYCLE_SECONDS,
|
1285
|
-
) -> int:
|
1291
|
+
) -> Tuple[int, str]:
|
1286
1292
|
"""Block run a command remotely, 'name' attribute in app_json dict used to run an existing application
|
1287
1293
|
The synchronized run will block the process until the remote run is finished then return the result from HTTP response
|
1288
1294
|
|
@@ -1294,6 +1300,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1294
1300
|
|
1295
1301
|
Returns:
|
1296
1302
|
int: process exit code, return None if no exit code.
|
1303
|
+
str: stdout text
|
1297
1304
|
"""
|
1298
1305
|
path = "/appmesh/app/syncrun"
|
1299
1306
|
resp = self._request_http(
|
@@ -1310,7 +1317,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1310
1317
|
exit_code = int(resp.headers.get("Exit-Code"))
|
1311
1318
|
elif stdout_print:
|
1312
1319
|
print(resp.text)
|
1313
|
-
return exit_code
|
1320
|
+
return exit_code, resp.text
|
1314
1321
|
|
1315
1322
|
def _request_http(self, method: Method, path: str, query: dict = None, header: dict = None, body=None) -> requests.Response:
|
1316
1323
|
"""REST API
|
@@ -1332,9 +1339,9 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1332
1339
|
header["Authorization"] = "Bearer " + self.jwt_token
|
1333
1340
|
if self.delegate_host and len(self.delegate_host) > 0:
|
1334
1341
|
if ":" in self.delegate_host:
|
1335
|
-
header[
|
1342
|
+
header[HTTP_HEADER_KEY_X_TARGET_HOST] = self.delegate_host
|
1336
1343
|
else:
|
1337
|
-
header[
|
1344
|
+
header[HTTP_HEADER_KEY_X_TARGET_HOST] = self.delegate_host + ":" + str(parse.urlsplit(self.server_url).port)
|
1338
1345
|
header[HTTP_USER_AGENT_HEADER_NAME] = HTTP_USER_AGENT
|
1339
1346
|
|
1340
1347
|
if method is AppMeshClient.Method.GET:
|
@@ -1499,11 +1506,8 @@ class AppMeshClientTCP(AppMeshClient):
|
|
1499
1506
|
if super().jwt_token:
|
1500
1507
|
appmesh_requst.headers["Authorization"] = "Bearer " + super().jwt_token
|
1501
1508
|
if super().delegate_host and len(super().delegate_host) > 0:
|
1502
|
-
|
1503
|
-
|
1504
|
-
else:
|
1505
|
-
appmesh_requst.headers["X-Target-Host"] = super().delegate_host + ":" + str(parse.urlsplit(self.server_url).port)
|
1506
|
-
appmesh_requst.headers[HTTP_USER_AGENT_HEADER_NAME] = HTTP_USER_AGENT
|
1509
|
+
raise Exception("Not support delegate request in TCP mode")
|
1510
|
+
appmesh_requst.headers[HTTP_USER_AGENT_HEADER_NAME] = HTTP_USER_AGENT_TCP
|
1507
1511
|
appmesh_requst.uuid = str(uuid.uuid1())
|
1508
1512
|
appmesh_requst.http_method = method.value
|
1509
1513
|
appmesh_requst.request_uri = path
|
@@ -1524,13 +1528,13 @@ class AppMeshClientTCP(AppMeshClient):
|
|
1524
1528
|
for k, v in query.items():
|
1525
1529
|
appmesh_requst.querys[k] = v
|
1526
1530
|
data = appmesh_requst.serialize()
|
1527
|
-
self.__socket_client.sendall(len(data).to_bytes(TCP_MESSAGE_HEADER_LENGTH, "big", signed=False))
|
1531
|
+
self.__socket_client.sendall(len(data).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
|
1528
1532
|
self.__socket_client.sendall(data)
|
1529
1533
|
|
1530
1534
|
# https://developers.google.com/protocol-buffers/docs/pythontutorial
|
1531
1535
|
# https://stackoverflow.com/questions/33913308/socket-module-how-to-send-integer
|
1532
1536
|
resp_data = bytes()
|
1533
|
-
resp_data = self.__recvall(int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), "big", signed=False))
|
1537
|
+
resp_data = self.__recvall(int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), byteorder="big", signed=False))
|
1534
1538
|
if resp_data is None or len(resp_data) == 0:
|
1535
1539
|
self.__close_socket()
|
1536
1540
|
raise Exception("socket connection broken")
|
@@ -1557,18 +1561,21 @@ class AppMeshClientTCP(AppMeshClient):
|
|
1557
1561
|
Returns:
|
1558
1562
|
bool: success or failure.
|
1559
1563
|
"""
|
1560
|
-
|
1561
|
-
|
1564
|
+
header = {}
|
1565
|
+
header["File-Path"] = file_path
|
1566
|
+
header[HTTP_HEADER_KEY_X_RECV_FILE_SOCKET] = "true"
|
1567
|
+
resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/file/download", header=header)
|
1568
|
+
if resp.status_code == HTTPStatus.OK and HTTP_HEADER_KEY_X_RECV_FILE_SOCKET in resp.headers:
|
1562
1569
|
with open(local_file, "wb") as fp:
|
1563
1570
|
chunk_data = bytes()
|
1564
|
-
chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), "big", signed=False)
|
1571
|
+
chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), byteorder="big", signed=False)
|
1565
1572
|
while chunk_size > 0:
|
1566
1573
|
chunk_data = self.__recvall(chunk_size)
|
1567
1574
|
if chunk_data is None or len(chunk_data) == 0:
|
1568
1575
|
self.__close_socket()
|
1569
1576
|
raise Exception("socket connection broken")
|
1570
1577
|
fp.write(chunk_data)
|
1571
|
-
chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), "big", signed=False)
|
1578
|
+
chunk_size = int.from_bytes(self.__recvall(TCP_MESSAGE_HEADER_LENGTH), byteorder="big", signed=False)
|
1572
1579
|
if "File-Mode" in resp.headers:
|
1573
1580
|
os.chmod(path=local_file, mode=int(resp.headers["File-Mode"]))
|
1574
1581
|
if "File-User" in resp.headers and "File-Group" in resp.headers:
|
@@ -1604,15 +1611,16 @@ class AppMeshClientTCP(AppMeshClient):
|
|
1604
1611
|
header["File-User"] = str(file_stat.st_uid)
|
1605
1612
|
header["File-Group"] = str(file_stat.st_gid)
|
1606
1613
|
header["Content-Type"] = "text/plain"
|
1614
|
+
header[HTTP_HEADER_KEY_X_SEND_FILE_SOCKET] = "true"
|
1607
1615
|
# https://stackoverflow.com/questions/22567306/python-requests-file-upload
|
1608
1616
|
resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/file/upload", header=header)
|
1609
|
-
if resp.status_code == HTTPStatus.OK:
|
1610
|
-
chunk_size =
|
1617
|
+
if resp.status_code == HTTPStatus.OK and HTTP_HEADER_KEY_X_SEND_FILE_SOCKET in resp.headers:
|
1618
|
+
chunk_size = 8 * 1024 # (8 KB in bytes), 131072 bytes (128 KB) is default max ssl buffer size
|
1611
1619
|
chunk_data = fp.read(chunk_size)
|
1612
1620
|
while chunk_data:
|
1613
|
-
self.__socket_client.sendall(len(chunk_data).to_bytes(TCP_MESSAGE_HEADER_LENGTH, "big", signed=False))
|
1621
|
+
self.__socket_client.sendall(len(chunk_data).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
|
1614
1622
|
self.__socket_client.sendall(chunk_data)
|
1615
1623
|
chunk_data = fp.read(chunk_size)
|
1616
|
-
self.__socket_client.sendall(int(0).to_bytes(TCP_MESSAGE_HEADER_LENGTH, "big", signed=False))
|
1624
|
+
self.__socket_client.sendall(int(0).to_bytes(TCP_MESSAGE_HEADER_LENGTH, byteorder="big", signed=False))
|
1617
1625
|
return True, ""
|
1618
1626
|
return False, resp.json()[REST_TEXT_MESSAGE_JSON_KEY]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: appmesh
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: Client SDK for App Mesh
|
5
5
|
Home-page: https://github.com/laoshanxi/app-mesh
|
6
6
|
Author: laoshanxi
|
@@ -31,7 +31,7 @@ App Mesh is a `Multi-Tenant`, `Cloud Native`, `Micro Service` application manage
|
|
31
31
|
|
32
32
|
App Mesh is similar to Kubernetes but is much more lightweight, supporting both containerized and native applications.
|
33
33
|
|
34
|
-
<div align=center><img src="https://github.com/laoshanxi/
|
34
|
+
<div align=center><img src="https://github.com/laoshanxi/picture/raw/master/appmesh/diagram.png" align=center /></div>
|
35
35
|
|
36
36
|
## Features
|
37
37
|
|
@@ -43,7 +43,7 @@ Cloud native | Schedule cloud-level applications to run on multiple hosts with r
|
|
43
43
|
Micro service application | ⚡️ [Consul micro-service cluster management](https://app-mesh.readthedocs.io/en/latest/CONSUL.html)
|
44
44
|
Extra Features | Collect host/app resource usage <br> Remote shell command execution <br> File upload/download interface <br> Hot-update support `systemctl reload appmesh` <br> Bash completion <br> Reverse proxy <br> [Web GUI](https://github.com/laoshanxi/app-mesh-ui)
|
45
45
|
Platform support | X86_64 <br> ARM32 <br> ARM64
|
46
|
-
SDK | [Python](https://app-mesh.readthedocs.io/en/latest/api/appmesh_client.html) <br> [Golang](https://github.com/laoshanxi/app-mesh/blob/main/src/sdk/go/appmesh_client.go) <br> [JavaScript](https://www.npmjs.com/package/appmesh) <br> [Swagger OpenAPI Specification](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/laoshanxi/app-mesh/main/src/daemon/rest/openapi.yaml)
|
46
|
+
SDK | [Python](https://app-mesh.readthedocs.io/en/latest/api/appmesh_client.html) <br> [Golang](https://github.com/laoshanxi/app-mesh/blob/main/src/sdk/go/appmesh_client.go) <br> [JavaScript](https://www.npmjs.com/package/appmesh) <br> [Java](https://github.com/laoshanxi/app-mesh/packages/2227502) <br> [Swagger OpenAPI Specification](https://petstore.swagger.io/?url=https://raw.githubusercontent.com/laoshanxi/app-mesh/main/src/daemon/rest/openapi.yaml)
|
47
47
|
|
48
48
|
## Getting started
|
49
49
|
|
@@ -0,0 +1,6 @@
|
|
1
|
+
appmesh/__init__.py,sha256=xRdXeFHEieRauuJZElbEBASgXG0ZzU1a5_0isAhM7Gw,11
|
2
|
+
appmesh/appmesh_client.py,sha256=1K0n44MLVPJUUSN4Lg-SK49Vjn4yveW1PymaceW7nUI,62911
|
3
|
+
appmesh-1.3.0.dist-info/METADATA,sha256=Qkniderc7hlYrnsPZ4S2wWR6JYtROtrHruko3kdXUdc,11031
|
4
|
+
appmesh-1.3.0.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
5
|
+
appmesh-1.3.0.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
6
|
+
appmesh-1.3.0.dist-info/RECORD,,
|
appmesh-1.2.6.dist-info/RECORD
DELETED
@@ -1,6 +0,0 @@
|
|
1
|
-
appmesh/__init__.py,sha256=xRdXeFHEieRauuJZElbEBASgXG0ZzU1a5_0isAhM7Gw,11
|
2
|
-
appmesh/appmesh_client.py,sha256=XJNMUIyBj97JiRfQ3Y11Hk76nQLKtIy6fszUUO-_nmM,62408
|
3
|
-
appmesh-1.2.6.dist-info/METADATA,sha256=3OdzuZkZp3ehs-ng7iVXzBQNh4CGJywiFXyFfynILQM,10966
|
4
|
-
appmesh-1.2.6.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
|
5
|
-
appmesh-1.2.6.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
6
|
-
appmesh-1.2.6.dist-info/RECORD,,
|
File without changes
|