appmesh 0.2.3__py3-none-any.whl → 0.2.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/appmesh_client.py CHANGED
@@ -3,6 +3,7 @@
3
3
  import abc
4
4
  import aniso8601
5
5
  import base64
6
+ import copy
6
7
  import json
7
8
  import os
8
9
  import socket
@@ -25,6 +26,165 @@ TCP_MESSAGE_HEADER_LENGTH = 4
25
26
  _SSL_CA_PEM_FILE = "/opt/appmesh/ssl/ca.pem"
26
27
 
27
28
 
29
+ def _get_str_item(data, key):
30
+ return str(data[key]) if (data and key in data and data[key]) else None
31
+
32
+
33
+ def _get_int_item(data, key):
34
+ return int(data[key]) if (data and key in data and data[key]) else None
35
+
36
+
37
+ def _get_bool_item(data, key):
38
+ return bool(data[key]) if (data and key in data and data[key]) else None
39
+
40
+
41
+ def _get_dict_item(data, key):
42
+ return data[key] if (data and key in data and data[key]) else None
43
+
44
+
45
+ class App(object):
46
+ """
47
+ App object present an application in App Mesh
48
+ """
49
+
50
+ class Behavior(object):
51
+ """
52
+ Application error handling behavior definition object
53
+ """
54
+
55
+ def __init__(self, data=None) -> None:
56
+ if isinstance(data, (str, bytes, bytearray)):
57
+ data = json.loads(data)
58
+ self.exit = _get_str_item(data, "exit")
59
+ self.control = copy.deepcopy(data)
60
+
61
+ class DailyLimitation(object):
62
+ """
63
+ Application avialable day time definition object
64
+ """
65
+
66
+ def __init__(self, data=None) -> None:
67
+ if isinstance(data, (str, bytes, bytearray)):
68
+ data = json.loads(data)
69
+ self.daily_start = _get_int_item(data, "daily_start")
70
+ self.daily_end = _get_int_item(data, "daily_end")
71
+
72
+ class ResourceLimitation(object):
73
+ """
74
+ Application cgroup limitation definition object
75
+ """
76
+
77
+ def __init__(self, data=None) -> None:
78
+ if isinstance(data, (str, bytes, bytearray)):
79
+ data = json.loads(data)
80
+ self.cpu_shares = _get_int_item(data, "cpu_shares")
81
+ self.memory_mb = _get_int_item(data, "memory_mb")
82
+ self.memory_virt_mb = _get_int_item(data, "memory_virt_mb")
83
+
84
+ def __init__(self, data=None):
85
+ """Construct an App Mesh Application object
86
+
87
+ Args:
88
+ data (str | dict | json, optional): application definition data
89
+ """
90
+
91
+ if isinstance(data, (str, bytes, bytearray)):
92
+ data = json.loads(data)
93
+
94
+ # mandatory parameters
95
+ self.name = _get_str_item(data, "name")
96
+ self.command = _get_str_item(data, "command")
97
+
98
+ self.shell = _get_bool_item(data, "shell")
99
+ self.description = _get_str_item(data, "description")
100
+ self.metadata = _get_str_item(data, "metadata")
101
+ self.working_dir = _get_str_item(data, "working_dir")
102
+ self.status = _get_int_item(data, "status")
103
+ self.docker_image = _get_str_item(data, "docker_image")
104
+ self.stdout_cache_num = _get_int_item(data, "stdout_cache_num")
105
+
106
+ self.start_time = _get_int_item(data, "start_time")
107
+ self.end_time = _get_int_item(data, "end_time")
108
+ self.interval = _get_int_item(data, "interval")
109
+ self.cron = _get_bool_item(data, "cron")
110
+ self.daily_limitation = App.DailyLimitation(_get_dict_item(data, "daily_limitation"))
111
+
112
+ self.retention = _get_str_item(data, "retention")
113
+ self.extra_time = _get_str_item(data, "extra_time")
114
+
115
+ self.health_check_cmd = _get_str_item(data, "health_check_cmd")
116
+ self.permission = _get_int_item(data, "permission")
117
+ self.behavior = App.Behavior(_get_dict_item(data, "behavior"))
118
+
119
+ self.env = dict()
120
+ if data and "env" in data:
121
+ for k, v in data["env"].items():
122
+ self.env[k] = v
123
+ self.sec_env = dict()
124
+ if data and "sec_env" in data:
125
+ for k, v in data["sec_env"].items():
126
+ self.sec_env[k] = v
127
+ self.pid = _get_int_item(data, "pid")
128
+ self.resource_limit = App.ResourceLimitation(_get_dict_item(data, "resource_limit"))
129
+
130
+ # readonly attributes
131
+ self.owner = _get_str_item(data, "owner")
132
+ self.pstree = _get_str_item(data, "pstree")
133
+ self.container_id = _get_str_item(data, "container_id")
134
+ self.memory = _get_int_item(data, "memory")
135
+ self.cpu = _get_int_item(data, "cpu")
136
+ self.fd = _get_int_item(data, "fd")
137
+ self.last_start_time = _get_int_item(data, "last_start_time")
138
+ self.last_exit_time = _get_int_item(data, "last_exit_time")
139
+ self.health = _get_int_item(data, "health")
140
+ self.version = _get_int_item(data, "version")
141
+ self.return_code = _get_int_item(data, "return_code")
142
+
143
+ def __str__(self) -> str:
144
+ output = copy.deepcopy(self.__dict__)
145
+ output["behavior"] = copy.deepcopy(self.behavior.__dict__)
146
+ output["daily_limitation"] = copy.deepcopy(self.daily_limitation.__dict__)
147
+ output["resource_limit"] = copy.deepcopy(self.resource_limit.__dict__)
148
+
149
+ def clean_empty_item(data, key) -> None:
150
+ value = data[key]
151
+ if not value:
152
+ del data[key]
153
+ elif isinstance(value, dict):
154
+ for k in list(value):
155
+ clean_empty_item(value, k)
156
+
157
+ for k in list(output):
158
+ clean_empty_item(output, k)
159
+ for k in list(output):
160
+ clean_empty_item(output, k)
161
+ return json.dumps(output, indent=2)
162
+
163
+
164
+ class Run(object):
165
+ """
166
+ Application run object indicate to a remote run from run_async()
167
+ """
168
+
169
+ def __init__(self, client, app_name: str, process_id: str):
170
+ self.app_name = app_name
171
+ self.proc_uid = process_id
172
+ self.__client = client
173
+
174
+ def wait(self, stdout_print: bool = True, timeout: int = 0) -> int:
175
+ """Wait for an async run to be finished
176
+
177
+ Args:
178
+ run (Run): asyncrized run result from run_async().
179
+ stdout_print (bool, optional): print remote stdout to local or not.
180
+ timeout (int, optional): wait max timeout seconds and return if not finished, 0 means wait until finished
181
+
182
+ Returns:
183
+ int: return exit code if process finished, return None for timeout or exception.
184
+ """
185
+ return self.__client.run_async_wait(self, stdout_print, timeout)
186
+
187
+
28
188
  class AppMeshClient(metaclass=abc.ABCMeta):
