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 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 = "appmeshsdk/py"
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 Run(object):
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 Run(self, resp.json()["name"], resp.json()["process_uuid"])
1250
+ return AppRun(self, resp.json()["name"], resp.json()["process_uuid"])
1245
1251
 
1246
- def run_async_wait(self, run: Run, stdout_print: bool = True, timeout: int = 0) -> int:
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 (Run): asyncrized run result from run_async().
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["X-Target-Host"] = self.delegate_host
1342
+ header[HTTP_HEADER_KEY_X_TARGET_HOST] = self.delegate_host
1336
1343
  else:
1337
- header["X-Target-Host"] = self.delegate_host + ":" + str(parse.urlsplit(self.server_url).port)
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
- if ":" in super().delegate_host:
1503
- appmesh_requst.headers["X-Target-Host"] = super().delegate_host
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
- resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/file/download", header={"File-Path": file_path})
1561
- if resp.status_code == HTTPStatus.OK:
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 = 1024 * 4 # 131072 bytes, default max ssl buffer 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.2.6
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/app-mesh/raw/main/docs/source/diagram.jpg" align=center /></div>
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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,,