hcs-core 0.1.307__py3-none-any.whl → 0.1.309__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.
- hcs_core/__init__.py +1 -1
- hcs_core/ctxp/cli_options.py +19 -3
- hcs_core/ctxp/cli_processor.py +10 -8
- hcs_core/ctxp/util.py +48 -1
- hcs_core/sglib/cli_options.py +2 -0
- hcs_core/sglib/client_util.py +28 -15
- hcs_core/sglib/login_support.py +1 -1
- {hcs_core-0.1.307.dist-info → hcs_core-0.1.309.dist-info}/METADATA +2 -2
- {hcs_core-0.1.307.dist-info → hcs_core-0.1.309.dist-info}/RECORD +10 -10
- {hcs_core-0.1.307.dist-info → hcs_core-0.1.309.dist-info}/WHEEL +0 -0
hcs_core/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.309"
|
hcs_core/ctxp/cli_options.py
CHANGED
|
@@ -13,6 +13,8 @@ See the License for the specific language governing permissions and
|
|
|
13
13
|
limitations under the License.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
import os
|
|
17
|
+
|
|
16
18
|
import click
|
|
17
19
|
|
|
18
20
|
verbose = click.option(
|
|
@@ -27,7 +29,7 @@ verbose = click.option(
|
|
|
27
29
|
output = click.option(
|
|
28
30
|
"--output",
|
|
29
31
|
"-o",
|
|
30
|
-
type=click.Choice(["json", "json-compact", "yaml", "yml", "
|
|
32
|
+
type=click.Choice(["json", "json-compact", "yaml", "yml", "table", "t", "text"], case_sensitive=False),
|
|
31
33
|
default=None,
|
|
32
34
|
hidden=True,
|
|
33
35
|
help="Specify output format",
|
|
@@ -101,10 +103,24 @@ force = click.option("--force/--grace", type=bool, default=True, help="Specify d
|
|
|
101
103
|
|
|
102
104
|
confirm = click.option("--confirm/--prompt", "-y", type=bool, default=False, help="Confirm the operation without prompt.")
|
|
103
105
|
|
|
106
|
+
env = click.option(
|
|
107
|
+
"--env",
|
|
108
|
+
multiple=True,
|
|
109
|
+
type=str,
|
|
110
|
+
required=False,
|
|
111
|
+
help="Alternative explicit in-line environment variable override in KEY=VALUE format.",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def apply_env(envs):
|
|
116
|
+
for kv in envs:
|
|
117
|
+
k, v = kv.split("=", 1)
|
|
118
|
+
os.environ[k.strip()] = v.strip()
|
|
119
|
+
|
|
104
120
|
|
|
105
|
-
def formatter(
|
|
121
|
+
def formatter(formatter=None, columns=None):
|
|
106
122
|
def decorator(f):
|
|
107
|
-
f.formatter =
|
|
123
|
+
f.formatter = formatter if formatter else columns
|
|
108
124
|
return f
|
|
109
125
|
|
|
110
126
|
return decorator
|
hcs_core/ctxp/cli_processor.py
CHANGED
|
@@ -24,7 +24,7 @@ from pathlib import Path
|
|
|
24
24
|
import click
|
|
25
25
|
from click.core import Group
|
|
26
26
|
|
|
27
|
-
from .util import avoid_trace_for_ctrl_c, print_error, print_output, validate_error_return
|
|
27
|
+
from .util import avoid_trace_for_ctrl_c, default_table_formatter, print_error, print_output, validate_error_return
|
|
28
28
|
|
|
29
29
|
_eager_loading = os.environ.get("_CTXP_EAGER_LOAD")
|
|
30
30
|
if _eager_loading:
|
|
@@ -192,15 +192,17 @@ def _default_io(cmd: click.Command):
|
|
|
192
192
|
|
|
193
193
|
telemetry_update(ctx.command_path, ctx.params)
|
|
194
194
|
|
|
195
|
-
if io_args["output"] == "table":
|
|
195
|
+
if io_args["output"] == "table" or io_args["output"] == "t":
|
|
196
196
|
|
|
197
197
|
def _format(data):
|
|
198
|
-
if
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
198
|
+
if hasattr(callback, "formatter"):
|
|
199
|
+
formatter = callback.__getattribute__("formatter")
|
|
200
|
+
else:
|
|
201
|
+
formatter = default_table_formatter
|
|
202
|
+
if isinstance(formatter, dict):
|
|
203
|
+
return default_table_formatter(data, formatter)
|
|
204
|
+
else:
|
|
205
|
+
return formatter(data)
|
|
204
206
|
|
|
205
207
|
io_args["format"] = _format
|
|
206
208
|
ret = callback(*args, **kwargs)
|
hcs_core/ctxp/util.py
CHANGED
|
@@ -13,6 +13,7 @@ See the License for the specific language governing permissions and
|
|
|
13
13
|
limitations under the License.
|
|
14
14
|
"""
|
|
15
15
|
|
|
16
|
+
import datetime
|
|
16
17
|
import json
|
|
17
18
|
import os
|
|
18
19
|
import re
|
|
@@ -26,6 +27,7 @@ import click
|
|
|
26
27
|
import httpx
|
|
27
28
|
import questionary
|
|
28
29
|
import yaml
|
|
30
|
+
import yumako
|
|
29
31
|
|
|
30
32
|
|
|
31
33
|
class CtxpException(Exception):
|
|
@@ -112,7 +114,7 @@ def print_output(data: Any, args: dict, file=sys.stdout):
|
|
|
112
114
|
text = data
|
|
113
115
|
else:
|
|
114
116
|
text = json.dumps(data, indent=4)
|
|
115
|
-
elif output == "table":
|
|
117
|
+
elif output == "table" or output == "t":
|
|
116
118
|
formatter = args["format"]
|
|
117
119
|
text = formatter(data)
|
|
118
120
|
else:
|
|
@@ -411,3 +413,48 @@ def colorize(data: dict, name: str, mapping: dict):
|
|
|
411
413
|
data[name] = click.style(s, fg=c)
|
|
412
414
|
else:
|
|
413
415
|
raise Exception(f"Unexpected mapping type: {type(mapping)} {mapping}")
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def default_table_formatter(data: Any, mapping: dict = None):
|
|
419
|
+
if not isinstance(data, list):
|
|
420
|
+
return data
|
|
421
|
+
|
|
422
|
+
def _restrict_readable_length(data: dict, name: str, length: int):
|
|
423
|
+
text = data.get(name)
|
|
424
|
+
if not text:
|
|
425
|
+
return
|
|
426
|
+
if len(text) > length:
|
|
427
|
+
data[name] = text[: length - 3] + "..."
|
|
428
|
+
|
|
429
|
+
field_mapping = {}
|
|
430
|
+
for d in data:
|
|
431
|
+
if "id" in d:
|
|
432
|
+
field_mapping["id"] = "Id"
|
|
433
|
+
if "name" in d:
|
|
434
|
+
field_mapping["name"] = "Name"
|
|
435
|
+
if "location" in d:
|
|
436
|
+
field_mapping["location"] = "Location"
|
|
437
|
+
if "type" in d:
|
|
438
|
+
field_mapping["type"] = "Type"
|
|
439
|
+
if "status" in d:
|
|
440
|
+
field_mapping["status"] = "Status"
|
|
441
|
+
if "createdAt" in d:
|
|
442
|
+
d["_createdStale"] = yumako.time.stale(d["createdAt"], datetime.timezone.utc)
|
|
443
|
+
field_mapping["_createdStale"] = "Created At"
|
|
444
|
+
if "updatedAt" in d:
|
|
445
|
+
d["_updatedStale"] = yumako.time.stale(d["updatedAt"], datetime.timezone.utc)
|
|
446
|
+
field_mapping["_updatedStale"] = "Updated At"
|
|
447
|
+
|
|
448
|
+
colorize(
|
|
449
|
+
d,
|
|
450
|
+
"status",
|
|
451
|
+
{
|
|
452
|
+
"READY": "green",
|
|
453
|
+
"SUCCESS": "green",
|
|
454
|
+
"ERROR": "red",
|
|
455
|
+
},
|
|
456
|
+
)
|
|
457
|
+
_restrict_readable_length(d, "name", 60)
|
|
458
|
+
if mapping:
|
|
459
|
+
field_mapping.update(mapping)
|
|
460
|
+
return format_table(data, fields_mapping=field_mapping)
|
hcs_core/sglib/cli_options.py
CHANGED
|
@@ -18,7 +18,9 @@ import os
|
|
|
18
18
|
import click
|
|
19
19
|
|
|
20
20
|
from hcs_core.ctxp import CtxpException, recent
|
|
21
|
+
from hcs_core.ctxp.cli_options import apply_env as apply_env
|
|
21
22
|
from hcs_core.ctxp.cli_options import confirm as confirm
|
|
23
|
+
from hcs_core.ctxp.cli_options import env as env
|
|
22
24
|
from hcs_core.ctxp.cli_options import exclude_field as exclude_field
|
|
23
25
|
from hcs_core.ctxp.cli_options import field as field
|
|
24
26
|
from hcs_core.ctxp.cli_options import first as first
|
hcs_core/sglib/client_util.py
CHANGED
|
@@ -288,10 +288,13 @@ def wait_for_res_deleted(
|
|
|
288
288
|
resource_name: str,
|
|
289
289
|
fn_get: Callable,
|
|
290
290
|
timeout: str,
|
|
291
|
-
|
|
291
|
+
polling_interval: int = 10,
|
|
292
292
|
fn_is_error: Callable = None,
|
|
293
293
|
):
|
|
294
294
|
timeout_seconds = _parse_timeout(timeout)
|
|
295
|
+
polling_interval_seconds = _parse_timeout(polling_interval)
|
|
296
|
+
if polling_interval_seconds < 3:
|
|
297
|
+
polling_interval_seconds = 3
|
|
295
298
|
start = time.time()
|
|
296
299
|
while True:
|
|
297
300
|
t = fn_get()
|
|
@@ -310,7 +313,7 @@ def wait_for_res_deleted(
|
|
|
310
313
|
sleep_seconds = remaining_seconds
|
|
311
314
|
if sleep_seconds > polling_interval_seconds:
|
|
312
315
|
sleep_seconds = polling_interval_seconds
|
|
313
|
-
|
|
316
|
+
time.sleep(sleep_seconds)
|
|
314
317
|
|
|
315
318
|
|
|
316
319
|
# flake8: noqa=E731
|
|
@@ -337,21 +340,25 @@ def wait_for_res_status(
|
|
|
337
340
|
field_name = get_status
|
|
338
341
|
get_status = lambda t: t[field_name]
|
|
339
342
|
if status_map:
|
|
340
|
-
if isinstance(status_map["ready"], str):
|
|
341
|
-
status_map["ready"] = [status_map["ready"]]
|
|
342
|
-
if isinstance(status_map["transition"], str):
|
|
343
|
-
status_map["transition"] = [status_map["transition"]]
|
|
344
|
-
if isinstance(status_map["error"], str):
|
|
345
|
-
status_map["error"] = [status_map["error"]]
|
|
346
343
|
if is_ready:
|
|
347
344
|
raise CtxpException("Can not specify is_ready when status_map is provided.")
|
|
348
345
|
if is_error:
|
|
349
346
|
raise CtxpException("Can not specify is_error when status_map is provided.")
|
|
350
347
|
if is_transition:
|
|
351
348
|
raise CtxpException("Can not specify is_transition when status_map is provided.")
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
349
|
+
|
|
350
|
+
ready_status = status_map["ready"]
|
|
351
|
+
error_status = status_map["error"]
|
|
352
|
+
transition_status = status_map["transition"]
|
|
353
|
+
if isinstance(ready_status, str):
|
|
354
|
+
ready_status = [ready_status]
|
|
355
|
+
if isinstance(error_status, str):
|
|
356
|
+
error_status = [error_status]
|
|
357
|
+
if isinstance(transition_status, str):
|
|
358
|
+
transition_status = [transition_status]
|
|
359
|
+
is_ready = lambda s: s in ready_status
|
|
360
|
+
is_error = lambda s: error_status is None or s in error_status
|
|
361
|
+
is_transition = lambda s: transition_status is None or s in transition_status
|
|
355
362
|
else:
|
|
356
363
|
if not is_ready:
|
|
357
364
|
raise CtxpException("Either status_map or is_ready must be specified.")
|
|
@@ -359,6 +366,9 @@ def wait_for_res_status(
|
|
|
359
366
|
raise CtxpException("Either status_map or is_error must be specified.")
|
|
360
367
|
if not is_transition:
|
|
361
368
|
raise CtxpException("Either status_map or is_transition must be specified.")
|
|
369
|
+
ready_status = None
|
|
370
|
+
error_status = None
|
|
371
|
+
transition_status = None
|
|
362
372
|
|
|
363
373
|
while True:
|
|
364
374
|
t = fn_get()
|
|
@@ -368,9 +378,9 @@ def wait_for_res_status(
|
|
|
368
378
|
raise CtxpException(prefix + "Not found.")
|
|
369
379
|
status = get_status(t)
|
|
370
380
|
if is_error(status):
|
|
371
|
-
msg = prefix + f"
|
|
372
|
-
if
|
|
373
|
-
msg += f", expected={
|
|
381
|
+
msg = prefix + f"Unexpected terminal state. Actual={status}"
|
|
382
|
+
if ready_status:
|
|
383
|
+
msg += f", expected={ready_status}"
|
|
374
384
|
print("-- DUMP START --", file=sys.stderr)
|
|
375
385
|
print(json.dumps(t, indent=4), file=sys.stderr)
|
|
376
386
|
print("-- DUMP END --", file=sys.stderr)
|
|
@@ -383,7 +393,10 @@ def wait_for_res_status(
|
|
|
383
393
|
now = time.time()
|
|
384
394
|
remaining_seconds = timeout_seconds - (now - start)
|
|
385
395
|
if remaining_seconds < 1:
|
|
386
|
-
|
|
396
|
+
msg = prefix + f"Timeout. Current: {status}."
|
|
397
|
+
if ready_status:
|
|
398
|
+
msg += f" Expected: {ready_status}."
|
|
399
|
+
raise TimeoutError(msg)
|
|
387
400
|
sleep_seconds = remaining_seconds
|
|
388
401
|
if sleep_seconds > polling_interval_seconds:
|
|
389
402
|
sleep_seconds = polling_interval_seconds
|
hcs_core/sglib/login_support.py
CHANGED
|
@@ -61,7 +61,7 @@ _auth_success_html = """
|
|
|
61
61
|
</style>
|
|
62
62
|
</head>
|
|
63
63
|
<body>
|
|
64
|
-
<h3>You have successfully logged into
|
|
64
|
+
<h3>You have successfully logged into Omnissa Horizon Cloud Service.</h3>
|
|
65
65
|
<p>You can close this window, and return to the terminal.</p>
|
|
66
66
|
<br/>
|
|
67
67
|
<p><a href="https://github.com/euc-eng/hcs-cli/blob/dev/README.md">HCS CLI</a> is in beta. <a href="https://github.com/euc-eng/hcs-cli/blob/main/doc/hcs-cli-cheatsheet.md">Cheatsheet</a>:</p>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hcs-core
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.309
|
|
4
4
|
Summary: Horizon Cloud Service CLI module.
|
|
5
5
|
Project-URL: Homepage, https://github.com/euc-eng/hcs-cli
|
|
6
6
|
Project-URL: Bug Tracker, https://github.com/euc-eng/hcs-cli/issues
|
|
@@ -36,7 +36,7 @@ Requires-Dist: schedule>=1.1.0
|
|
|
36
36
|
Requires-Dist: setuptools>=70.0.0
|
|
37
37
|
Requires-Dist: tabulate>=0.9.0
|
|
38
38
|
Requires-Dist: websocket-client>=1.2.3
|
|
39
|
-
Requires-Dist: yumako>=0.1.
|
|
39
|
+
Requires-Dist: yumako>=0.1.36
|
|
40
40
|
Provides-Extra: dev
|
|
41
41
|
Requires-Dist: bandit; extra == 'dev'
|
|
42
42
|
Requires-Dist: black; extra == 'dev'
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
hcs_core/__init__.py,sha256=
|
|
1
|
+
hcs_core/__init__.py,sha256=VUKQ0_TMXT6yqCtvomTkg0PwNyCwosoVnBBfIM5i3vc,24
|
|
2
2
|
hcs_core/ctxp/__init__.py,sha256=bHVHhJP10Luz1a3Kk3zFx14dAO4SY6Q20Lrv8rNWWGc,1075
|
|
3
3
|
hcs_core/ctxp/_init.py,sha256=fMcRMPfJx-N0c-u0Zj2sFVKQL1-lWQd28gooAZETGUA,2933
|
|
4
|
-
hcs_core/ctxp/cli_options.py,sha256=
|
|
5
|
-
hcs_core/ctxp/cli_processor.py,sha256=
|
|
4
|
+
hcs_core/ctxp/cli_options.py,sha256=KFu9_cRB1OyXaZJFLDCb3PpuQ0_5-ou2cdaL_q0_Lns,3098
|
|
5
|
+
hcs_core/ctxp/cli_processor.py,sha256=thxNqGIztWTdhDWgzs5NopCSk8yDy1FzG-weqfmIUbE,7756
|
|
6
6
|
hcs_core/ctxp/cmd_util.py,sha256=_-VwQSmkfi52qWC3uHQI06mSiIPfsZroDruTDYHXiMA,3119
|
|
7
7
|
hcs_core/ctxp/config.py,sha256=vRdzPxi3Yrt04cnR6b5mJwEOtYBh21qvmlSSsgyGoI4,931
|
|
8
8
|
hcs_core/ctxp/context.py,sha256=LafhucyGRGYLmnXoZLZOKRWXUwJ1KzP-6vjDTTrC8j4,3451
|
|
@@ -22,7 +22,7 @@ hcs_core/ctxp/task_schd.py,sha256=mvZMeKDSSo2p7VidSoZY1XZj433TQn_YF9SGJEzl9lg,45
|
|
|
22
22
|
hcs_core/ctxp/telemetry.py,sha256=tSjI_8OE2Ix3n--YHAO9sPmzi8ETbFHEPxzS52-usmM,3476
|
|
23
23
|
hcs_core/ctxp/template_util.py,sha256=XslvIuRBlTVsUW0Y9M_D8gUPc1jWq6X2p4At2VAe1KU,731
|
|
24
24
|
hcs_core/ctxp/timeutil.py,sha256=RyRrIRdFHbIghdB8wbC8VdABvc7hki2v51b1x2JvHgo,445
|
|
25
|
-
hcs_core/ctxp/util.py,sha256=
|
|
25
|
+
hcs_core/ctxp/util.py,sha256=UTTtP-jjt3r5N-CTf0We64yLPWfFIl9dNSHkfsbFvLY,14225
|
|
26
26
|
hcs_core/ctxp/var_template.py,sha256=cTjj1UJ58ac6s5z4Oh5hSDQwKixq-rdbCF1D8akjAo0,3219
|
|
27
27
|
hcs_core/ctxp/built_in_cmds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
hcs_core/ctxp/built_in_cmds/_ut.py,sha256=e50XBmPim2qRe0RYk_XAuRz1HWYyLJuMu-6dVxWR_fQ,3356
|
|
@@ -43,13 +43,13 @@ hcs_core/plan/provider/dev/dummy.py,sha256=zKEr9J4WHhlN5gFdmrFyEfCF0xlQlCJg0CC1d
|
|
|
43
43
|
hcs_core/plan/provider/dev/fibonacci.py,sha256=8WhDr5c9harNAlVPZomQJEqbWe0hUqbppO6ZkwEUcJ0,1104
|
|
44
44
|
hcs_core/sglib/__init__.py,sha256=oT0etW7vsEbHlXiGL5x23ZXyyFqeLi81RxQQ5lfKSV0,654
|
|
45
45
|
hcs_core/sglib/auth.py,sha256=r9zgLdnybuHsf3_j6nTP4SGoS2dD3keYZ-c25o2Mx64,6766
|
|
46
|
-
hcs_core/sglib/cli_options.py,sha256=
|
|
47
|
-
hcs_core/sglib/client_util.py,sha256=
|
|
46
|
+
hcs_core/sglib/cli_options.py,sha256=GBJ59u9iWiCfJt-5F8qw_JGfMRfB-LcLeiKAQkmMh_c,2548
|
|
47
|
+
hcs_core/sglib/client_util.py,sha256=4YH-QoqkpF2DtXhemYx4vM19YBzUWk4iNL2BvYLTDmg,14617
|
|
48
48
|
hcs_core/sglib/csp.py,sha256=UcO68YtLOPDQWiTjPVIPwQ2Z-Mywc-154aoIkLdyzwE,10991
|
|
49
49
|
hcs_core/sglib/ez_client.py,sha256=dWQx-EMTrySz1EVzsSu4ZezORR3_iEOAcZigtbuvIQ8,8404
|
|
50
50
|
hcs_core/sglib/hcs_client.py,sha256=pjrAVQDEy2tiQMypMpOzODFntT6aNHXjje8or_mkL2U,804
|
|
51
51
|
hcs_core/sglib/init.py,sha256=w_0ZU70Q1TGbSZsqSi7ewKQqpExFlepOT7mIqH0wnho,310
|
|
52
|
-
hcs_core/sglib/login_support.py,sha256=
|
|
52
|
+
hcs_core/sglib/login_support.py,sha256=unwzx8_W8knWqSm-jN9wFzkQGpw4U5z4kfzKb_Sjlvw,7575
|
|
53
53
|
hcs_core/sglib/payload_util.py,sha256=Hnj7rjzrQ1j5gpbrwZX34biN8MIZjy6dOJZ63ulmzdw,685
|
|
54
54
|
hcs_core/sglib/requtil.py,sha256=O37DrD4VVBmmRkkHJLbDtPfFq8l6fLZwYZggt2FTEFc,920
|
|
55
55
|
hcs_core/sglib/utils.py,sha256=8a-e-nUhAbulZtV05CB5loov6Kgq8_Q0TxYwfvu7Bj8,3178
|
|
@@ -64,6 +64,6 @@ hcs_core/util/query_util.py,sha256=uYfcEF_00eUs_S5OK64zpH0cnb6dwy91_J1OY5ZrFVs,3
|
|
|
64
64
|
hcs_core/util/scheduler.py,sha256=bPpCmGUL1UctJMfLPAg-h4Hl2YZr96FiI78-G_Usn08,2958
|
|
65
65
|
hcs_core/util/ssl_util.py,sha256=MvU102fGwWWh9hhSmLnn1qQIWuD6TjZnN0iH0MXUtW0,1239
|
|
66
66
|
hcs_core/util/versions.py,sha256=6nyyZzi3P69WQfioPc2_YWZQcUc13mC1eKoK58b3WUQ,1709
|
|
67
|
-
hcs_core-0.1.
|
|
68
|
-
hcs_core-0.1.
|
|
69
|
-
hcs_core-0.1.
|
|
67
|
+
hcs_core-0.1.309.dist-info/METADATA,sha256=Ay1v0mInJ51bxqir-k1pxvjNEPBEuegwAo68GdQUn8g,1951
|
|
68
|
+
hcs_core-0.1.309.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
69
|
+
hcs_core-0.1.309.dist-info/RECORD,,
|
|
File without changes
|