29
189
  """
30
190
  Client object used to access App Mesh REST Service
@@ -132,7 +292,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
132
292
  if self.jwt_auth_enable:
133
293
  self.jwt_token = token
134
294
  headers = {}
135
- if permission is not None:
295
+ if permission:
136
296
  headers["Auth-Permission"] = permission
137
297
  resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/auth", header=headers)
138
298
  if resp.status_code == HTTPStatus.OK:
@@ -146,28 +306,39 @@ class AppMeshClient(metaclass=abc.ABCMeta):
146
306
  ########################################
147
307
  # Application view
148
308
  ########################################
149
- def app_view(self, app_name: str):
150
- """Get application information in JSON format
309
+ def app_view(self, app_name: str) -> App:
310
+ """Get one application information
151
311
 
152
312
  Args:
153
313
  app_name (str): the application name.
154
314
 
155
315
  Returns:
156
- bool: success or failure.
157
- dict: the application JSON both contain static configuration and runtime information.
316
+ App: the application object both contain static configuration and runtime information.
317
+
318
+ Exception:
319
+ failed request or no such application
158
320
  """
159
321
  resp = self._request_http(AppMeshClient.Method.GET, path=f"/appmesh/app/{app_name}")
160
- return (resp.status_code == HTTPStatus.OK), resp.json()
322
+ if resp.status_code != HTTPStatus.OK:
323
+ raise Exception(resp.text)
324
+ return App(resp.json())
161
325
 
162
326
  def app_view_all(self):
163
- """Get all applications in JSON format
327
+ """Get all applications
164
328
 
165
329
  Returns:
