appmesh 1.6.1__py3-none-any.whl → 1.6.2__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/__init__.py CHANGED
@@ -9,10 +9,40 @@ Example:
9
9
  client = AppMeshClient()
10
10
  """
11
11
 
12
- from .app import App
13
- from .client_http import AppMeshClient
14
- from .client_tcp import AppMeshClientTCP
15
- from .server_http import AppMeshServer
16
- from .server_tcp import AppMeshServerTCP
12
+ import sys
13
+ from types import ModuleType
17
14
 
18
- __all__ = ["App", "AppMeshClient", "AppMeshClientTCP", "AppMeshServer", "AppMeshServerTCP"]
15
+ __all__ = ["App", "AppMeshClient", "AppMeshClientTCP", "AppMeshClientOAuth", "AppMeshServer", "AppMeshServerTCP"]
16
+
17
+ _LAZY_IMPORTS = {
18
+ "App": ("app", "App"), # from .app import App
19
+ "AppMeshClient": ("client_http", "AppMeshClient"), # from .client_http import AppMeshClient
20
+ "AppMeshClientTCP": ("client_tcp", "AppMeshClientTCP"), # from .client_tcp import AppMeshClientTCP
21
+ "AppMeshClientOAuth": ("client_http_oauth", "AppMeshClientOAuth"), # from .client_http_oauth import AppMeshClientOAuth
22
+ "AppMeshServer": ("server_http", "AppMeshServer"), # from .server_http import AppMeshServer
23
+ "AppMeshServerTCP": ("server_tcp", "AppMeshServerTCP"), # from .server_tcp import AppMeshServerTCP
24
+ }
25
+
26
+
27
+ def _lazy_import(name):
28
+ """Helper function for lazy importing."""
29
+ if name in _LAZY_IMPORTS:
30
+ module_name, attr_name = _LAZY_IMPORTS[name]
31
+ module = __import__(f"{__name__}.{module_name}", fromlist=[attr_name])
32
+ return getattr(module, attr_name)
33
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
34
+
35
+
36
+ if sys.version_info >= (3, 7):
37
+
38
+ def __getattr__(name):
39
+ return _lazy_import(name)
40
+
41
+ else:
42
+ # Python 3.6 compatibility
43
+ class _LazyModule(ModuleType):
44
+ def __getattr__(self, name):
45
+ return _lazy_import(name)
46
+
47
+ sys.modules[__name__] = _LazyModule(__name__)
48
+ sys.modules[__name__].__dict__.update(globals())
appmesh/client_http.py CHANGED
@@ -107,7 +107,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
107
107
  DURATION_ONE_WEEK_ISO = "P1W"
108
108
  DURATION_TWO_DAYS_ISO = "P2D"
109
109
  DURATION_TWO_DAYS_HALF_ISO = "P2DT12H"
110
- TOKEN_REFRESH_INTERVAL = 60
110
+ TOKEN_REFRESH_INTERVAL = 300 # 5 min to refresh token
111
+ TOKEN_REFRESH_OFFSET = 30 # 30s before token expire to refresh token
111
112
 
112
113
  # Platform-aware default SSL paths
113
114
  _DEFAULT_SSL_DIR = "c:/local/appmesh/ssl" if os.name == "nt" else "/opt/appmesh/ssl"
@@ -140,7 +141,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
140
141
  rest_ssl_client_cert=(DEFAULT_SSL_CLIENT_CERT_PATH, DEFAULT_SSL_CLIENT_KEY_PATH) if os.path.exists(DEFAULT_SSL_CLIENT_CERT_PATH) else None,
141
142
  rest_timeout=(60, 300),
142
143
  jwt_token=None,
143
- oauth2=None,
144
144
  auto_refresh_token=False,
145
145
  ):
146
146
  """Initialize an App Mesh HTTP client for interacting with the App Mesh server via secure HTTPS.
@@ -163,15 +163,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
163
163
  The default is `(60, 300)`, where `60` seconds is the maximum time to establish a connection and `300` seconds for the maximum read duration.
