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.
Files changed (106) hide show
  1. {cgcsdk-1.0.15/cgcsdk.egg-info → cgcsdk-1.0.17}/PKG-INFO +7 -10
  2. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/.env +1 -1
  3. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/CHANGELOG.md +24 -0
  4. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_responses.py +10 -4
  5. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/cgc_cmd.py +3 -1
  6. cgcsdk-1.0.17/cgc/commands/cgc_cmd_responses.py +109 -0
  7. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/cgc_helpers.py +13 -3
  8. cgcsdk-1.0.17/cgc/commands/cgc_models.py +17 -0
  9. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/compute_cmd.py +40 -6
  10. cgcsdk-1.0.17/cgc/commands/compute/compute_models.py +35 -0
  11. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/compute_responses.py +6 -2
  12. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/db/db_cmd.py +9 -0
  13. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/db/db_models.py +12 -10
  14. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/job_utils.py +13 -6
  15. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/jobs_cmd.py +11 -0
  16. cgcsdk-1.0.17/cgc/commands/user/keys_models.py +31 -0
  17. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/data_model.py +2 -3
  18. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/volume_cmd.py +34 -19
  19. cgcsdk-1.0.17/cgc/commands/volume/volume_models.py +22 -0
  20. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/volume_responses.py +27 -1
  21. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/telemetry/basic.py +1 -1
  22. cgcsdk-1.0.17/cgc/utils/config_utils.py +218 -0
  23. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/consts/env_consts.py +0 -4
  24. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/consts/message_consts.py +1 -1
  25. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/version_control.py +23 -6
  26. {cgcsdk-1.0.15 → cgcsdk-1.0.17/cgcsdk.egg-info}/PKG-INFO +7 -10
  27. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/SOURCES.txt +1 -0
  28. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/setup.py +13 -9
  29. cgcsdk-1.0.15/cgc/commands/cgc_cmd_responses.py +0 -82
  30. cgcsdk-1.0.15/cgc/commands/cgc_models.py +0 -9
  31. cgcsdk-1.0.15/cgc/commands/compute/compute_models.py +0 -37
  32. cgcsdk-1.0.15/cgc/commands/user/keys_models.py +0 -16
  33. cgcsdk-1.0.15/cgc/utils/config_utils.py +0 -116
  34. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/LICENSE +0 -0
  35. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/MANIFEST.in +0 -0
  36. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/README.md +0 -0
  37. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/__init__.py +0 -0
  38. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/cgc.py +0 -0
  39. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/__init__.py +0 -0
  40. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/__init__.py +0 -0
  41. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_cmd.py +0 -0
  42. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_logic.py +0 -0
  43. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/auth/auth_utils.py +0 -0
  44. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/__init__.py +0 -0
  45. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/__init__.py +0 -0
  46. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/billing_cmd.py +0 -0
  47. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/billing_responses.py +0 -0
  48. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/billing/billing_utils.py +0 -0
  49. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/compute/compute_utils.py +0 -0
  50. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/db/__init__.py +0 -0
  51. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/debug/__init__.py +0 -0
  52. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/debug/debug_cmd.py +0 -0
  53. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/exceptions.py +0 -0
  54. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/__init__.py +0 -0
  55. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/jobs/jobs_responses.py +0 -0
  56. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/resource/__init__.py +0 -0
  57. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/resource/resource_cmd.py +0 -0
  58. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/resource/resource_responses.py +0 -0
  59. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/__init__.py +0 -0
  60. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/keys_cmd.py +0 -0
  61. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/keys_responses.py +0 -0
  62. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/keys_utils.py +0 -0
  63. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_cmd.py +0 -0
  64. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_models.py +0 -0
  65. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_responses.py +0 -0
  66. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/user/secret_utils.py +0 -0
  67. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/__init__.py +0 -0
  68. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/commands/volume/volume_utils.py +0 -0
  69. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/config.py +0 -0
  70. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/__init__.py +0 -0
  71. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/exceptions.py +0 -0
  72. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/job.py +0 -0
  73. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/postgresql.py +0 -0
  74. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/sdk/resource.py +0 -0
  75. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/server.crt +0 -0
  76. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/telemetry/__init__.py +0 -0
  77. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/__init__.py +0 -0
  78. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_invoice.txt +0 -0
  79. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_status.txt +0 -0
  80. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_stop_events_compute.txt +0 -0
  81. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_billing_stop_events_volume.txt +0 -0
  82. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_compute_list.txt +0 -0
  83. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_compute_list_no_labels.txt +0 -0
  84. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_tabulate_response.txt +0 -0
  85. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/desired_responses/test_volume_list.txt +0 -0
  86. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/tests/responses_tests.py +0 -0
  87. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/__init__.py +0 -0
  88. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/click_group.py +0 -0
  89. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/consts/__init__.py +0 -0
  90. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/__init__.py +0 -0
  91. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/aes_crypto.py +0 -0
  92. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/encryption_module.py +0 -0
  93. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/cryptography/rsa_crypto.py +0 -0
  94. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/custom_exceptions.py +0 -0
  95. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/get_headers_data.py +0 -0
  96. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/message_utils.py +0 -0
  97. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/prepare_headers.py +0 -0
  98. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/requests_helper.py +0 -0
  99. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/response_utils.py +0 -0
  100. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgc/utils/update.py +0 -0
  101. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/dependency_links.txt +0 -0
  102. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/entry_points.txt +0 -0
  103. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/requires.txt +0 -0
  104. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/cgcsdk.egg-info/top_level.txt +0 -0
  105. {cgcsdk-1.0.15 → cgcsdk-1.0.17}/pyproject.toml +0 -0
  106. {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.15
4
- Summary: Comtegra GPU Cloud REST API client
5
- Home-page: https://git.comtegra.pl/
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/foobar/foobar/blob/master/CHANGELOG.md
12
- Keywords: cloud,sdk,orchestrator,kubernetes,jupyter-notebook
13
- Classifier: Development Status :: 1 - Planning
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
@@ -6,4 +6,4 @@ CONFIG_FILE_NAME = cfg.json
6
6
  TMP_DIR = .tmp
7
7
  RELEASE = 1
8
8
  MAJOR_VERSION = 0
9
- MINOR_VERSION = 15
9
+ MINOR_VERSION = 17
@@ -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, get_config_file_name
7
- from cgc.utils.config_utils import get_config_path, save_to_config
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
- # config.json
31
- if config_filename == "config.json":
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
- def compute_port_add(app_name: str, port_name: str, port: int, ingress: bool):
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
- def compute_port_update(app_name: str, port_name: str, port: int, ingress: bool):
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
- def compute_port_delete(app_name: str, port_name: str):
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
- return data["details"]["ports"]["ports"]
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
- :param Enum: name of template
9
- :type Enum: str
10
- """
11
-
12
- POSTGRESQL = "postgresql"
13
- WEAVIATE = "weaviate"
14
- # MINIO = "minio"
15
- MONGODB = "mongodb"
16
- REDIS = "redis"
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]["ttl_seconds_after_finished"] = job_data.get(
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
- if job_pod.get("labels", {}).get("app-name") == job.get("name"):
120
- job["status"] = job_pod.get("status", "Pending")
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("phase", "Pending"),
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, access, size, disk_type):
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
- "access_type": access,
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