166
- bool: success or failure.
167
- dict: the application JSON both contain static configuration and runtime information, only return applications that the user has permissions.
330
+ list: the application object both contain static configuration and runtime information, only return applications that the user has permissions.
331
+
332
+ Exception:
333
+ failed request or no such application
168
334
  """
169
335
  resp = self._request_http(AppMeshClient.Method.GET, path="/appmesh/applications")
170
- return (resp.status_code == HTTPStatus.OK), resp.json()
336
+ if resp.status_code != HTTPStatus.OK:
337
+ raise Exception(resp.text)
338
+ apps = []
339
+ for app in resp.json():
340
+ apps.append(App(app))
341
+ return apps
171
342
 
172
343
  def app_output(self, app_name: str, stdout_position: int = 0, stdout_index: int = 0, stdout_maxsize: int = 10240, process_uuid: str = "", timeout: int = 0):
173
344
  """Get application stdout/stderr
@@ -217,18 +388,22 @@ class AppMeshClient(metaclass=abc.ABCMeta):
217
388
  ########################################
218
389
  # Application manage
219
390
  ########################################
220
- def app_add(self, app_json: dict):
391
+ def app_add(self, app: App) -> App:
221
392
  """Register an application
222
393
 
223
394
  Args:
224
- app_json (dict): the application definition.
395
+ app (App): the application definition.
225
396
 
226
397
  Returns:
227
- bool: success or failure.
228
- dict: resigtered application in JSON format.
398
+ App: resigtered application object.
399
+
400
+ Exception:
401
+ failed request
229
402
  """
230
- resp = self._request_http(AppMeshClient.Method.PUT, path="/appmesh/app/{0}".format(app_json["name"]), body=app_json)
231
- return (resp.status_code == HTTPStatus.OK), resp.json()
403
+ resp = self._request_http(AppMeshClient.Method.PUT, path="/appmesh/app/{0}".format(app.name), body=str(app))
404
+ if resp.status_code != HTTPStatus.OK:
405
+ raise Exception(resp.text)
406
+ return App(resp.json())
232
407
 
233
408
  def app_delete(self, app_name: str):
234
409
  """Remove an application.
@@ -762,7 +937,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
762
937
 
763
938
  def run_async(
764
939
  self,
765
- app_json: dict,
940
+ app: App,
766
941
  max_time_seconds=DEFAULT_RUN_APP_TIMEOUT_SECONDS,
767
942
  life_cycle_seconds=DEFAULT_RUN_APP_LIFECYCLE_SECONDS,
768
943
  ):
@@ -770,7 +945,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
770
945
  Asyncrized run will not block process
771
946
 
772
947
  Args:
773
- app_json (dict): application JSON dict.
948
+ app (App): application object.
774
949
  max_time_seconds (int | str, optional): max run time for the remote process, support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P5W').
775
950
  life_cycle_seconds (int | str, optional): max lifecycle time for the remote process. support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P5W').
776
951
 
@@ -781,25 +956,19 @@ class AppMeshClient(metaclass=abc.ABCMeta):
781
956
  path = "/appmesh/app/run"
782
957
  resp = self._request_http(
783
958
  AppMeshClient.Method.POST,
784
- body=app_json,
959
+ body=str(app),
785
960
  path=path,
786
961
  query={"timeout": self._parse_duration(max_time_seconds), "lifecycle": self._parse_duration(life_cycle_seconds)},
787
962
  )
788
- if resp.status_code == HTTPStatus.OK:
789
- app_name = resp.json()["name"]
790
- process_uuid = resp.json()["process_uuid"]
791
- return (app_name, process_uuid)
792
- else:
793
- print(resp.text)
794
- return None
963
+ if resp.status_code != HTTPStatus.OK:
964
+ raise Exception(resp.text)
965
+ return Run(self, resp.json()["name"], resp.json()["process_uuid"])
795
966
 
796
- def run_async_wait(self, async_tuple: tuple, stdout_print: bool = True, timeout: int = 0) -> int:
967
+ def run_async_wait(self, run: Run, stdout_print: bool = True, timeout: int = 0) -> int:
797
968
  """Wait for an async run to be finished
798
969
 
799
970
  Args:
800
- async_tuple (tuple): asyncrized run result from run_async().
801
- async_tuple[0] app_name: application name from run_async
802
- async_tuple[1] process_uuid: process uuid
971
+ run (Run): asyncrized run result from run_async().
803
972
  stdout_print (bool, optional): print remote stdout to local or not.
804
973
  timeout (int, optional): wait max timeout seconds and return if not finished, 0 means wait until finished
805
974
 
@@ -807,23 +976,21 @@ class AppMeshClient(metaclass=abc.ABCMeta):
807
976
  int: return exit code if process finished, return None for timeout or exception.