164
164
 
165
165
  jwt_token (str, optional): JWT token for API authentication, used in headers to authorize requests where required.
166
-
167
- oauth2 (Dict[str, Any], optional): Keycloak configuration for oauth2 authentication:
168
- - server_url: Keycloak server URL (e.g. "https://keycloak.example.com/auth/")
169
- - realm: Keycloak realm
170
- - client_id: Keycloak client ID
171
- - client_secret: Keycloak client secret (optional)
172
- Using this parameter enables Keycloak integration for authentication. The 'python-keycloak' package
173
- will be imported on-demand only when this parameter is, make sure package is installed (pip3 install python-keycloak).
174
-
175
166
  auto_refresh_token (bool, optional): Enable automatic token refresh before expiration.
176
167
  When enabled, a background timer will monitor token expiration and attempt to refresh
177
168
  the token before it expires. This works with both native App Mesh tokens and Keycloak tokens.
@@ -185,29 +176,10 @@ class AppMeshClient(metaclass=abc.ABCMeta):
185
176
  self.rest_timeout = rest_timeout
186
177
  self._forward_to = None
187
178
 
188
- # Keycloak integration
189
- self._keycloak_openid = None
190
- if oauth2:
191
- try:
192
- from keycloak import KeycloakOpenID
193
-
194
- self._keycloak_openid = KeycloakOpenID(
195
- server_url=oauth2.get("auth_server_url"),
196
- client_id=oauth2.get("client_id"),
197
- realm_name=oauth2.get("realm"),
198
- client_secret_key=oauth2.get("client_secret"),
199
- verify=self.ssl_verify,
200
- timeout=rest_timeout,
201
- )
202
- except ImportError:
203
- logging.error("Keycloak package not installed. Install with: pip install python-keycloak")
204
- raise Exception("Keycloak integration requested but python-keycloak package is not installed")
205
-
206
179
  # Token auto-refresh
207
180
  self._token_refresh_timer = None
208
181
  self._auto_refresh_token = auto_refresh_token
209
- if auto_refresh_token and jwt_token:
210
- self._schedule_token_refresh()
182
+ self.jwt_token = jwt_token # Set property last after all dependencies are initialized
211
183
 
212
184
  @staticmethod
213
185
  def _ensure_logging_configured():
@@ -215,6 +187,9 @@ class AppMeshClient(metaclass=abc.ABCMeta):
215
187
  if not logging.root.handlers:
216
188
  logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
217
189
 
190
+ def _get_access_token(self) -> str:
191
+ return self.jwt_token
192
+
218
193
  def _check_and_refresh_token(self):
