cgcsdk 0.8.5__py3-none-any.whl → 0.8.7__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.
- cgc/.env +1 -1
- cgc/CHANGELOG.md +20 -0
- cgc/cgc.py +2 -0
- cgc/commands/auth/__init__.py +5 -0
- cgc/commands/auth/auth_cmd.py +16 -4
- cgc/commands/auth/auth_responses.py +17 -9
- cgc/commands/auth/auth_utils.py +1 -2
- cgc/commands/cgc_cmd.py +54 -1
- cgc/commands/cgc_helpers.py +33 -0
- cgc/sdk/redis.py +57 -20
- cgc/utils/__init__.py +113 -0
- cgc/utils/config_utils.py +14 -13
- cgc/utils/consts/env_consts.py +4 -1
- cgc/utils/consts/message_consts.py +4 -1
- cgc/utils/message_utils.py +7 -1
- cgc/utils/prepare_headers.py +3 -0
- cgc/utils/requests_helper.py +1 -1
- cgc/utils/response_utils.py +5 -1
- {cgcsdk-0.8.5.dist-info → cgcsdk-0.8.7.dist-info}/METADATA +1 -1
- {cgcsdk-0.8.5.dist-info → cgcsdk-0.8.7.dist-info}/RECORD +24 -23
- {cgcsdk-0.8.5.dist-info → cgcsdk-0.8.7.dist-info}/LICENSE +0 -0
- {cgcsdk-0.8.5.dist-info → cgcsdk-0.8.7.dist-info}/WHEEL +0 -0
- {cgcsdk-0.8.5.dist-info → cgcsdk-0.8.7.dist-info}/entry_points.txt +0 -0
- {cgcsdk-0.8.5.dist-info → cgcsdk-0.8.7.dist-info}/top_level.txt +0 -0
cgc/.env
CHANGED
cgc/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## 0.8.7
|
4
|
+
|
5
|
+
Release on May 23, 2023.
|
6
|
+
|
7
|
+
* hotfix: development changed .env file making it broken for new users
|
8
|
+
|
9
|
+
## 0.8.6
|
10
|
+
|
11
|
+
Release on May 19, 2023.
|
12
|
+
|
13
|
+
* added get_redis_client_async() for RedisConnector
|
14
|
+
* get_redis_access() - async_client: bool, new parameter
|
15
|
+
* new command: cgc context switch [number]
|
16
|
+
* switch between user contexts
|
17
|
+
* new command: cgc context list
|
18
|
+
* list all configuration files
|
19
|
+
* updated command: cgc register
|
20
|
+
* allow to have multiple user contexts
|
21
|
+
* increased timeout for requests to 30 sec
|
22
|
+
|
3
23
|
## 0.8.5
|
4
24
|
|
5
25
|
Release on Apr 21, 2023.
|
cgc/cgc.py
CHANGED
@@ -15,6 +15,7 @@ from cgc.commands.cgc_cmd import (
|
|
15
15
|
cgc_status,
|
16
16
|
sending_telemetry_permission,
|
17
17
|
resource_events,
|
18
|
+
context_group,
|
18
19
|
)
|
19
20
|
from cgc.utils.version_control import check_version, _get_version
|
20
21
|
from cgc.utils.click_group import CustomGroup
|
@@ -28,6 +29,7 @@ def cli():
|
|
28
29
|
|
29
30
|
|
30
31
|
cli.add_command(debug_group)
|
32
|
+
cli.add_command(context_group)
|
31
33
|
cli.add_command(auth_register)
|
32
34
|
cli.add_command(api_keys_group)
|
33
35
|
cli.add_command(volume_group)
|
cgc/commands/auth/__init__.py
CHANGED
@@ -8,3 +8,8 @@ class AuthCommandException(ResponseException):
|
|
8
8
|
class NoNamespaceInConfig(AuthCommandException):
|
9
9
|
def __init__(self) -> None:
|
10
10
|
super().__init__(f"Namespace not readable from config file.")
|
11
|
+
|
12
|
+
|
13
|
+
class NoConfigFileFound(AuthCommandException):
|
14
|
+
def __init__(self) -> None:
|
15
|
+
super().__init__(f"Config does not exists.")
|
cgc/commands/auth/auth_cmd.py
CHANGED
@@ -7,12 +7,16 @@ from cgc.commands.auth.auth_responses import (
|
|
7
7
|
from cgc.commands.auth.auth_utils import (
|
8
8
|
auth_create_api_key_with_save,
|
9
9
|
)
|
10
|
-
|
11
10
|
from cgc.utils.prepare_headers import get_url_and_prepare_headers_register
|
12
11
|
from cgc.utils.cryptography import rsa_crypto
|
13
12
|
from cgc.utils.click_group import CustomCommand, CustomGroup
|
14
13
|
from cgc.utils.requests_helper import call_api, EndpointTypes
|
15
14
|
from cgc.utils.response_utils import retrieve_and_validate_response_send_metric
|
15
|
+
from cgc.utils import (
|
16
|
+
check_if_config_exist,
|
17
|
+
require_confirm_loop,
|
18
|
+
find_first_available_config_name,
|
19
|
+
)
|
16
20
|
|
17
21
|
|
18
22
|
@click.group("api-keys", cls=CustomGroup, hidden=True)
|
@@ -24,9 +28,9 @@ def api_keys_group():
|
|
24
28
|
|
25
29
|
|
26
30
|
@click.command("register", cls=CustomCommand)
|
27
|
-
@click.option("--user_id", "-u", "user_id", prompt=True)
|
28
|
-
@click.option("--access_key", "-k", "access_key", prompt=True)
|
29
|
-
def auth_register(
|
31
|
+
# @click.option("--user_id", "-u", "user_id", prompt=True)
|
32
|
+
# @click.option("--access_key", "-k", "access_key", prompt=True)
|
33
|
+
def auth_register(config_filename: str = "cfg.json"):
|
30
34
|
"""Register a user in system using user id and access key.\n
|
31
35
|
Enabling/Disabling Telemetry sending is available, if set to yes CGC will send
|
32
36
|
usage metrics for application improvements purposes.
|
@@ -40,6 +44,13 @@ def auth_register(user_id: str, access_key: str):
|
|
40
44
|
:type telemetry_sending: bool
|
41
45
|
"""
|
42
46
|
|
47
|
+
if check_if_config_exist(config_filename):
|
48
|
+
click.echo("Already registered.")
|
49
|
+
require_confirm_loop("Do you want to add new context?")
|
50
|
+
config_filename = find_first_available_config_name()
|
51
|
+
|
52
|
+
user_id = input("User ID: ")
|
53
|
+
access_key = input("Access key: ")
|
43
54
|
url, headers = get_url_and_prepare_headers_register(user_id, access_key)
|
44
55
|
metric = "auth.register"
|
45
56
|
pub_key_bytes, priv_key_bytes = rsa_crypto.key_generate_pair()
|
@@ -56,6 +67,7 @@ def auth_register(user_id: str, access_key: str):
|
|
56
67
|
retrieve_and_validate_response_send_metric(__res, metric, False),
|
57
68
|
user_id,
|
58
69
|
priv_key_bytes,
|
70
|
+
config_filename,
|
59
71
|
)
|
60
72
|
)
|
61
73
|
|
@@ -2,26 +2,34 @@ import shutil
|
|
2
2
|
import os
|
3
3
|
|
4
4
|
from cgc.commands.auth import auth_utils
|
5
|
-
from cgc.utils.consts.env_consts import TMP_DIR
|
6
|
-
from cgc.utils.config_utils import get_config_path, save_to_config
|
5
|
+
from cgc.utils.consts.env_consts import TMP_DIR, get_config_file_name
|
6
|
+
from cgc.utils.config_utils import get_config_path, save_to_config
|
7
7
|
from cgc.utils.message_utils import key_error_decorator_for_helpers
|
8
8
|
|
9
9
|
|
10
10
|
@key_error_decorator_for_helpers
|
11
|
-
def auth_register_response(response, user_id, priv_key_bytes) -> str:
|
11
|
+
def auth_register_response(response, user_id, priv_key_bytes, config_filename) -> str:
|
12
12
|
TMP_DIR_PATH = os.path.join(get_config_path(), TMP_DIR)
|
13
|
-
unzip_dir = auth_utils.save_and_unzip_file(response)
|
13
|
+
unzip_dir, namespace = auth_utils.save_and_unzip_file(response)
|
14
14
|
aes_key, password = auth_utils.get_aes_key_and_password(unzip_dir, priv_key_bytes)
|
15
15
|
|
16
|
-
|
16
|
+
os.environ["CONFIG_FILE_NAME"] = config_filename
|
17
|
+
save_to_config(
|
18
|
+
user_id=user_id, password=password, aes_key=aes_key, namespace=namespace
|
19
|
+
)
|
17
20
|
auth_utils.auth_create_api_key_with_save()
|
18
21
|
shutil.rmtree(TMP_DIR_PATH)
|
19
|
-
|
20
|
-
|
22
|
+
# config.json
|
23
|
+
if config_filename == "config.json":
|
24
|
+
return f"Register successful! You can now use the CLI. Saved data to:{os.path.join(get_config_path(),config_filename)}\n\
|
25
|
+
Consider backup this file. It stores data accessible only to you with which you can access CGC platform."
|
26
|
+
return f"New context created successfully! \nNew config file saved to: {os.path.join(get_config_path(),config_filename)}\n\
|
27
|
+
Consider backup this file. It stores data accessible only to you with which you can access CGC platform.\n \n\
|
28
|
+
To switch context use \ncgc context switch"
|
21
29
|
|
22
30
|
|
23
31
|
@key_error_decorator_for_helpers
|
24
32
|
def login_successful_response():
|
25
33
|
return f"Successfully logged in, created new API key pair.\n\
|
26
|
-
Saved data to: {
|
27
|
-
Consider backup this file. It stores data with which you can access CGC platform."
|
34
|
+
Saved data to: {os.path.join(get_config_path(), get_config_file_name())}.\n\
|
35
|
+
Consider backup this file. It stores data accessible only to you with which you can access CGC platform."
|
cgc/commands/auth/auth_utils.py
CHANGED
@@ -76,7 +76,6 @@ def save_and_unzip_file(res: requests.Response) -> str:
|
|
76
76
|
"""
|
77
77
|
zip_file = res.headers.get("content-disposition").split('"')[1]
|
78
78
|
namespace = zip_file.split("---")[-1].split(".")[0]
|
79
|
-
save_to_config(namespace=namespace)
|
80
79
|
|
81
80
|
if not os.path.isdir(TMP_DIR_PATH):
|
82
81
|
os.makedirs(TMP_DIR_PATH)
|
@@ -87,7 +86,7 @@ def save_and_unzip_file(res: requests.Response) -> str:
|
|
87
86
|
unzip_dir = zip_file_path[:-4]
|
88
87
|
shutil.unpack_archive(zip_file_path, unzip_dir)
|
89
88
|
|
90
|
-
return unzip_dir
|
89
|
+
return unzip_dir, namespace
|
91
90
|
|
92
91
|
|
93
92
|
def get_aes_key_and_password(unzip_dir: str, priv_key_bytes: bytes):
|
cgc/commands/cgc_cmd.py
CHANGED
@@ -4,11 +4,15 @@ import json
|
|
4
4
|
from cgc.commands.cgc_cmd_responses import cgc_status_response
|
5
5
|
from cgc.commands.resource.resource_cmd import resource_delete
|
6
6
|
from cgc.utils.requests_helper import call_api, EndpointTypes
|
7
|
-
from cgc.utils.click_group import CustomCommand
|
7
|
+
from cgc.utils.click_group import CustomCommand, CustomGroup
|
8
8
|
from cgc.utils.prepare_headers import get_api_url_and_prepare_headers
|
9
9
|
from cgc.utils.response_utils import retrieve_and_validate_response_send_metric
|
10
10
|
from cgc.telemetry.basic import telemetry_permission_set
|
11
11
|
from cgc.commands.compute.compute_responses import compute_logs_response
|
12
|
+
from cgc.commands.auth.auth_cmd import auth_register
|
13
|
+
from cgc.utils import set_environment_data, check_if_config_exist, list_all_config_files
|
14
|
+
from cgc.commands.cgc_helpers import table_of_user_context_files
|
15
|
+
from cgc.utils.config_utils import config_path
|
12
16
|
|
13
17
|
|
14
18
|
@click.command("rm", cls=CustomCommand)
|
@@ -62,3 +66,52 @@ def sending_telemetry_permission():
|
|
62
66
|
click.echo(
|
63
67
|
f"Sending telemetry is now {'enabled' if telemetry_permission_set() else 'disabled'}"
|
64
68
|
)
|
69
|
+
|
70
|
+
|
71
|
+
@click.group(name="context", cls=CustomGroup)
|
72
|
+
def context_group():
|
73
|
+
"""
|
74
|
+
Switch between namespaces (contexts) that are at your disposal.
|
75
|
+
"""
|
76
|
+
|
77
|
+
|
78
|
+
@context_group.command("switch", cls=CustomCommand)
|
79
|
+
@click.argument("number", type=click.INT)
|
80
|
+
# @click.pass_context
|
81
|
+
def switch_context(number: int):
|
82
|
+
"""Set which namespace config should be used. After switching context your next command will be run in given namespace that corresponds to user namespace"""
|
83
|
+
file_name = f"{number}.json" if number > 1 else "cfg.json"
|
84
|
+
|
85
|
+
if not check_if_config_exist(file_name):
|
86
|
+
click.echo("Selected context does not exist.")
|
87
|
+
click.echo("To get all available contexts use:")
|
88
|
+
click.echo("cgc context list")
|
89
|
+
exit(0)
|
90
|
+
# user_id = input("User ID: ")
|
91
|
+
# access_key = input("Access key: ")
|
92
|
+
# ctx.invoke(
|
93
|
+
# auth_register,
|
94
|
+
# user_id=user_id,
|
95
|
+
# access_key=access_key,
|
96
|
+
# config_filename=file_name,
|
97
|
+
# )
|
98
|
+
set_environment_data("CONFIG_FILE_NAME", file_name)
|
99
|
+
click.echo(f"Context file changed to: {file_name}")
|
100
|
+
|
101
|
+
|
102
|
+
@context_group.command("list", cls=CustomCommand)
|
103
|
+
def list_context():
|
104
|
+
"""List all namespaces available to you"""
|
105
|
+
click.echo(table_of_user_context_files(list_all_config_files()))
|
106
|
+
|
107
|
+
|
108
|
+
@context_group.command("folder", cls=CustomCommand)
|
109
|
+
def folder_of_contexts():
|
110
|
+
"""Check location of config files in case that you need to export them."""
|
111
|
+
click.echo(f"All config files are located: {config_path}")
|
112
|
+
click.echo(
|
113
|
+
"If you'd like to use them on a different machine just copy all the files to corresponding folder."
|
114
|
+
)
|
115
|
+
click.echo(
|
116
|
+
"You can check location of that folder on different machine with the same command."
|
117
|
+
)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from typing import List
|
2
|
+
from cgc.utils import quick_sort
|
3
|
+
from cgc.utils.config_utils import read_from_cfg
|
4
|
+
from tabulate import tabulate
|
5
|
+
|
6
|
+
|
7
|
+
def table_of_user_context_files(config_files: List[str]):
|
8
|
+
# print tabulate of: [context NR | namespace | user_id]
|
9
|
+
headers = ["Context No.", "Namespace", "User ID"]
|
10
|
+
contexts = []
|
11
|
+
contexts_nrs = []
|
12
|
+
for file in config_files:
|
13
|
+
file_context = []
|
14
|
+
file_context.append(
|
15
|
+
int(file.split(".")[0]) if file != "cfg.json" else 1
|
16
|
+
) # should never throw exception with good config_file list
|
17
|
+
contexts_nrs.append(file_context[0])
|
18
|
+
file_data = read_from_cfg(None, file)
|
19
|
+
values_to_read = ["namespace", "user_id"]
|
20
|
+
for k in values_to_read:
|
21
|
+
try:
|
22
|
+
value = file_data[k]
|
23
|
+
except KeyError:
|
24
|
+
value = None
|
25
|
+
file_context.append(value)
|
26
|
+
contexts.append(file_context)
|
27
|
+
|
28
|
+
contexts_nrs_sorted = quick_sort(contexts_nrs)
|
29
|
+
contexts_sorted = []
|
30
|
+
for context in contexts_nrs_sorted:
|
31
|
+
contexts_sorted.append(contexts[contexts_nrs.index(context)])
|
32
|
+
|
33
|
+
return tabulate(contexts_sorted, headers=headers)
|
cgc/sdk/redis.py
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
from redis import
|
1
|
+
from redis.asyncio import redis as redis_async
|
2
|
+
import redis
|
2
3
|
|
3
4
|
|
4
5
|
class RedisConnector:
|
6
|
+
redis_client_async = None
|
7
|
+
redis_client = None
|
8
|
+
|
5
9
|
def __init__(
|
6
10
|
self, host: str, password: str = None, decode_responses: bool = False
|
7
11
|
) -> None:
|
@@ -10,42 +14,75 @@ class RedisConnector:
|
|
10
14
|
"host must be a str containing redis app name"
|
11
15
|
self._password = password
|
12
16
|
self._decode_responses = decode_responses
|
13
|
-
self.connect()
|
14
17
|
|
15
|
-
def connect(self):
|
18
|
+
def connect(self, async_client: bool = False):
|
16
19
|
while True:
|
17
20
|
try:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
if not async_client:
|
22
|
+
self.redis_client = redis.Redis(
|
23
|
+
host=self._host,
|
24
|
+
port=6379,
|
25
|
+
password=self._password,
|
26
|
+
decode_responses=self._decode_responses,
|
27
|
+
)
|
28
|
+
else:
|
29
|
+
self.redis_client_async = redis_async.Redis(
|
30
|
+
host=self._host,
|
31
|
+
port=6379,
|
32
|
+
password=self._password,
|
33
|
+
decode_responses=self._decode_responses,
|
34
|
+
)
|
24
35
|
print(f"Connected to Redis: {self._host}")
|
25
36
|
break
|
26
|
-
except (ConnectionError,) as e:
|
37
|
+
except (redis.ConnectionError,) as e:
|
27
38
|
print(f"Redis connection error: {e}")
|
28
39
|
print(f"retrying to connect...")
|
29
40
|
|
30
41
|
def get_redis_client(self):
|
31
|
-
|
42
|
+
if self.redis_client is None:
|
43
|
+
self.connect()
|
44
|
+
return self.redis_client
|
45
|
+
|
46
|
+
def get_redis_client_async(self):
|
47
|
+
if self.redis_client_async is None:
|
48
|
+
self.connect(async_client=True)
|
49
|
+
return self.redis_client_async
|
32
50
|
|
33
51
|
|
34
52
|
def get_redis_access(
|
35
|
-
app_name: str,
|
53
|
+
app_name: str,
|
54
|
+
password: str,
|
55
|
+
decode_responses: bool = False,
|
56
|
+
restart: bool = False,
|
57
|
+
async_client=False,
|
36
58
|
):
|
37
59
|
global _redis_access
|
60
|
+
global _redis_access_async
|
38
61
|
|
39
|
-
def init_access():
|
62
|
+
def init_access(async_client=False):
|
40
63
|
global _redis_access
|
41
|
-
|
42
|
-
|
43
|
-
|
64
|
+
global _redis_access_async
|
65
|
+
|
66
|
+
if not async_client:
|
67
|
+
_redis_access = RedisConnector(
|
68
|
+
host=app_name, password=password, decode_responses=decode_responses
|
69
|
+
)
|
70
|
+
else:
|
71
|
+
_redis_access_async = RedisConnector(
|
72
|
+
host=app_name, password=password, decode_responses=decode_responses
|
73
|
+
)
|
44
74
|
|
45
75
|
try:
|
46
|
-
if not
|
47
|
-
|
76
|
+
if not async_client:
|
77
|
+
if not isinstance(_redis_access, RedisConnector) or restart:
|
78
|
+
init_access()
|
79
|
+
else:
|
80
|
+
if not isinstance(_redis_access_async, RedisConnector) or restart:
|
81
|
+
init_access(True)
|
48
82
|
except NameError:
|
49
|
-
|
83
|
+
if not async_client:
|
84
|
+
init_access()
|
85
|
+
else:
|
86
|
+
init_access(True)
|
50
87
|
pass
|
51
|
-
return _redis_access
|
88
|
+
return _redis_access if async_client else _redis_access_async
|
cgc/utils/__init__.py
CHANGED
@@ -0,0 +1,113 @@
|
|
1
|
+
from typing import List
|
2
|
+
from os import listdir
|
3
|
+
from os.path import isfile, join
|
4
|
+
from cgc.utils.config_utils import config_path
|
5
|
+
from operator import is_not
|
6
|
+
from functools import partial
|
7
|
+
from random import randrange
|
8
|
+
|
9
|
+
from cgc.utils.consts.env_consts import ENV_FILE_PATH
|
10
|
+
from cgc.utils.config_utils import read_from_cfg
|
11
|
+
from cgc.commands.auth import NoConfigFileFound
|
12
|
+
|
13
|
+
|
14
|
+
def require_confirm_loop(message: str):
|
15
|
+
while True:
|
16
|
+
answer = input(f"{message} (Y/N): ").lower()
|
17
|
+
if answer in ("y", "yes"):
|
18
|
+
break
|
19
|
+
if answer in ("n", "no"):
|
20
|
+
exit(0)
|
21
|
+
|
22
|
+
|
23
|
+
def quick_sort(collection: list) -> list:
|
24
|
+
"""A pure Python implementation of quick sort algorithm
|
25
|
+
|
26
|
+
:param collection: a mutable collection of comparable items
|
27
|
+
:return: the same collection ordered by ascending
|
28
|
+
|
29
|
+
Examples:
|
30
|
+
>>> quick_sort([0, 5, 3, 2, 2])
|
31
|
+
[0, 2, 2, 3, 5]
|
32
|
+
>>> quick_sort([])
|
33
|
+
[]
|
34
|
+
>>> quick_sort([-2, 5, 0, -45])
|
35
|
+
[-45, -2, 0, 5]
|
36
|
+
"""
|
37
|
+
if len(collection) < 2:
|
38
|
+
return collection
|
39
|
+
pivot_index = randrange(len(collection)) # Use random element as pivot
|
40
|
+
pivot = collection[pivot_index]
|
41
|
+
greater: list[int] = [] # All elements greater than pivot
|
42
|
+
lesser: list[int] = [] # All elements less than or equal to pivot
|
43
|
+
|
44
|
+
for element in collection[:pivot_index]:
|
45
|
+
(greater if element > pivot else lesser).append(element)
|
46
|
+
|
47
|
+
for element in collection[pivot_index + 1 :]:
|
48
|
+
(greater if element > pivot else lesser).append(element)
|
49
|
+
|
50
|
+
return [*quick_sort(lesser), pivot, *quick_sort(greater)]
|
51
|
+
|
52
|
+
|
53
|
+
def set_environment_data(variable: str, value: str):
|
54
|
+
"""Set variable to .env file
|
55
|
+
|
56
|
+
:return: new value
|
57
|
+
:rtype: str
|
58
|
+
"""
|
59
|
+
f = open(file=ENV_FILE_PATH, mode="r")
|
60
|
+
replaced_content = f.read()
|
61
|
+
replaced_content = replaced_content.splitlines()
|
62
|
+
f.close()
|
63
|
+
for i, line in enumerate(replaced_content):
|
64
|
+
splitted = line.split(" ")
|
65
|
+
if splitted[0] == variable.upper():
|
66
|
+
replaced_content[i] = line.replace(splitted[2], value)
|
67
|
+
with open(file=ENV_FILE_PATH, mode="w") as f:
|
68
|
+
f.write("\n".join(replaced_content))
|
69
|
+
break
|
70
|
+
else:
|
71
|
+
with open(file=ENV_FILE_PATH, mode="a") as f:
|
72
|
+
f.write(f"\n{variable.upper()} = {value}")
|
73
|
+
|
74
|
+
return value
|
75
|
+
|
76
|
+
|
77
|
+
def find_first_available_config_name() -> str:
|
78
|
+
increment = 2
|
79
|
+
while True:
|
80
|
+
filename = f"{increment}.json"
|
81
|
+
try:
|
82
|
+
read_from_cfg(None, filename)
|
83
|
+
increment += 1
|
84
|
+
except NoConfigFileFound:
|
85
|
+
break
|
86
|
+
return filename
|
87
|
+
|
88
|
+
|
89
|
+
def check_if_config_exist(filename: str) -> bool:
|
90
|
+
try:
|
91
|
+
read_from_cfg(None, filename)
|
92
|
+
except NoConfigFileFound:
|
93
|
+
return False
|
94
|
+
return True
|
95
|
+
|
96
|
+
|
97
|
+
def list_all_config_files() -> List[str]:
|
98
|
+
only_files = [f for f in listdir(config_path) if isfile(join(config_path, f))]
|
99
|
+
|
100
|
+
def only_json_file(filename: str):
|
101
|
+
return filename if filename.endswith(".json") else None
|
102
|
+
|
103
|
+
def cgc_config_file(filename: str):
|
104
|
+
filename_prefix = filename.split(".")[0]
|
105
|
+
try:
|
106
|
+
int(filename_prefix)
|
107
|
+
return filename
|
108
|
+
except ValueError:
|
109
|
+
if filename_prefix == "cfg":
|
110
|
+
return filename
|
111
|
+
|
112
|
+
json_files = list(filter(partial(is_not, None), map(only_json_file, only_files)))
|
113
|
+
return list(filter(partial(is_not, None), map(cgc_config_file, json_files)))
|
cgc/utils/config_utils.py
CHANGED
@@ -3,11 +3,9 @@ import os
|
|
3
3
|
import sys
|
4
4
|
import click
|
5
5
|
|
6
|
-
from cgc.commands.auth import NoNamespaceInConfig
|
6
|
+
from cgc.commands.auth import NoNamespaceInConfig, NoConfigFileFound
|
7
7
|
from cgc.utils.message_utils import prepare_error_message
|
8
|
-
from cgc.utils.consts.env_consts import
|
9
|
-
CONFIG_FILE_NAME,
|
10
|
-
)
|
8
|
+
from cgc.utils.consts.env_consts import get_config_file_name
|
11
9
|
|
12
10
|
|
13
11
|
def get_config_path():
|
@@ -32,7 +30,6 @@ def get_config_path():
|
|
32
30
|
|
33
31
|
|
34
32
|
config_path = get_config_path()
|
35
|
-
user_config_file = os.path.join(config_path, CONFIG_FILE_NAME)
|
36
33
|
|
37
34
|
|
38
35
|
def save_to_config(**kwargs):
|
@@ -44,6 +41,7 @@ def save_to_config(**kwargs):
|
|
44
41
|
:type kwargs: dict
|
45
42
|
"""
|
46
43
|
read_cfg = {}
|
44
|
+
user_config_file = os.path.join(config_path, get_config_file_name())
|
47
45
|
if not os.path.isdir(config_path):
|
48
46
|
os.makedirs(config_path)
|
49
47
|
try:
|
@@ -57,7 +55,7 @@ def save_to_config(**kwargs):
|
|
57
55
|
json.dump(final_cfg, f)
|
58
56
|
|
59
57
|
|
60
|
-
def read_from_cfg(key: str):
|
58
|
+
def read_from_cfg(key: str, filename=None):
|
61
59
|
"""Function to read a single value from config
|
62
60
|
|
63
61
|
:param key: key name to read the value from config
|
@@ -65,15 +63,18 @@ def read_from_cfg(key: str):
|
|
65
63
|
:return: value for the provided key
|
66
64
|
:rtype: _type_
|
67
65
|
"""
|
66
|
+
if filename is None:
|
67
|
+
filename_with_path = os.path.join(config_path, get_config_file_name())
|
68
|
+
else:
|
69
|
+
filename_with_path = os.path.join(config_path, filename)
|
68
70
|
try:
|
69
|
-
|
70
|
-
|
71
|
-
|
71
|
+
with open(filename_with_path, "r+", encoding="UTF-8") as f:
|
72
|
+
read_cfg = json.load(f)
|
73
|
+
if key is None:
|
74
|
+
return read_cfg
|
75
|
+
return read_cfg[key]
|
72
76
|
except FileNotFoundError:
|
73
|
-
|
74
|
-
raise NoNamespaceInConfig()
|
75
|
-
print("No config file found. Please use cgc register first.")
|
76
|
-
sys.exit()
|
77
|
+
raise NoConfigFileFound()
|
77
78
|
except KeyError:
|
78
79
|
if key == "namespace":
|
79
80
|
raise NoNamespaceInConfig()
|
cgc/utils/consts/env_consts.py
CHANGED
@@ -36,8 +36,11 @@ else:
|
|
36
36
|
|
37
37
|
API_PORT = os.getenv("API_PORT")
|
38
38
|
API_URL = f"{__prefix}://{API_HOST}:{API_PORT}"
|
39
|
-
CONFIG_FILE_NAME = os.getenv("CONFIG_FILE_NAME")
|
40
39
|
TMP_DIR = os.getenv("TMP_DIR")
|
41
40
|
RELEASE = int(os.getenv("RELEASE"))
|
42
41
|
MAJOR_VERSION = int(os.getenv("MAJOR_VERSION"))
|
43
42
|
MINOR_VERSION = int(os.getenv("MINOR_VERSION"))
|
43
|
+
|
44
|
+
|
45
|
+
def get_config_file_name():
|
46
|
+
return os.getenv("CONFIG_FILE_NAME")
|
@@ -1,3 +1,6 @@
|
|
1
|
+
CONFIG_FILE_NOT_FOUND = (
|
2
|
+
"Config file not found. Please register with CGC or verify user context."
|
3
|
+
)
|
1
4
|
UNKNOWN_ERROR = "An unknown error occurred. Please try again or contact support at support@comtegra.pl."
|
2
5
|
TIMEOUT_ERROR = (
|
3
6
|
"Connection timed out. Try again or contact support at support@comtegra.pl"
|
@@ -12,6 +15,6 @@ OUTDATED_MINOR = "There is a new release available, consider updating the applic
|
|
12
15
|
OUTDATED_MAJOR = (
|
13
16
|
"You are using outdated version of cgcsdk, please update to the latest version."
|
14
17
|
)
|
15
|
-
UNAUTHORIZED_ERROR = "Unauthorized.
|
18
|
+
UNAUTHORIZED_ERROR = "Unauthorized. Credentials provided are invalid. Contact support at support@comtegra.pl"
|
16
19
|
DISABLED_ERROR = "Account has been disabled. If you require assistance, please contact support at support@comtegra.pl"
|
17
20
|
ENDPOINT_DISABLED = "Endpoint is currently disabled, please try again later or contact support for additional information at support@comtegra.pl"
|
cgc/utils/message_utils.py
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
import click
|
2
|
+
|
1
3
|
from colorama import Fore, Style
|
2
4
|
from functools import wraps
|
3
5
|
|
4
6
|
from cgc.commands.exceptions import ResponseException
|
5
7
|
from cgc.telemetry.basic import increment_metric
|
6
|
-
from cgc.utils.consts.message_consts import UNKNOWN_ERROR
|
8
|
+
from cgc.utils.consts.message_consts import UNKNOWN_ERROR, CONFIG_FILE_NOT_FOUND
|
9
|
+
from cgc.commands.auth import NoConfigFileFound
|
7
10
|
|
8
11
|
|
9
12
|
def prepare_error_message(message: str) -> str:
|
@@ -46,6 +49,9 @@ def key_error_decorator_for_helpers(func):
|
|
46
49
|
def wrapper(*args, **kwargs):
|
47
50
|
try:
|
48
51
|
return func(*args, **kwargs)
|
52
|
+
except NoConfigFileFound as err:
|
53
|
+
click.echo(prepare_warning_message(CONFIG_FILE_NOT_FOUND))
|
54
|
+
exit(1)
|
49
55
|
except (TypeError, KeyError, IndexError) as err:
|
50
56
|
print(args, "\n", kwargs)
|
51
57
|
increment_metric("client.parser", True)
|
cgc/utils/prepare_headers.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from cgc.utils.config_utils import read_from_cfg
|
2
2
|
from cgc.utils.consts.env_consts import API_URL, CGC_SECRET
|
3
3
|
from cgc.commands.auth import auth_utils
|
4
|
+
from cgc.utils.message_utils import key_error_decorator_for_helpers
|
4
5
|
|
5
6
|
|
6
7
|
def load_user_api_keys():
|
@@ -12,6 +13,7 @@ def load_user_api_keys():
|
|
12
13
|
return read_from_cfg("api_key"), read_from_cfg("api_secret")
|
13
14
|
|
14
15
|
|
16
|
+
@key_error_decorator_for_helpers
|
15
17
|
def get_api_url_and_prepare_headers():
|
16
18
|
"""Loads API_URL and user api keys into single function. Ment to be used as single point of truth for all andpoints except register - due to different Content-Type header
|
17
19
|
|
@@ -53,6 +55,7 @@ def get_url_and_headers_jwt_token():
|
|
53
55
|
return url, headers
|
54
56
|
|
55
57
|
|
58
|
+
@key_error_decorator_for_helpers
|
56
59
|
def prepare_headers_api_key():
|
57
60
|
"""Prepares headers for create API key request.
|
58
61
|
|
cgc/utils/requests_helper.py
CHANGED
cgc/utils/response_utils.py
CHANGED
@@ -4,7 +4,7 @@ import pprint
|
|
4
4
|
import requests
|
5
5
|
import json
|
6
6
|
from tabulate import tabulate
|
7
|
-
from cgc.commands.auth import NoNamespaceInConfig
|
7
|
+
from cgc.commands.auth import NoNamespaceInConfig, NoConfigFileFound
|
8
8
|
from cgc.utils.message_utils import prepare_error_message
|
9
9
|
from cgc.utils.consts.message_consts import (
|
10
10
|
UNKNOWN_ERROR,
|
@@ -38,6 +38,10 @@ def retrieve_and_validate_response_send_metric(
|
|
38
38
|
metric = f"{get_namespace()}.{metric}"
|
39
39
|
except NoNamespaceInConfig:
|
40
40
|
metric = f"unknown-namespace.{metric}"
|
41
|
+
except NoConfigFileFound:
|
42
|
+
print("No config file found. Please use:")
|
43
|
+
print("cgc register")
|
44
|
+
metric = f"bad-client.{metric}"
|
41
45
|
|
42
46
|
if response.status_code == 200:
|
43
47
|
increment_metric(
|
@@ -1,17 +1,18 @@
|
|
1
|
-
cgc/.env,sha256=
|
2
|
-
cgc/CHANGELOG.md,sha256=
|
1
|
+
cgc/.env,sha256=s-vHJroAqqbjxntSwKabvrteilxs6Jb3ezMPRoIi-z8,234
|
2
|
+
cgc/CHANGELOG.md,sha256=SjMZBYWSaCASprwbfZtlNnXnSy14NbK79nRdyzNDP1s,4029
|
3
3
|
cgc/__init__.py,sha256=d03Xv8Pw4ktNyUHfmicP6XfxYPXnVYLaCZPyUlg_RNQ,326
|
4
|
-
cgc/cgc.py,sha256=
|
4
|
+
cgc/cgc.py,sha256=kPLg3h-3kjlMBiwZGOM7yvXJ7pzkVglAbWWQ7KX8jeY,1377
|
5
5
|
cgc/config.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
cgc/server.crt,sha256=OEvi0e8A3Dl5NnVqxFSu1D2JhLfH79lrW_lIyNW-BVM,1452
|
7
7
|
cgc/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
cgc/commands/cgc_cmd.py,sha256=
|
8
|
+
cgc/commands/cgc_cmd.py,sha256=Tvjr_dtRur_5G-rhLFgvNNS-T19bI3bRHQ0mDbjmwLw,4061
|
9
9
|
cgc/commands/cgc_cmd_responses.py,sha256=ToPjvGf3zUbFLhLwv-BV8ZAvAHg1xS99iprM928MnOY,2026
|
10
|
+
cgc/commands/cgc_helpers.py,sha256=i5M0xYwEAYFKeA9Rvp5x3xYBGrxtUPU8y8uegt6VkhY,1207
|
10
11
|
cgc/commands/exceptions.py,sha256=l3Sms3D2fxSpLQQQEYeLWxO3to82myTQ0VFgFYdQdLU,45
|
11
|
-
cgc/commands/auth/__init__.py,sha256=
|
12
|
-
cgc/commands/auth/auth_cmd.py,sha256=
|
13
|
-
cgc/commands/auth/auth_responses.py,sha256=
|
14
|
-
cgc/commands/auth/auth_utils.py,sha256=
|
12
|
+
cgc/commands/auth/__init__.py,sha256=K8HkHHotMnK7SQRAst5rx_wprHEphPo_w2KToEymjAY,399
|
13
|
+
cgc/commands/auth/auth_cmd.py,sha256=IymOWji_m_3ieuLdzaIy7EroXhmTjtVJvHN0ALivvCY,2824
|
14
|
+
cgc/commands/auth/auth_responses.py,sha256=Z1eMM_BxHZb_3fdkQobMOlOHtEG9pxfLm8D-WKbevto,1783
|
15
|
+
cgc/commands/auth/auth_utils.py,sha256=vYVoz6VOGDCkEz2CLg8Cz6voTPE9G6lEbD7RIwlaVwg,3893
|
15
16
|
cgc/commands/billing/__init__.py,sha256=0arQm0R3Ouw7tXPooJsvWd_pGeHhzaVwQCbWMKQPT9A,753
|
16
17
|
cgc/commands/billing/billing_cmd.py,sha256=I4OWos6DWM8zM28nJzaM8-KJhkQTPhI7oWBivIaPmKY,3450
|
17
18
|
cgc/commands/billing/billing_responses.py,sha256=HAD5N-Odx3Jz1OmhO4v66rHoXpTYIOGlXDsrs0da9dk,1949
|
@@ -36,7 +37,7 @@ cgc/sdk/__init__.py,sha256=XhdIQ-K0mFVl3m4UPftBc7ZYDSsrPpLi2g2Scbk9XI0,194
|
|
36
37
|
cgc/sdk/handlers.py,sha256=ECCHNe1pErsXFlmwHewsWRvYqzAZ5j5TrSqwernpLJk,868
|
37
38
|
cgc/sdk/mongodb.py,sha256=TJ2XU7nilNRXLOIpQQPrRiVxHN2TaVM5QOSuMRtNDVs,7221
|
38
39
|
cgc/sdk/postgresql.py,sha256=ziXaMMwjSF3k1OAID3F9npqWVxreQaoZ8wn7X8x1FZw,1637
|
39
|
-
cgc/sdk/redis.py,sha256=
|
40
|
+
cgc/sdk/redis.py,sha256=EkVQnmxpkkofL7TsU_hqttA14PtkE4bgNPEf_cV61F0,2786
|
40
41
|
cgc/telemetry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
42
|
cgc/telemetry/basic.py,sha256=XagCcyH4QSEPmfiQ1WCjqXslnJO6IaJCY0AMPySd5rc,3175
|
42
43
|
cgc/tests/__init__.py,sha256=NTtosBQi5W7yDpElH1B8Nim9WpkNkcqikVQXP6yWiQw,102744
|
@@ -49,26 +50,26 @@ cgc/tests/desired_responses/test_compute_list.txt,sha256=3CDAuILJdwBmX6-GLj3zDbn
|
|
49
50
|
cgc/tests/desired_responses/test_compute_list_no_labels.txt,sha256=-OeQIaEHHsHZ81tCOI5j6VQYUMlj8VYcyyOU_DhPOpU,155
|
50
51
|
cgc/tests/desired_responses/test_tabulate_response.txt,sha256=beNyCTS9fwrHn4ueEOVk2BpOeSYZWumIa3H5EUGnW1I,789
|
51
52
|
cgc/tests/desired_responses/test_volume_list.txt,sha256=vYB1p50BBHD801q7LUdDc_aca4ezQ8CFLWw7I-b4Uao,309
|
52
|
-
cgc/utils/__init__.py,sha256=
|
53
|
+
cgc/utils/__init__.py,sha256=h6AyoMfMxgDhvzUJ94bs3NCYzAKR2tBPG7V7u3Hl5zE,3405
|
53
54
|
cgc/utils/click_group.py,sha256=Scfw8eMIyt2dE1ezUq2JuiI-E_LklqXQXJEr7L-EG6A,633
|
54
|
-
cgc/utils/config_utils.py,sha256=
|
55
|
+
cgc/utils/config_utils.py,sha256=VFTrcN9QeOByIobhh48TfAm-BWON4PN8zX0H8PdUNTU,2729
|
55
56
|
cgc/utils/custom_exceptions.py,sha256=DXhEjei0dW-dHOSCZitiuzBQEhDSBheGBHi6gZ-jO3Q,2067
|
56
|
-
cgc/utils/message_utils.py,sha256=
|
57
|
-
cgc/utils/prepare_headers.py,sha256=
|
58
|
-
cgc/utils/requests_helper.py,sha256=
|
59
|
-
cgc/utils/response_utils.py,sha256=
|
57
|
+
cgc/utils/message_utils.py,sha256=_cTvf--X7_S740wYX91kiS1O2MO6hExJHGI1BdzGlWA,1773
|
58
|
+
cgc/utils/prepare_headers.py,sha256=gEN2UHCzEZc7T8rihOAvxdRYOyEN2BT0bRHR5CcY584,2488
|
59
|
+
cgc/utils/requests_helper.py,sha256=stXD1rRDN8-OM8Hsp516or4p-E7Gc0h4RJmvOmklSHU,1973
|
60
|
+
cgc/utils/response_utils.py,sha256=mH7Scc8aqticD17j_Sxx0WL-8PFqUhFH8Aoq-b6EGno,4913
|
60
61
|
cgc/utils/update.py,sha256=AsQwhcBqsjgNPKn6AN6ojt0Ew5otvJXyshys6bjr7DQ,413
|
61
62
|
cgc/utils/version_control.py,sha256=hTHb06QfzBQNmiiSBn3TUdp6JMg6d8l1Qd3y78RuSfw,2959
|
62
63
|
cgc/utils/consts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
63
|
-
cgc/utils/consts/env_consts.py,sha256=
|
64
|
-
cgc/utils/consts/message_consts.py,sha256=
|
64
|
+
cgc/utils/consts/env_consts.py,sha256=RawfOqxqSxWTU50Y2Y34CN0YDBtPMYDI_ZIKlNuPkv4,1340
|
65
|
+
cgc/utils/consts/message_consts.py,sha256=8CIe3N_HL6Pj-gSArkPkpegsvm-QMWxqqnSgtzG08Qw,1218
|
65
66
|
cgc/utils/cryptography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
66
67
|
cgc/utils/cryptography/aes_crypto.py,sha256=S0rKg38oy7rM5lTrP6DDpjLA-XRxuZggAXyxMFHtyzY,3333
|
67
68
|
cgc/utils/cryptography/encryption_module.py,sha256=rbblBBorHYPGl-iKblyZX3_NuPEvUTpnH1l_RgNGCbA,1958
|
68
69
|
cgc/utils/cryptography/rsa_crypto.py,sha256=h3jU5qPpj9uVjP1rTqZJTdYB5yjhD9HZpr_nD439h9Q,4180
|
69
|
-
cgcsdk-0.8.
|
70
|
-
cgcsdk-0.8.
|
71
|
-
cgcsdk-0.8.
|
72
|
-
cgcsdk-0.8.
|
73
|
-
cgcsdk-0.8.
|
74
|
-
cgcsdk-0.8.
|
70
|
+
cgcsdk-0.8.7.dist-info/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
71
|
+
cgcsdk-0.8.7.dist-info/METADATA,sha256=OHf5kc8nmVI4svt4s2m55o479xidCHa-KU7QRudMZIA,1420
|
72
|
+
cgcsdk-0.8.7.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
73
|
+
cgcsdk-0.8.7.dist-info/entry_points.txt,sha256=bdfIHeJ6Y-BBr5yupCVoK7SUrJj1yNdew8OtIOg_3No,36
|
74
|
+
cgcsdk-0.8.7.dist-info/top_level.txt,sha256=nqW9tqcIcCXFigQT69AuOk7XHKc4pCuv4HGJQGXb6iA,12
|
75
|
+
cgcsdk-0.8.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|