808
977
  """
809
978
  exit_code = None
810
- if async_tuple is not None:
811
- app_name = async_tuple[0]
812
- process_uuid = async_tuple[1]
979
+ if run:
813
980
  output_position = 0
814
981
  start = datetime.now()
815
982
  interval = 1 if self.__class__.__name__ == "AppMeshClient" else 1000
816
- while len(process_uuid) > 0:
983
+ while len(run.proc_uid) > 0:
817
984
  success, output, position, exit_code = self.app_output(
818
- app_name=app_name, stdout_position=output_position, stdout_index=0, process_uuid=process_uuid, timeout=interval
985
+ app_name=run.app_name, stdout_position=output_position, stdout_index=0, process_uuid=run.proc_uid, timeout=interval
819
986
  )
820
- if output is not None and stdout_print:
987
+ if output and stdout_print:
821
988
  print(output, end="")
822
989
  if position is not None:
823
990
  output_position = position
824
991
  if exit_code is not None:
825
992
  # success
826
- self.app_delete(app_name)
993
+ self.app_delete(run.app_name)
827
994
  break
828
995
  if not success:
829
996
  # failed
@@ -835,7 +1002,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
835
1002
 
836
1003
  def run_sync(
837
1004
  self,
838
- app_json: dict,
1005
+ app: App,
839
1006
  stdout_print: bool = True,
840
1007
  max_time_seconds=DEFAULT_RUN_APP_TIMEOUT_SECONDS,
841
1008
  life_cycle_seconds=DEFAULT_RUN_APP_LIFECYCLE_SECONDS,
@@ -844,7 +1011,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
844
1011
  The synchronized run will block the process until the remote run is finished then return the result from HTTP response
845
1012
 
846
1013
  Args:
847
- app_json (dict): application JSON dict.
1014
+ app (App): application object.
848
1015
  stdout_print (bool, optional): whether print remote stdout to local or not. Defaults to True.
849
1016
  max_time_seconds (int | str, optional): max run time for the remote process. support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P5W').
850
1017
  life_cycle_seconds (int | str, optional): max lifecycle time for the remote process. support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P5W').
@@ -855,7 +1022,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
855
1022
  path = "/appmesh/app/syncrun"
856
1023
  resp = self._request_http(
857
1024
  AppMeshClient.Method.POST,
858
- body=app_json,
1025
+ body=str(app),
859
1026
  path=path,
860
1027
  query={"timeout": self._parse_duration(max_time_seconds), "lifecycle": self._parse_duration(life_cycle_seconds)},
861
1028
  )
@@ -883,7 +1050,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
883
1050
  requests.Response: HTTP response
884
1051
  """
885
1052
  rest_url = parse.urljoin(self.server_url, path)
886
- if self.jwt_token is not None:
1053
+ if self.jwt_token:
887
1054
  header["Authorization"] = "Bearer " + self.jwt_token
888
1055
 
889
1056
  if method is AppMeshClient.Method.GET:
@@ -1018,7 +1185,7 @@ class AppMeshClientTCP(AppMeshClient):
1018
1185
  setattr(self, k, v)
1019
1186
  return self
1020
1187
 
1021
- if super().jwt_token is not None:
1188
+ if super().jwt_token:
1022
1189
  header["Authorization"] = "Bearer " + super().jwt_token
1023
1190
  if self.__socket_client is None:
1024
1191
  self.__connect_socket()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: appmesh
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Client SDK for App Mesh
5
5
  Home-page: https://github.com/laoshanxi/app-mesh
6
6
  Author: laoshanxi
@@ -0,0 +1,6 @@
1
+ appmesh/__init__.py,sha256=xRdXeFHEieRauuJZElbEBASgXG0ZzU1a5_0isAhM7Gw,11
2
+ appmesh/appmesh_client.py,sha256=8lR_gF4_BYzWgg63XBIaJuSGJeSE7jt066v1QLFq-pc,49634
3
+ appmesh-0.2.4.dist-info/METADATA,sha256=LtKj7oblEzep3qW4RhcsWUt1oCgyUj5Nv_i-BWfE2uI,10620
4
+ appmesh-0.2.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
5
+ appmesh-0.2.4.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
6
+ appmesh-0.2.4.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- appmesh/__init__.py,sha256=xRdXeFHEieRauuJZElbEBASgXG0ZzU1a5_0isAhM7Gw,11
2
- appmesh/appmesh_client.py,sha256=wZDX62DY318vpGqmZfEcUQXYjm5heIIb5mCkTR9Q2WI,43866
3
- appmesh-0.2.3.dist-info/METADATA,sha256=b4B2rrF9rtJSK6P-ogSIWGUEtmpew5JlfFiFsB_Z-s4,10620
4
- appmesh-0.2.3.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
5
- appmesh-0.2.3.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
6
- appmesh-0.2.3.dist-info/RECORD,,