219
194
  """Check and refresh token if needed, then schedule next check.
220
195
 
@@ -232,12 +207,12 @@ class AppMeshClient(metaclass=abc.ABCMeta):
232
207
 
233
208
  # Check token expiration directly from JWT
234
209
  try:
235
- decoded_token = jwt.decode(self.jwt_token if isinstance(self.jwt_token, str) else self.jwt_token.get("access_token", ""), options={"verify_signature": False})
210
+ decoded_token = jwt.decode(self._get_access_token(), options={"verify_signature": False})
236
211
  expiry = decoded_token.get("exp", 0)
237
212
  current_time = time.time()
238
213
  time_to_expiry = expiry - current_time
239
214
  # Refresh if token expires within 5 minutes
240
- needs_refresh = time_to_expiry < 300
215
+ needs_refresh = time_to_expiry < self.TOKEN_REFRESH_OFFSET
241
216
  except Exception as e:
242
217
  logging.debug("Failed to parse JWT token for expiration check: %s", str(e))
243
218
 
@@ -277,11 +252,11 @@ class AppMeshClient(metaclass=abc.ABCMeta):
277
252
 
278
253
  # Calculate more precise check time if expiry is known
279
254
  if time_to_expiry is not None:
280
- if time_to_expiry <= 300: # Expires within 5 minutes
255
+ if time_to_expiry <= self.TOKEN_REFRESH_OFFSET: # Expires within 5 minutes
281
256
  check_interval = 1 # Almost immediate refresh
282
257
  else:
283
258
  # Check at earlier of 5 minutes before expiry or regular interval
284
- check_interval = min(time_to_expiry - 300, self.TOKEN_REFRESH_INTERVAL)
259
+ check_interval = min(time_to_expiry - self.TOKEN_REFRESH_OFFSET, self.TOKEN_REFRESH_INTERVAL)
285
260
 
286
261
  # Create timer to execute refresh check
287
262
  self._token_refresh_timer = threading.Timer(check_interval, self._check_and_refresh_token)
@@ -303,14 +278,9 @@ class AppMeshClient(metaclass=abc.ABCMeta):
303
278
  self.session.close()
304
279
  self.session = None
305
280
 
306
- # Logout from Keycloak if needed
307
- if hasattr(self, "_keycloak_openid") and self._keycloak_openid and hasattr(self, "_jwt_token") and self._jwt_token and isinstance(self._jwt_token, dict) and "refresh_token" in self._jwt_token:
308
- try:
309
- self._keycloak_openid.logout(self._jwt_token.get("refresh_token"))
310
- except Exception as e:
311
- logging.warning("Failed to logout from Keycloak: %s", str(e))
312
- finally:
313
- self._keycloak_openid = None
281
+ # Clean token
282
+ if hasattr(self, "_jwt_token") and self._jwt_token:
283
+ self._jwt_token = None
314
284
 
315
285
  def __enter__(self):
316
286
  """Support for context manager protocol."""
@@ -370,6 +340,13 @@ class AppMeshClient(metaclass=abc.ABCMeta):
370
340
  """
371
341
  self._jwt_token = token
372
342
 
343
+ # handle refresh
344
+ if self._jwt_token and self._auto_refresh_token:
345
+ self._schedule_token_refresh()
346
+ elif self._token_refresh_timer:
347
+ self._token_refresh_timer.cancel()
348
+ self._token_refresh_timer = None
349
+
373
350
  @property
374
351
  def forward_to(self) -> str:
375
352
  """Get the target host address for request forwarding in a cluster setup.
@@ -419,7 +396,14 @@ class AppMeshClient(metaclass=abc.ABCMeta):
419
396
  ########################################
420
397
  # Security
421
398
  ########################################
422
- 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:
399
+ def login(
400
+ self,
401
+ user_name: str,
402
+ user_pwd: str,
403
+ totp_code: Optional[str] = "",
404
+ timeout_seconds: Union[str, int] = DURATION_ONE_WEEK_ISO,
405
+ audience: Optional[str] = None,
406
+ ) -> str:
423
407
  """Login with user name and password
424
408
 
425
409
  Args:
@@ -432,20 +416,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
432
416
  Returns:
433
417
  str: JWT token.
434
418
  """
435
- # Keycloak authentication if configured
436
- if self._keycloak_openid:
437
- self.jwt_token = self._keycloak_openid.token(
438
- username=user_name,
439
- password=user_pwd,
440
- totp=totp_code if totp_code else None,
441
- grant_type="password", # grant type for token request: "password" / "client_credentials" / "refresh_token"
442
- scope="openid", # what information to include in the token, such as "openid profile email"
443
- )
444
-
445
- if self._auto_refresh_token:
446
- self._schedule_token_refresh()
447
- return self.jwt_token
448
-
449
419
  # Standard App Mesh authentication
450
420
  self.jwt_token = None
451
421
  resp = self._request_http(
@@ -467,8 +437,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
467
437
  else:
468
438
  raise Exception(resp.text)
469
439
 
470
- if self._auto_refresh_token:
471
- self._schedule_token_refresh()
472
440
  return self.jwt_token
473
441
 
474
442
  def validate_totp(self, username: str, challenge: str, code: str, timeout: Union[int, str] = DURATION_ONE_WEEK_ISO) -> str:
@@ -510,24 +478,12 @@ class AppMeshClient(metaclass=abc.ABCMeta):
510
478
  bool: logoff success or failure.
511
479
  """
