cgcsdk 1.0.15__tar.gz → 1.0.17__tar.gz
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.
- {cgcsdk-1.0.15/cgcsdk.egg-info → cgcsdk-1.0.17}/PKG-INFO +7 -10
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/.env +1 -1
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/CHANGELOG.md +24 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_responses.py +10 -4
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/cgc_cmd.py +3 -1
- cgcsdk-1.0.17/cgc/commands/cgc_cmd_responses.py +109 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/cgc_helpers.py +13 -3
- cgcsdk-1.0.17/cgc/commands/cgc_models.py +17 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/compute_cmd.py +40 -6
- cgcsdk-1.0.17/cgc/commands/compute/compute_models.py +35 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/compute_responses.py +6 -2
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/db/db_cmd.py +9 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/db/db_models.py +12 -10
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/job_utils.py +13 -6
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/jobs_cmd.py +11 -0
- cgcsdk-1.0.17/cgc/commands/user/keys_models.py +31 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/data_model.py +2 -3
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/volume_cmd.py +34 -19
- cgcsdk-1.0.17/cgc/commands/volume/volume_models.py +22 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/volume_responses.py +27 -1
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/telemetry/basic.py +1 -1
- cgcsdk-1.0.17/cgc/utils/config_utils.py +218 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/consts/env_consts.py +0 -4
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/consts/message_consts.py +1 -1
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/version_control.py +23 -6
- {cgcsdk-1.0.15 → cgcsdk-1.0.17/cgcsdk.egg-info}/PKG-INFO +7 -10
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/SOURCES.txt +1 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/setup.py +13 -9
- cgcsdk-1.0.15/cgc/commands/cgc_cmd_responses.py +0 -82
- cgcsdk-1.0.15/cgc/commands/cgc_models.py +0 -9
- cgcsdk-1.0.15/cgc/commands/compute/compute_models.py +0 -37
- cgcsdk-1.0.15/cgc/commands/user/keys_models.py +0 -16
- cgcsdk-1.0.15/cgc/utils/config_utils.py +0 -116
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/LICENSE +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/MANIFEST.in +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/README.md +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/cgc.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_cmd.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_logic.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/billing_cmd.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/billing_responses.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/billing_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/compute_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/db/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/debug/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/debug/debug_cmd.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/exceptions.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/jobs_responses.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/resource/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/resource/resource_cmd.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/resource/resource_responses.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/keys_cmd.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/keys_responses.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/keys_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_cmd.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_models.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_responses.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/volume_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/config.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/exceptions.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/job.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/postgresql.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/resource.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/server.crt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/telemetry/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_invoice.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_status.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_stop_events_compute.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_stop_events_volume.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_compute_list.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_compute_list_no_labels.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_tabulate_response.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_volume_list.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/responses_tests.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/click_group.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/consts/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/__init__.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/aes_crypto.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/encryption_module.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/rsa_crypto.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/custom_exceptions.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/get_headers_data.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/message_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/prepare_headers.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/requests_helper.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/response_utils.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/update.py +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/dependency_links.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/entry_points.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/requires.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/top_level.txt +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/pyproject.toml +0 -0
- {cgcsdk-1.0.15 → cgcsdk-1.0.17}/setup.cfg +0 -0
@@ -1,23 +1,20 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: cgcsdk
|
3
|
-
Version: 1.0.
|
4
|
-
Summary:
|
5
|
-
Home-page: https://
|
3
|
+
Version: 1.0.17
|
4
|
+
Summary: CGC Core REST API client
|
5
|
+
Home-page: https://cgc.comtegra.cloud/
|
6
6
|
Author: Comtegra AI Team
|
7
7
|
Author-email: ai@comtegra.pl
|
8
8
|
License: BSD 2-clause
|
9
9
|
Project-URL: Documentation, https://docs.cgc.comtegra.cloud/
|
10
|
-
Project-URL: GitHub, https://git.comtegra.pl/
|
11
|
-
Project-URL: Changelog, https://git.comtegra.pl/
|
12
|
-
Keywords: cloud,sdk,orchestrator,kubernetes,jupyter-notebook
|
13
|
-
Classifier: Development Status ::
|
10
|
+
Project-URL: GitHub, https://git.comtegra.pl/k8s/cgc-client-k8s-cloud
|
11
|
+
Project-URL: Changelog, https://git.comtegra.pl/k8s/cgc-client-k8s-cloud/-/blob/main/cgc/CHANGELOG.md
|
12
|
+
Keywords: cloud,sdk,orchestrator,kubernetes,jupyter-notebook,cgc-core
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
14
14
|
Classifier: Intended Audience :: Science/Research
|
15
15
|
Classifier: License :: OSI Approved :: BSD License
|
16
16
|
Classifier: Operating System :: POSIX :: Linux
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
18
|
-
Classifier: Programming Language :: Python :: 3.8
|
19
|
-
Classifier: Programming Language :: Python :: 3.9
|
20
|
-
Classifier: Programming Language :: Python :: 3.10
|
21
18
|
Classifier: Programming Language :: Python :: 3.11
|
22
19
|
Classifier: Programming Language :: Python :: 3.12
|
23
20
|
Description-Content-Type: text/markdown
|
@@ -1,5 +1,29 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 1.0.17
|
4
|
+
|
5
|
+
Release on Aug 19, 2024
|
6
|
+
|
7
|
+
* `cgc port list` now shows which ports are ingress (`cgc resource ingress app_name`)
|
8
|
+
* fix bug for the `cgc keys ssh create` command
|
9
|
+
* `cgc context list` now shows which context is active
|
10
|
+
* `cgc context list` now shows context server address
|
11
|
+
|
12
|
+
## 1.0.16
|
13
|
+
|
14
|
+
Release on Aug 02, 2024
|
15
|
+
|
16
|
+
* dynamic storage classes for volumes
|
17
|
+
* dynamic templates available for compute
|
18
|
+
* dynamic templates available for databases
|
19
|
+
* fixed bug: context switched to cfg.json after CGC update
|
20
|
+
* updated command: `cgc status`, now it is fully dynamic
|
21
|
+
* add flag `-y` to `cgc compute port` group commands
|
22
|
+
* `active_deadline_seconds` to `cgc job create` command
|
23
|
+
* `cgc db create` now have option `-d` available
|
24
|
+
* updated displayed values with `cgc job list`
|
25
|
+
* updated version control messages
|
26
|
+
|
3
27
|
## 1.0.15
|
4
28
|
|
5
29
|
Release on June 27, 2024
|
@@ -3,8 +3,13 @@ import os
|
|
3
3
|
|
4
4
|
from cgc.commands.auth import auth_utils
|
5
5
|
from cgc.commands.auth import auth_logic
|
6
|
-
from cgc.utils.consts.env_consts import TMP_DIR
|
7
|
-
from cgc.utils.config_utils import
|
6
|
+
from cgc.utils.consts.env_consts import TMP_DIR
|
7
|
+
from cgc.utils.config_utils import (
|
8
|
+
get_config_path,
|
9
|
+
save_to_config,
|
10
|
+
get_config_file_name,
|
11
|
+
save_to_local_config_context,
|
12
|
+
)
|
8
13
|
from cgc.utils.message_utils import key_error_decorator_for_helpers
|
9
14
|
|
10
15
|
|
@@ -17,6 +22,7 @@ def auth_register_response(
|
|
17
22
|
aes_key, password = auth_utils.get_aes_key_and_password(unzip_dir, priv_key_bytes)
|
18
23
|
|
19
24
|
os.environ["CONFIG_FILE_NAME"] = config_filename
|
25
|
+
save_to_local_config_context(config_filename)
|
20
26
|
save_to_config(
|
21
27
|
user_id=user_id,
|
22
28
|
password=password,
|
@@ -27,8 +33,8 @@ def auth_register_response(
|
|
27
33
|
)
|
28
34
|
auth_logic.auth_create_api_key_with_save()
|
29
35
|
shutil.rmtree(TMP_DIR_PATH)
|
30
|
-
#
|
31
|
-
if config_filename == "
|
36
|
+
# cfg.json
|
37
|
+
if config_filename == "cfg.json":
|
32
38
|
return f"Register successful! You can now use the CLI. Saved data to:{os.path.join(get_config_path(),config_filename)}\n\
|
33
39
|
Consider backup this file. It stores data accessible only to you with which you can access CGC platform."
|
34
40
|
return f"New context created successfully! \nNew config file saved to: {os.path.join(get_config_path(),config_filename)}\n\
|
@@ -12,10 +12,11 @@ from cgc.utils.prepare_headers import get_api_url_and_prepare_headers
|
|
12
12
|
from cgc.utils.response_utils import retrieve_and_validate_response_send_metric
|
13
13
|
from cgc.telemetry.basic import telemetry_permission_set
|
14
14
|
from cgc.commands.compute.compute_responses import compute_logs_response
|
15
|
+
|
15
16
|
# from cgc.commands.auth.auth_cmd import auth_register
|
16
17
|
from cgc.utils import set_environment_data, check_if_config_exist, list_all_config_files
|
17
18
|
from cgc.commands.cgc_helpers import table_of_user_context_files
|
18
|
-
from cgc.utils.config_utils import config_path
|
19
|
+
from cgc.utils.config_utils import config_path, save_to_local_config_context
|
19
20
|
from cgc.utils.consts.env_consts import ENV_FILE_PATH
|
20
21
|
|
21
22
|
|
@@ -100,6 +101,7 @@ def switch_context(number: int):
|
|
100
101
|
# config_filename=file_name,
|
101
102
|
# )
|
102
103
|
set_environment_data("CONFIG_FILE_NAME", file_name)
|
104
|
+
save_to_local_config_context(file_name)
|
103
105
|
click.echo(f"Context file changed to: {file_name}")
|
104
106
|
|
105
107
|
|
@@ -0,0 +1,109 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
from typing import Union
|
3
|
+
from tabulate import tabulate
|
4
|
+
from cgc.utils.message_utils import key_error_decorator_for_helpers
|
5
|
+
|
6
|
+
|
7
|
+
def _resource_match(resource: str) -> Union[str, None]:
|
8
|
+
if resource == "requests.cpu":
|
9
|
+
return "Total CPU"
|
10
|
+
elif resource == "requests.memory":
|
11
|
+
return "Total RAM"
|
12
|
+
elif resource == "requests.nvidia.com/gpu":
|
13
|
+
return "Total GPU"
|
14
|
+
elif resource.startswith("requests.comtegra.cloud/"):
|
15
|
+
gpu_type = resource.split("/")[-1]
|
16
|
+
return f"GPU {gpu_type.upper()}"
|
17
|
+
elif resource == "persistentvolumeclaims":
|
18
|
+
return "Volume Count"
|
19
|
+
elif resource == "requests.storage":
|
20
|
+
return "Total Storage"
|
21
|
+
elif resource.endswith(".storageclass.storage.k8s.io/requests.storage"):
|
22
|
+
storage_class = resource.split(".")[0]
|
23
|
+
return f"Storage ({storage_class})"
|
24
|
+
else:
|
25
|
+
return None
|
26
|
+
|
27
|
+
|
28
|
+
class ResourceOrder(Enum):
|
29
|
+
CPU = 1
|
30
|
+
MEMORY = 2
|
31
|
+
GPU = 3
|
32
|
+
STORAGE = 4
|
33
|
+
VOLUME = 5
|
34
|
+
GPU_TYPE = 6
|
35
|
+
OTHER = 7
|
36
|
+
|
37
|
+
|
38
|
+
def _resource_order(resource: str) -> ResourceOrder:
|
39
|
+
if resource == "requests.cpu":
|
40
|
+
return ResourceOrder.CPU
|
41
|
+
elif resource == "requests.memory":
|
42
|
+
return ResourceOrder.MEMORY
|
43
|
+
elif resource == "requests.nvidia.com/gpu":
|
44
|
+
return ResourceOrder.GPU
|
45
|
+
elif resource.startswith("requests.comtegra.cloud/"):
|
46
|
+
return ResourceOrder.GPU_TYPE
|
47
|
+
elif resource == "persistentvolumeclaims":
|
48
|
+
return ResourceOrder.VOLUME
|
49
|
+
elif resource == "requests.storage":
|
50
|
+
return ResourceOrder.STORAGE
|
51
|
+
elif resource.endswith(".storageclass.storage.k8s.io/requests.storage"):
|
52
|
+
return ResourceOrder.STORAGE
|
53
|
+
else:
|
54
|
+
return ResourceOrder.OTHER
|
55
|
+
|
56
|
+
|
57
|
+
@key_error_decorator_for_helpers
|
58
|
+
def cgc_status_response(data: dict):
|
59
|
+
"""Generates and prints resource limits and available resources in a pretty format
|
60
|
+
|
61
|
+
:param data: data to extrct resources from
|
62
|
+
:type data: dict
|
63
|
+
:param metric_error: error metric for graphana
|
64
|
+
:type metric_error: str
|
65
|
+
"""
|
66
|
+
|
67
|
+
resources_available: dict = data["details"]["available_resources"]
|
68
|
+
resources_limits: dict = data["details"]["limits_resources"]
|
69
|
+
list_headers = ["Resource", "Available", "Limit"]
|
70
|
+
resource_names = []
|
71
|
+
|
72
|
+
resources_available_list = []
|
73
|
+
resources_limits_list = []
|
74
|
+
resources_available = {
|
75
|
+
key: value
|
76
|
+
for key, value in sorted(
|
77
|
+
resources_available.items(),
|
78
|
+
key=lambda x: (_resource_order(x[0]).value, x[1]),
|
79
|
+
)
|
80
|
+
}
|
81
|
+
for resource, available in resources_available.items():
|
82
|
+
if resource not in resources_limits.keys():
|
83
|
+
continue
|
84
|
+
resource_parsed = _resource_match(resource)
|
85
|
+
if resource_parsed is None:
|
86
|
+
continue
|
87
|
+
resource_names.append(resource_parsed)
|
88
|
+
limit = resources_limits[resource]
|
89
|
+
if "storage" in resource or "memory" in resource:
|
90
|
+
available = f"{available} GB"
|
91
|
+
limit = f"{limit} GB"
|
92
|
+
else:
|
93
|
+
available = int(available)
|
94
|
+
limit = int(limit)
|
95
|
+
resources_available_list.append(available)
|
96
|
+
resources_limits_list.append(limit)
|
97
|
+
|
98
|
+
return tabulate(
|
99
|
+
list(zip(resource_names, resources_available_list, resources_limits_list)),
|
100
|
+
headers=list_headers,
|
101
|
+
)
|
102
|
+
|
103
|
+
|
104
|
+
def cgc_logs_response(data: dict):
|
105
|
+
return "\n".join(
|
106
|
+
"==> %s/%s <==\n%s" % (pod, cont, log)
|
107
|
+
for pod, containers in data["details"]["logs"].items()
|
108
|
+
for cont, log in containers.items()
|
109
|
+
)
|
@@ -1,12 +1,18 @@
|
|
1
1
|
from typing import List
|
2
2
|
from cgc.utils import quick_sort
|
3
|
-
from cgc.utils.config_utils import read_from_cfg
|
3
|
+
from cgc.utils.config_utils import get_config_file_name, read_from_cfg
|
4
4
|
from tabulate import tabulate
|
5
5
|
|
6
6
|
|
7
|
+
def _is_main_context_file(file: str) -> bool:
|
8
|
+
if get_config_file_name() == file:
|
9
|
+
return True
|
10
|
+
return None
|
11
|
+
|
12
|
+
|
7
13
|
def table_of_user_context_files(config_files: List[str]):
|
8
14
|
# print tabulate of: [context NR | namespace | user_id]
|
9
|
-
headers = ["Context No.", "Namespace", "User ID"]
|
15
|
+
headers = ["Context No.", "Namespace", "User ID", "URL", "Is active"]
|
10
16
|
contexts = []
|
11
17
|
contexts_nrs = []
|
12
18
|
for file in config_files:
|
@@ -16,13 +22,17 @@ def table_of_user_context_files(config_files: List[str]):
|
|
16
22
|
) # should never throw exception with good config_file list
|
17
23
|
contexts_nrs.append(file_context[0])
|
18
24
|
file_data = read_from_cfg(None, file)
|
19
|
-
values_to_read = ["namespace", "user_id"]
|
25
|
+
values_to_read = ["namespace", "user_id", "cgc_api_url"]
|
20
26
|
for k in values_to_read:
|
21
27
|
try:
|
22
28
|
value = file_data[k]
|
23
29
|
except KeyError:
|
24
30
|
value = None
|
31
|
+
if k == "cgc_api_url":
|
32
|
+
value = "https://cgc-api.comtegra.cloud:443"
|
25
33
|
file_context.append(value)
|
34
|
+
|
35
|
+
file_context.append(_is_main_context_file(file))
|
26
36
|
contexts.append(file_context)
|
27
37
|
|
28
38
|
contexts_nrs_sorted = quick_sort(contexts_nrs)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from abc import ABC, abstractmethod
|
2
|
+
|
3
|
+
|
4
|
+
class CGCEntityList(ABC):
|
5
|
+
"""Base class for other lists"""
|
6
|
+
|
7
|
+
@staticmethod
|
8
|
+
@abstractmethod
|
9
|
+
def load_data() -> list[str]:
|
10
|
+
pass
|
11
|
+
|
12
|
+
@classmethod
|
13
|
+
def get_list(cls) -> list[str]:
|
14
|
+
try:
|
15
|
+
return [el for el in cls.load_data()]
|
16
|
+
except TypeError:
|
17
|
+
return []
|
@@ -96,9 +96,21 @@ def compute_filebrowser_delete():
|
|
96
96
|
default=True,
|
97
97
|
help="If set, port will NOT be exposed to the internet. By default port is exposed to the internet.",
|
98
98
|
)
|
99
|
-
|
99
|
+
@click.option(
|
100
|
+
"-y",
|
101
|
+
"--yes",
|
102
|
+
"yes",
|
103
|
+
is_flag=True,
|
104
|
+
type=click.BOOL,
|
105
|
+
required=False,
|
106
|
+
default=False,
|
107
|
+
help="If set, command will not ask for confirmation",
|
108
|
+
)
|
109
|
+
def compute_port_add(
|
110
|
+
app_name: str, port_name: str, port: int, ingress: bool, yes: bool
|
111
|
+
):
|
100
112
|
"""Add a port to a running resource"""
|
101
|
-
while True:
|
113
|
+
while True and not yes:
|
102
114
|
click.echo(
|
103
115
|
'Adding a port to a running resource will expose it to the internet. If you want to add a port without exposing it to the internet, use the "--no-ingress" flag.'
|
104
116
|
)
|
@@ -161,9 +173,21 @@ def compute_port_add(app_name: str, port_name: str, port: int, ingress: bool):
|
|
161
173
|
default=True,
|
162
174
|
help="If set, port will NOT be exposed to the internet. By default port is exposed to the internet.",
|
163
175
|
)
|
164
|
-
|
176
|
+
@click.option(
|
177
|
+
"-y",
|
178
|
+
"--yes",
|
179
|
+
"yes",
|
180
|
+
is_flag=True,
|
181
|
+
type=click.BOOL,
|
182
|
+
required=False,
|
183
|
+
default=False,
|
184
|
+
help="If set, command will not ask for confirmation",
|
185
|
+
)
|
186
|
+
def compute_port_update(
|
187
|
+
app_name: str, port_name: str, port: int, ingress: bool, yes: bool
|
188
|
+
):
|
165
189
|
"""Update a port in a running resource"""
|
166
|
-
while True:
|
190
|
+
while True and not yes:
|
167
191
|
click.echo(
|
168
192
|
'Updating a port in a running resource will expose it to the internet. If you want to update a port without exposing it to the internet, use the "--no-ingress" flag.'
|
169
193
|
)
|
@@ -204,9 +228,19 @@ def compute_port_update(app_name: str, port_name: str, port: int, ingress: bool)
|
|
204
228
|
required=True,
|
205
229
|
help="Name of port",
|
206
230
|
)
|
207
|
-
|
231
|
+
@click.option(
|
232
|
+
"-y",
|
233
|
+
"--yes",
|
234
|
+
"yes",
|
235
|
+
is_flag=True,
|
236
|
+
type=click.BOOL,
|
237
|
+
required=False,
|
238
|
+
default=False,
|
239
|
+
help="If set, command will not ask for confirmation",
|
240
|
+
)
|
241
|
+
def compute_port_delete(app_name: str, port_name: str, yes: bool):
|
208
242
|
"""Delete a port from a running resource"""
|
209
|
-
while True:
|
243
|
+
while True and not yes:
|
210
244
|
click.echo(
|
211
245
|
'Deleting a port from a running resource will expose it to the internet. If you want to delete a port without exposing it to the internet, use the "--no-ingress" flag.'
|
212
246
|
)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
|
3
|
+
from cgc.commands.cgc_models import CGCEntityList
|
4
|
+
from cgc.utils.config_utils import read_from_local_cfg
|
5
|
+
import cgc.utils.version_control as version_control
|
6
|
+
|
7
|
+
|
8
|
+
class ComputesList(CGCEntityList):
|
9
|
+
"""List of compute templates in cgc-server"""
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
def load_data() -> list[str]:
|
13
|
+
try:
|
14
|
+
return read_from_local_cfg("compute_templates")
|
15
|
+
except FileNotFoundError:
|
16
|
+
version_control.get_server_version() # possible loop on error
|
17
|
+
return ComputesList.load_data()
|
18
|
+
|
19
|
+
|
20
|
+
class GPUsList(Enum):
|
21
|
+
"""List of templates in cgc-server
|
22
|
+
|
23
|
+
:param Enum: name of template
|
24
|
+
:type Enum: str
|
25
|
+
"""
|
26
|
+
|
27
|
+
V100 = "V100"
|
28
|
+
A100 = "A100"
|
29
|
+
A5000 = "A5000"
|
30
|
+
H100 = "H100"
|
31
|
+
P40 = "P40"
|
32
|
+
P100 = "P100"
|
33
|
+
|
34
|
+
def get_list() -> list[str]:
|
35
|
+
return [el.value for el in GPUsList]
|
@@ -9,12 +9,16 @@ from cgc.utils.response_utils import (
|
|
9
9
|
tabulate_a_response,
|
10
10
|
fill_missing_values_in_a_response,
|
11
11
|
)
|
12
|
-
from cgc.utils.message_utils import prepare_warning_message
|
13
12
|
|
14
13
|
|
15
14
|
@key_error_decorator_for_helpers
|
16
15
|
def get_compute_port_list(data: dict) -> list:
|
17
|
-
|
16
|
+
resource_ports_data = data["details"]["ports"]["ports"]
|
17
|
+
ingress_data = data["details"]["ingress"]
|
18
|
+
ingress_port_names = [port["port_name"] for port in ingress_data]
|
19
|
+
for port in resource_ports_data:
|
20
|
+
port["ingress"] = True if port["name"] in ingress_port_names else False
|
21
|
+
return resource_ports_data
|
18
22
|
|
19
23
|
|
20
24
|
@key_error_decorator_for_helpers
|
@@ -46,11 +46,19 @@ def db_group():
|
|
46
46
|
multiple=True,
|
47
47
|
help="Volume name to be mounted with default mount path",
|
48
48
|
)
|
49
|
+
@click.option(
|
50
|
+
"-d",
|
51
|
+
"--resource-data",
|
52
|
+
"resource_data",
|
53
|
+
multiple=True,
|
54
|
+
help="List of optional arguments to be passed to the app, key=value format",
|
55
|
+
)
|
49
56
|
def db_create(
|
50
57
|
entity: str,
|
51
58
|
cpu: int,
|
52
59
|
memory: int,
|
53
60
|
volumes: list[str],
|
61
|
+
resource_data: list[str],
|
54
62
|
name: str,
|
55
63
|
):
|
56
64
|
"""
|
@@ -81,6 +89,7 @@ def db_create(
|
|
81
89
|
cpu=cpu,
|
82
90
|
memory=memory,
|
83
91
|
volumes=volumes,
|
92
|
+
resource_data=resource_data,
|
84
93
|
)
|
85
94
|
__res = call_api(
|
86
95
|
request=EndpointTypes.post,
|
@@ -1,19 +1,21 @@
|
|
1
1
|
from cgc.commands.cgc_models import CGCEntityList
|
2
2
|
from cgc.commands.exceptions import DatabaseCreationException
|
3
|
+
from cgc.utils.config_utils import read_from_local_cfg
|
4
|
+
import cgc.utils.version_control as version_control
|
3
5
|
|
4
6
|
|
5
7
|
class DatabasesList(CGCEntityList):
|
6
|
-
"""List of templates in cgc-server
|
8
|
+
"""List of database templates in cgc-server"""
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
@staticmethod
|
11
|
+
def load_data() -> list[str]:
|
12
|
+
try:
|
13
|
+
list_of_templates = read_from_local_cfg("database_templates")
|
14
|
+
except FileNotFoundError:
|
15
|
+
version_control.get_server_version() # possible loop on error
|
16
|
+
return DatabasesList.load_data()
|
17
|
+
list_of_templates.extend(["mongodb", "redis"])
|
18
|
+
return list_of_templates
|
17
19
|
|
18
20
|
@staticmethod
|
19
21
|
def verify(entity: str) -> str:
|
@@ -28,6 +28,7 @@ def job_create_payload(
|
|
28
28
|
startup_command: str = "",
|
29
29
|
repository_secret: str = "",
|
30
30
|
ttl_seconds_after_finished: Optional[int] = None,
|
31
|
+
active_deadline_seconds: Optional[int] = None,
|
31
32
|
):
|
32
33
|
"""
|
33
34
|
Create payload for app creation.
|
@@ -38,6 +39,8 @@ def job_create_payload(
|
|
38
39
|
|
39
40
|
if ttl_seconds_after_finished is not None:
|
40
41
|
extra_payload["ttl_seconds_after_finished"] = ttl_seconds_after_finished
|
42
|
+
if active_deadline_seconds is not None:
|
43
|
+
extra_payload["active_deadline_seconds"] = active_deadline_seconds
|
41
44
|
|
42
45
|
payload = {
|
43
46
|
"resource_data": {
|
@@ -111,13 +114,17 @@ def get_job_list(job_list: list, job_pod_list: list):
|
|
111
114
|
|
112
115
|
for i, job_data in enumerate(job_list):
|
113
116
|
list_of_json_job_data[i]["name"] = job_data.get("name", "")
|
114
|
-
list_of_json_job_data[i]["
|
117
|
+
list_of_json_job_data[i]["ttl"] = job_data.get(
|
115
118
|
"ttl_seconds_after_finished", "N/A"
|
116
119
|
)
|
120
|
+
list_of_json_job_data[i]["ads"] = job_data.get("active_deadline_seconds", "N/A")
|
117
121
|
for job in list_of_json_job_data:
|
118
122
|
for job_pod in job_pod_list:
|
119
|
-
|
120
|
-
|
123
|
+
job_pod_labels: dict = job_pod.get("labels", {})
|
124
|
+
if job_pod_labels.get("app-name", "") == job.get("name"):
|
125
|
+
job["status"] = job_pod["status"]
|
126
|
+
job["gpu-count"] = job_pod_labels.get("gpu-count", 0)
|
127
|
+
job["gpu-label"] = job_pod_labels.get("gpu-label", "N/A")
|
121
128
|
# job["status_reason"] = [
|
122
129
|
# x.get("reason", "N/A") for x in job_pod.get("status_reasons", [])
|
123
130
|
# ]
|
@@ -159,12 +166,12 @@ def get_job_json_data(job_list: list):
|
|
159
166
|
|
160
167
|
job_data = {
|
161
168
|
"name": job.get("labels", {}).get("app-name"),
|
162
|
-
"status": job.get("status", {}).get(
|
169
|
+
"status": job.get("status", {}).get(
|
170
|
+
"phase", "Unknown"
|
171
|
+
), # only happen when Pod "disappeared" from the k8s - BUG
|
163
172
|
"volumes_mounted": volumes_mounted,
|
164
173
|
"cpu": cpu,
|
165
174
|
"ram": ram,
|
166
|
-
"gpu-count": job.get("labels", {}).get("gpu-count", 0),
|
167
|
-
"gpu-label": job.get("labels", {}).get("gpu-label", "N/A"),
|
168
175
|
}
|
169
176
|
# getting rid of unwanted and used values
|
170
177
|
if "pod-template-hash" in job["labels"].keys():
|
@@ -155,6 +155,13 @@ def job_list():
|
|
155
155
|
default=None,
|
156
156
|
help="Time to live in seconds after app is finished",
|
157
157
|
)
|
158
|
+
@click.option(
|
159
|
+
"--ads",
|
160
|
+
"active_deadline_seconds",
|
161
|
+
type=click.INT,
|
162
|
+
default=None,
|
163
|
+
help="Time to live in seconds after app is started",
|
164
|
+
)
|
158
165
|
def job_create(
|
159
166
|
gpu: int,
|
160
167
|
gpu_type: str,
|
@@ -170,6 +177,7 @@ def job_create(
|
|
170
177
|
startup_command: str,
|
171
178
|
repository_secret: str,
|
172
179
|
ttl_seconds_after_finished: int,
|
180
|
+
active_deadline_seconds: int,
|
173
181
|
):
|
174
182
|
"""
|
175
183
|
Create job in user namespace.
|
@@ -200,6 +208,8 @@ def job_create(
|
|
200
208
|
:type repository_secret: str
|
201
209
|
:param ttl_seconds_after_finished: time to live in seconds after app is finished
|
202
210
|
:type ttl_seconds_after_finished: int
|
211
|
+
:param active_deadline_seconds: time to live in seconds after app is started
|
212
|
+
:type active_deadline_seconds: int
|
203
213
|
"""
|
204
214
|
api_url, headers = get_api_url_and_prepare_headers()
|
205
215
|
url = f"{api_url}/v1/api/job/create"
|
@@ -226,6 +236,7 @@ def job_create(
|
|
226
236
|
startup_command=cleaned_data,
|
227
237
|
repository_secret=repository_secret,
|
228
238
|
ttl_seconds_after_finished=ttl_seconds_after_finished,
|
239
|
+
active_deadline_seconds=active_deadline_seconds,
|
229
240
|
)
|
230
241
|
__res = call_api(
|
231
242
|
request=EndpointTypes.post,
|
@@ -0,0 +1,31 @@
|
|
1
|
+
from cgc.commands.cgc_models import CGCEntityList
|
2
|
+
|
3
|
+
|
4
|
+
class SSHKeyTypes(CGCEntityList):
|
5
|
+
"""List of supported SSH key types
|
6
|
+
|
7
|
+
:param Enum: name of SSH key type
|
8
|
+
:type Enum: str
|
9
|
+
"""
|
10
|
+
|
11
|
+
RSA = "ssh-rsa"
|
12
|
+
DSS = "ssh-dss"
|
13
|
+
ECDSA_P256 = "ecdsa-sha2-nistp256"
|
14
|
+
ECDSA_P384 = "ecdsa-sha2-nistp384"
|
15
|
+
ECDSA_P521 = "ecdsa-sha2-nistp521"
|
16
|
+
ED25519 = "ssh-ed25519"
|
17
|
+
|
18
|
+
def load_data() -> list:
|
19
|
+
"""Return list of supported SSH key types
|
20
|
+
|
21
|
+
:return: list of supported SSH key types
|
22
|
+
:rtype: list
|
23
|
+
"""
|
24
|
+
return [
|
25
|
+
SSHKeyTypes.RSA,
|
26
|
+
SSHKeyTypes.DSS,
|
27
|
+
SSHKeyTypes.ECDSA_P256,
|
28
|
+
SSHKeyTypes.ECDSA_P384,
|
29
|
+
SSHKeyTypes.ECDSA_P521,
|
30
|
+
SSHKeyTypes.ED25519,
|
31
|
+
]
|
@@ -1,12 +1,11 @@
|
|
1
|
-
def volume_create_payload_validator(name,
|
1
|
+
def volume_create_payload_validator(name, size, storage_class):
|
2
2
|
"""
|
3
3
|
Create payload for volume creation.
|
4
4
|
"""
|
5
5
|
payload = {
|
6
6
|
"name": name,
|
7
|
-
"
|
7
|
+
"storage_class": storage_class,
|
8
8
|
"size": size,
|
9
|
-
"disks_type": disk_type,
|
10
9
|
"auto_mount": "false",
|
11
10
|
}
|
12
11
|
return payload
|