512
480
  result = False
513
- # Handle Keycloak logout if configured
514
- if self._keycloak_openid and self.jwt_token and isinstance(self.jwt_token, dict) and "refresh_token" in self.jwt_token:
515
- refresh_token = self.jwt_token.get("refresh_token")
516
- self._keycloak_openid.logout(refresh_token)
517
- self.jwt_token = None
518
- result = True
519
-
520
481
  # Standard App Mesh logout
521
482
  if self.jwt_token and isinstance(self.jwt_token, str):
522
483
  resp = self._request_http(AppMeshClient.Method.POST, path="/appmesh/self/logoff")
523
484
  self.jwt_token = None
524
485
  result = resp.status_code == HTTPStatus.OK
525
486
 
526
- # Cancel token refresh timer
527
- if self._token_refresh_timer:
528
- self._token_refresh_timer.cancel()
529
- self._token_refresh_timer = None
530
-
531
487
  return result
532
488
 
533
489
  def authentication(self, token: str, permission: Optional[str] = None, audience: Optional[str] = None) -> bool:
@@ -577,13 +533,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
577
533
  raise Exception("No token to renew")
578
534
 
579
535
  try:
580
- # Handle Keycloak token (dictionary format)
581
- if self._keycloak_openid and isinstance(self.jwt_token, dict) and "refresh_token" in self.jwt_token:
582
- new_token = self._keycloak_openid.refresh_token(self.jwt_token.get("refresh_token"))
583
- self.jwt_token = new_token
584
-
585
536
  # Handle App Mesh token (string format)
586
- elif isinstance(self.jwt_token, str):
537
+ if isinstance(self.jwt_token, str):
587
538
  resp = self._request_http(
588
539
  AppMeshClient.Method.POST,
589
540
  path="/appmesh/token/renew",
@@ -986,9 +937,6 @@ class AppMeshClient(metaclass=abc.ABCMeta):
986
937
  Returns:
987
938
  dict: user definition.
988
939
  """
989
- if self._keycloak_openid and isinstance(self.jwt_token, dict) and "access_token" in self.jwt_token:
990
- return self._keycloak_openid.userinfo(self.jwt_token.get("access_token"))
991
-
992
940
  resp = self._request_http(method=AppMeshClient.Method.GET, path="/appmesh/user/self")
993
941
  if resp.status_code != HTTPStatus.OK:
994
942
  raise Exception(resp.text)
@@ -1383,7 +1331,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1383
1331
  # Prepare headers
1384
1332
  header = {} if header is None else header
1385
1333
  if self.jwt_token:
1386
- token = self.jwt_token["access_token"] if isinstance(self.jwt_token, dict) and "access_token" in self.jwt_token else self.jwt_token
1334
+ token = self._get_access_token()
1387
1335
  header["Authorization"] = "Bearer " + token
1388
1336
  if self.forward_to and len(self.forward_to) > 0:
1389
1337
  if ":" in self.forward_to:
@@ -0,0 +1,138 @@
1
+ # client_http_oauth.py
2
+ # pylint: disable=line-too-long,broad-exception-caught,too-many-lines, import-outside-toplevel, protected-access
3
+ import os
4
+ import logging
5
+ from typing import Optional, Union
6
+ from keycloak import KeycloakOpenID
7
+ from .client_http import AppMeshClient
8
+
9
+
10
+ class AppMeshClientOAuth(AppMeshClient):
11
+ """
12
+ AppMeshClient extended with Keycloak authentication support.
13
+
14
+ Managing tokens using Keycloak as the identity provider.
15
+ """
16
+
17
+ def __init__(
18
+ self,
19
+ oauth2: dict, # Required for Keycloak
20
+ rest_url: str = "https://127.0.0.1:6060",
21
+ rest_ssl_verify=AppMeshClient.DEFAULT_SSL_CA_CERT_PATH if os.path.exists(AppMeshClient.DEFAULT_SSL_CA_CERT_PATH) else False,
22
+ rest_ssl_client_cert=(AppMeshClient.DEFAULT_SSL_CLIENT_CERT_PATH, AppMeshClient.DEFAULT_SSL_CLIENT_KEY_PATH) if os.path.exists(AppMeshClient.DEFAULT_SSL_CLIENT_CERT_PATH) else None,
23
+ rest_timeout=(60, 300),
24
+ jwt_token=None, # Keycloak dict
25
+ auto_refresh_token: bool = True, # Default to True for Keycloak
26
+ ):
27
+ """Initialize an App Mesh HTTP client with Keycloak support.
28
+ Args:
29
+ oauth2 (Dict[str, str]): Keycloak configuration for oauth2 authentication:
30
+ - auth_server_url: Keycloak server URL (e.g. "https://keycloak.example.com/auth/")
31
+ - realm: Keycloak realm
32
+ - client_id: Keycloak client ID
33
+ - client_secret: Keycloak client secret (optional)
34
+ Using this parameter enables Keycloak integration for authentication. The 'python-keycloak' package
35
+ will be imported on-demand only when this parameter is, make sure package is installed (pip3 install python-keycloak).
36
+ """
37
+ # Initialize base class, disabling its Keycloak and auto-refresh logic
38
+ super().__init__(
39
+ rest_url=rest_url,
40
+ rest_ssl_verify=rest_ssl_verify,
41
+ rest_ssl_client_cert=rest_ssl_client_cert,
42
+ rest_timeout=rest_timeout,
43
+ jwt_token=jwt_token,
44
+ auto_refresh_token=auto_refresh_token,
45
+ )
46
+
47
+ # Keycloak integration
48
+ self._keycloak_openid = KeycloakOpenID(
49
+ server_url=oauth2.get("auth_server_url"),
50
+ client_id=oauth2.get("client_id"),
51
+ realm_name=oauth2.get("realm"),
52
+ client_secret_key=oauth2.get("client_secret"),
53
+ verify=self.ssl_verify,
54
+ timeout=rest_timeout,
55
+ )
56
+
57
+ # @override, from typing import override avialable from python3.12
58
+ def _get_access_token(self) -> str:
59
+ return self.jwt_token.get("access_token", "") if self.jwt_token else None
60
+
61
+ def login(
62
+ self,
63
+ user_name: str,
64
+ user_pwd: str,
65
+ totp_code: Optional[str] = "",
66
+ timeout_seconds: Union[str, int] = AppMeshClient.DURATION_ONE_WEEK_ISO,
67
+ ) -> dict:
68
+ """Login with user name and password using Keycloak.
69
+ Args:
70
+ user_name (str): the name of the user.
71
+ user_pwd (str): the password of the user.
72
+ totp_code (str, optional): the TOTP code if enabled for the user.
73
+ timeout_seconds (int | str, optional): token expire timeout of seconds. support ISO 8601 durations (e.g., 'P1Y2M3DT4H5M6S' 'P1W').
74
+
75
+ Returns:
76
+ dict: Keycloak token.
77
+ """
78
+ # Keycloak authentication
79
+ self.jwt_token = self._keycloak_openid.token(
80
+ username=user_name,
81
+ password=user_pwd,
82
+ totp=totp_code if totp_code else None,
83
+ grant_type="password", # grant type for token request: "password" / "client_credentials" / "refresh_token"
84
+ scope="openid", # what information to include in the token, such as "openid profile email"
85
+ )
86
+
87
+ return self.jwt_token
88
+
89
+ def logoff(self) -> bool:
90
+ """Log out of the current session from Keycloak and clean up."""
91
+ result = False
92
+ if self._keycloak_openid and self.jwt_token:
93
+ try:
94
+ self._keycloak_openid.logout(self.jwt_token.get("refresh_token"))
95
+ result = True
96
+ except Exception as e:
97
+ logging.warning("Failed to logout from Keycloak: %s", str(e))
98
+ finally:
99
+ self.jwt_token = None
100
+
101
+ # Call super to handle base class cleanup (timers, session)
102
+ super_result = super().logoff()
103
+
104
+ return result and super_result
105
+
106
+ def renew_token(self) -> dict:
107
+ """Renew the current Keycloak token."""
108
+ if not self.jwt_token or not isinstance(self.jwt_token, dict) or "refresh_token" not in self.jwt_token:
109
+ raise Exception("No Keycloak refresh token available to renew")
110
+
111
+ try:
112
+ # Handle Keycloak token (dictionary format)
113
+ new_token = self._keycloak_openid.refresh_token(self.jwt_token.get("refresh_token"))
114
+ self.jwt_token = new_token
115
+ return self.jwt_token
116
+ except Exception as e:
117
+ logging.error("Keycloak token renewal failed: %s", str(e))
118
+ raise Exception(f"Keycloak token renewal failed: {str(e)}") from e
119
+
120
+ def view_self(self) -> dict:
121
+ """Get information about the current user, using Keycloak userinfo if applicable.
122
+ Returns:
123
+ dict: user definition.
124
+ """
125
+ return self._keycloak_openid.userinfo(self._get_access_token())
126
+
127
+ def close(self):
128
+ """Close the session and release resources, including Keycloak logout."""
129
+ # Logout from Keycloak if needed
130
+ if hasattr(self, "_keycloak_openid") and self._keycloak_openid and hasattr(self, "_jwt_token") and self._jwt_token and isinstance(self._jwt_token, dict) and "refresh_token" in self._jwt_token:
131
+ try:
132
+ self._keycloak_openid.logout(self._jwt_token.get("refresh_token"))
133
+ except Exception as e:
134
+ logging.warning("Failed to logout from Keycloak: %s", str(e))
135
+ finally:
136
+ self._keycloak_openid = None
137
+ # Close the base class session and resources (timers, etc.)
138
+ super().close()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: appmesh
3
- Version: 1.6.1
3
+ Version: 1.6.2
4
4
  Summary: Client SDK for App Mesh
5
5
  Home-page: https://github.com/laoshanxi/app-mesh
6
6
  Author: laoshanxi
@@ -42,6 +42,7 @@ Dynamic: summary
42
42
 
43
43
  App Mesh is an open-source, multi-tenant application management platform designed for cloud-native environments. It efficiently manages, schedules, and monitors both microservices and traditional applications, offering a lightweight alternative to Kubernetes. App Mesh bridges the gap between simple process managers and complex container orchestration systems, making it ideal for organizations seeking to modernize their infrastructure without adopting full container-native complexity. Supporting both containerized and native applications, it provides a versatile solution for diverse enterprise needs.
44
44
 
45
+ <div align=center><img src="https://github.com/laoshanxi/picture/raw/master/appmesh/whatis.gif" align=center /></div>
45
46
  <div align=center><img src="https://github.com/laoshanxi/picture/raw/master/appmesh/diagram.png" align=center /></div>
46
47
 
47
48
  ## Features
@@ -54,7 +55,7 @@ Cloud native | Schedule cloud-level applications to run on multiple hosts with r
54
55
  Micro service application | 🧱 [Consul micro-service cluster management](https://app-mesh.readthedocs.io/en/latest/CONSUL.html)
55
56
  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)
56
57
  Platform support | X86_64 <br> ARM32 <br> ARM64
57
- 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)
58
+ SDK | [Python](https://app-mesh.readthedocs.io/en/latest/api/appmesh.html#module-appmesh.client_http) <br> [Golang](https://github.com/laoshanxi/app-mesh/blob/main/src/sdk/go/client_http.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)
58
59
 
59
60
  ## Getting started
60
61
 
@@ -116,7 +117,6 @@ Refer to the [Installation doc](https://app-mesh.readthedocs.io/en/latest/Instal
116
117
 
117
118
  - [Build a powerful monitor system with Grafana/Prometheus/Loki](https://app-mesh.readthedocs.io/en/latest/success/build_powerful_monitor_system_with_Grafana_Prometheus_Loki.html)
118
119
  - [Customize application start behavior](https://app-mesh.readthedocs.io/en/latest/success/customize_app_startup_behavior.html)
119
- - [Manage cluster-level microservice applications](https://app-mesh.readthedocs.io/en/latest/success/manage_cluster_level_microservice_applications.html)
120
120
  - [Open service broker support local PV for Kubernetes](https://app-mesh.readthedocs.io/en/latest/success/open_service_broker_support_local_pv_for_K8S.html)
121
121
  - [Promote native application to microservice application](https://app-mesh.readthedocs.io/en/latest/success/promote_native_app_to_microservice_app.html)
122
122
  - [Secure REST file server](https://app-mesh.readthedocs.io/en/latest/success/secure_REST_file_server.html)
@@ -1,15 +1,16 @@
1
- appmesh/__init__.py,sha256=_I-kLcLy7DM3gG2JJTRM_hUxBu3zvIPm2wCsz3NYes4,493
1
+ appmesh/__init__.py,sha256=TY1y5B5cE57uhraEzCFOZRWuo9SY1R-fYNRan8hCZOM,1670
2
2
  appmesh/app.py,sha256=4lo66ob1ZFDgL8VYKxH4_sh-vbHcGkZNThURE0go-d4,10732
3
3
  appmesh/app_output.py,sha256=vfn322AyixblI8DbXds08h6L_ybObiaRSifsA1-Xcoo,1035
4
4
  appmesh/app_run.py,sha256=TJ9xVX8xqUN9-OOmr_8JlgXoyg3hTmDFNKvGf4w_oR4,1980
5
5
  appmesh/appmesh_client.py,sha256=7yy9c_ygJbqMekrUsHWmRObwHLK82qP65xQLXxfGd8U,339
6
- appmesh/client_http.py,sha256=jUIZJHrnu2-r6N6Cd9lQNPeQcZefB7ENl6DUn8Mugck,57896
6
+ appmesh/client_http.py,sha256=rVmGAc_nWkntoZBL7BCaQZtH9QOZXUis38tW9OhT2ps,54707
7
+ appmesh/client_http_oauth.py,sha256=1d51o0JX_xtB8d2bEuM7_XJHcwMnhcjkbIq7GE1Zxm8,6120
7
8
  appmesh/client_tcp.py,sha256=hE0T_2Z0OQZdF5zi--iuvu2_-ka0DfSSQ4BP3oHlg44,11243
8
9
  appmesh/server_http.py,sha256=zr9sfS8g_mtP2kuAfmz-qU7rLSFTVt3srbFXaCbl8Y0,4253
9
10
  appmesh/server_tcp.py,sha256=biBFF5IGWFOw2ru831cfmzn1DVXcBm9e-W6CP2VkfzE,1444
10
11
  appmesh/tcp_messages.py,sha256=4XRv5lSm_8ElMg_37SuyIRrfxI7XFNNP_7SdO7us3PA,1023
11
12
  appmesh/tcp_transport.py,sha256=f28zfZNH46tUHfT8F1PrCM1wUXiSBIW7R3ipMsXJqIU,8946
12
- appmesh-1.6.1.dist-info/METADATA,sha256=DvJTf5922gT6fc-iOWizqodwljYIkIlCCI1SeTd0juM,11847
13
- appmesh-1.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
- appmesh-1.6.1.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
15
- appmesh-1.6.1.dist-info/RECORD,,
13
+ appmesh-1.6.2.dist-info/METADATA,sha256=NljlBJBJxpevRRrgxFPyjNpxsYeu3FuUk7_klAhJCcs,11828
14
+ appmesh-1.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ appmesh-1.6.2.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
+ appmesh-1.6.2.dist-info/RECORD,,