berryworld 1.0.0.196751__py3-none-any.whl → 1.0.0.197185__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.
- berryworld/__init__.py +2 -3
- berryworld/credentials.py +0 -26
- berryworld/generate_env.py +115 -23
- berryworld/sql_connenction.py +1195 -37
- {berryworld-1.0.0.196751.dist-info → berryworld-1.0.0.197185.dist-info}/METADATA +1 -1
- {berryworld-1.0.0.196751.dist-info → berryworld-1.0.0.197185.dist-info}/RECORD +9 -9
- {berryworld-1.0.0.196751.dist-info → berryworld-1.0.0.197185.dist-info}/WHEEL +0 -0
- {berryworld-1.0.0.196751.dist-info → berryworld-1.0.0.197185.dist-info}/licenses/LICENSE +0 -0
- {berryworld-1.0.0.196751.dist-info → berryworld-1.0.0.197185.dist-info}/top_level.txt +0 -0
berryworld/__init__.py
CHANGED
|
@@ -5,8 +5,7 @@ from .allocation_solver import AllocationSolver
|
|
|
5
5
|
from .pickle_management import PickleManagement
|
|
6
6
|
from .email_logging import EmailLogging
|
|
7
7
|
from .verify_keys import Verify
|
|
8
|
-
from .credentials import SnowflakeCredentials, SQLCredentials,
|
|
9
|
-
MicrosoftTeamsCredentials
|
|
8
|
+
from .credentials import SnowflakeCredentials, SQLCredentials, WebServiceCredentials, MicrosoftTeamsCredentials
|
|
10
9
|
from .persistent_storage import PersistentStorage
|
|
11
10
|
from .generate_env import EnvVariables
|
|
12
11
|
from .sharepoint_con import SharepointConnection, SharepointConn
|
|
@@ -24,4 +23,4 @@ from .teams_logging import TeamsLogging
|
|
|
24
23
|
from .vivantio_logging import VivantioLogging
|
|
25
24
|
from .snowflake_conn import SnowflakeConn
|
|
26
25
|
from .logging import PythonLogs
|
|
27
|
-
from .sql_connenction import SQLConnection
|
|
26
|
+
from .sql_connenction import SQLConnection, SQLConnectionPool, SQLPoolEngine
|
berryworld/credentials.py
CHANGED
|
@@ -71,32 +71,6 @@ class SQLCredentials:
|
|
|
71
71
|
raise ValueError("Variable %s not found" % str(e))
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
class BCCredentials:
|
|
75
|
-
def __init__(self, db_name=None, auth=False):
|
|
76
|
-
self.db_name = db_name
|
|
77
|
-
self.auth = auth
|
|
78
|
-
|
|
79
|
-
def simple_creds(self):
|
|
80
|
-
try:
|
|
81
|
-
if self.auth:
|
|
82
|
-
scope = os.environ.get("BC-AUTH-SCOPE")
|
|
83
|
-
client_id = os.environ.get("BC-AUTH-CLIENT-ID")
|
|
84
|
-
client_secret = os.environ.get("BC-AUTH-CLIENT-SECRET")
|
|
85
|
-
|
|
86
|
-
return {'scope': scope,
|
|
87
|
-
'client_id': client_id,
|
|
88
|
-
'client_secret': client_secret}
|
|
89
|
-
elif self.db_name is not None:
|
|
90
|
-
server_type = os.environ.get(f"BC-ENV-SERVER-{self.db_name.upper()}")
|
|
91
|
-
|
|
92
|
-
return {'server_type': server_type}
|
|
93
|
-
else:
|
|
94
|
-
raise ValueError("Please provide a valid input")
|
|
95
|
-
|
|
96
|
-
except ValueError as e:
|
|
97
|
-
raise ValueError("Variable %s not found" % str(e))
|
|
98
|
-
|
|
99
|
-
|
|
100
74
|
class WebServiceCredentials:
|
|
101
75
|
def __init__(self, service=None):
|
|
102
76
|
self.service = service
|
berryworld/generate_env.py
CHANGED
|
@@ -53,19 +53,24 @@ class EnvVariables:
|
|
|
53
53
|
|
|
54
54
|
return config
|
|
55
55
|
|
|
56
|
-
def
|
|
57
|
-
"""
|
|
56
|
+
def get_secret_client(self, config):
|
|
57
|
+
""" Create a Key Vault client
|
|
58
58
|
:param config: Dictionary containing Azure Key Vault configuration
|
|
59
59
|
"""
|
|
60
60
|
tenant_id = config["AZURE-TENANT-ID"]
|
|
61
61
|
client_id = config["AZURE-CLIENT-ID"]
|
|
62
62
|
client_secret = config["AZURE-CLIENT-SECRET"]
|
|
63
63
|
vault_url = f"https://{config['AZURE-KEY-VAULT-NAME']}.vault.azure.net/"
|
|
64
|
-
project_tags = config["AZURE-KEY-VAULT-PROJECT-TAGS"]
|
|
65
|
-
|
|
66
64
|
credential = ClientSecretCredential(tenant_id, client_id, client_secret)
|
|
67
|
-
client = SecretClient(vault_url=vault_url, credential=credential)
|
|
68
65
|
|
|
66
|
+
return SecretClient(vault_url=vault_url, credential=credential)
|
|
67
|
+
|
|
68
|
+
def fetch_secrets_by_tag(self, config):
|
|
69
|
+
""" Fetch enabled secrets from Azure Key Vault based on tags
|
|
70
|
+
:param config: Dictionary containing Azure Key Vault configuration
|
|
71
|
+
"""
|
|
72
|
+
client = self.get_secret_client(config)
|
|
73
|
+
project_tags = config.get("AZURE-KEY-VAULT-PROJECT-TAGS", [])
|
|
69
74
|
secrets = {}
|
|
70
75
|
for prop in client.list_properties_of_secrets():
|
|
71
76
|
if not prop.enabled:
|
|
@@ -78,33 +83,120 @@ class EnvVariables:
|
|
|
78
83
|
secrets[key] = secret.value
|
|
79
84
|
return secrets
|
|
80
85
|
|
|
81
|
-
def
|
|
86
|
+
def fetch_all_secrets(self, config):
|
|
87
|
+
""" Fetch all enabled secrets from the Key Vault
|
|
88
|
+
:param config: Dictionary containing Azure Key Vault configuration
|
|
89
|
+
"""
|
|
90
|
+
client = self.get_secret_client(config)
|
|
91
|
+
secrets = {}
|
|
92
|
+
for prop in client.list_properties_of_secrets():
|
|
93
|
+
if prop.enabled:
|
|
94
|
+
secret = client.get_secret(prop.name)
|
|
95
|
+
secrets[secret.name] = {
|
|
96
|
+
"value": secret.value,
|
|
97
|
+
"tags": prop.tags or {}
|
|
98
|
+
}
|
|
99
|
+
return secrets
|
|
100
|
+
|
|
101
|
+
def create_or_update_akv_secret(self, config, name=None, value=None, tags=None, tag_name=None, tag_value=None,
|
|
102
|
+
disable_old=True, secrets_dict=None):
|
|
103
|
+
""" Create or update a secret / all secrets in Key Vault :
|
|
104
|
+
:param config: Dictionary containing Azure Key Vault configuration
|
|
105
|
+
:param name: Name of the secret to be created / updated
|
|
106
|
+
:param value: Value of the secret to be created / updated
|
|
107
|
+
:param tags: Dictionary containing Azure Key Vault configuration
|
|
108
|
+
:param tag_name: Tag name of the secret to be created / updated
|
|
109
|
+
:param tag_value: Tag value of the secret to be created / updated
|
|
110
|
+
:param disable_old: Flag if previous version should be disabled
|
|
111
|
+
:param secrets_dict: Dictionary of all the secrets from AKV
|
|
112
|
+
"""
|
|
113
|
+
client = self.get_secret_client(config)
|
|
114
|
+
|
|
115
|
+
# If secrets_dict is provided, loop through it
|
|
116
|
+
if secrets_dict is not None:
|
|
117
|
+
for s_name, s_data in secrets_dict.items():
|
|
118
|
+
self.create_or_update_akv_secret(
|
|
119
|
+
config,
|
|
120
|
+
name=s_name,
|
|
121
|
+
value=s_data["value"],
|
|
122
|
+
tags=s_data.get("tags"),
|
|
123
|
+
disable_old=disable_old
|
|
124
|
+
)
|
|
125
|
+
return
|
|
126
|
+
|
|
127
|
+
if (name is None and value is None) and secrets_dict is None:
|
|
128
|
+
raise ValueError("Must provide either secrets_dict or both name and value")
|
|
129
|
+
|
|
130
|
+
# Check the latest version of the secret
|
|
131
|
+
latest_secret = None
|
|
132
|
+
latest_tags = {}
|
|
133
|
+
try:
|
|
134
|
+
latest_secret = client.get_secret(name)
|
|
135
|
+
latest_tags = latest_secret.properties.tags or {}
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
updated_tags = {**latest_tags}
|
|
140
|
+
if tags is not None:
|
|
141
|
+
updated_tags.update(tags)
|
|
142
|
+
elif tag_name is not None and tag_value is not None:
|
|
143
|
+
updated_tags[tag_name] = tag_value
|
|
144
|
+
|
|
145
|
+
# Check if anything changed in the value or tag
|
|
146
|
+
value_changed = latest_secret is None or latest_secret.value != value
|
|
147
|
+
tags_changed = updated_tags != latest_tags
|
|
148
|
+
|
|
149
|
+
if not value_changed and not tags_changed:
|
|
150
|
+
print(f"Secret {name} already up to date. Skipping.")
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
# Create new version
|
|
154
|
+
new_secret = client.set_secret(name, value, tags=updated_tags)
|
|
155
|
+
new_version = new_secret.properties.version
|
|
156
|
+
print(f"Secret {name} updated. New version: {new_version}.")
|
|
157
|
+
|
|
158
|
+
# Disable previous versions
|
|
159
|
+
if disable_old:
|
|
160
|
+
for secret_prop in client.list_properties_of_secret_versions(name):
|
|
161
|
+
if secret_prop.version != new_version and secret_prop.enabled:
|
|
162
|
+
client.update_secret_properties(secret_prop.name, secret_prop.version, enabled=False)
|
|
163
|
+
|
|
164
|
+
def generate_akv_env_file(self, config_path=None, env_path=None, fetch_all=False):
|
|
82
165
|
""" Generate the environment variables file from Azure Key Vault secrets
|
|
83
166
|
:param config_path: Path to the Terraform configuration file (optional)
|
|
84
167
|
:param env_path: Path to the destination .env file (optional)
|
|
168
|
+
:param fetch_all: Flag if all the secrets should be fetched
|
|
85
169
|
"""
|
|
86
170
|
config = self.extract_akv_config_from_tf(config_path)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
171
|
+
if fetch_all:
|
|
172
|
+
secrets = self.fetch_all_secrets(config)
|
|
173
|
+
else:
|
|
174
|
+
secrets = self.fetch_secrets_by_tag(config)
|
|
175
|
+
|
|
176
|
+
if fetch_all:
|
|
177
|
+
return secrets
|
|
178
|
+
|
|
179
|
+
if not fetch_all:
|
|
180
|
+
# Create .env file for UnitTest
|
|
181
|
+
with open(env_path, "w") as f:
|
|
182
|
+
for key, value in secrets.items():
|
|
183
|
+
f.write(f"{key}={value}\n")
|
|
184
|
+
|
|
185
|
+
# Create .env file for container apps
|
|
186
|
+
if os.name != "nt" and self.env is not None:
|
|
187
|
+
# Linux/Mac: generate terraform .tfvars file
|
|
188
|
+
tfvars_path = f"./environments/{self.env}/secrets.auto.tfvars.json"
|
|
189
|
+
os.makedirs(os.path.dirname(tfvars_path), exist_ok=True)
|
|
190
|
+
with open(tfvars_path, "w") as f:
|
|
191
|
+
json.dump({"keyvault_secrets": secrets}, f, indent=2)
|
|
192
|
+
|
|
193
|
+
def generate_env_tf(self, config_path='./environments/prod/step01.tf', env_path='.env', fetch_all=False):
|
|
103
194
|
""" Main function to parse arguments and generate AKV environment variables file.
|
|
104
195
|
:param config_path: Path to the Terraform configuration file
|
|
105
196
|
:param env_path: Path to the destination .env file
|
|
197
|
+
:param fetch_all: Flag if all the secrets should be fetched
|
|
106
198
|
"""
|
|
107
|
-
self.generate_akv_env_file(config_path=config_path, env_path=env_path)
|
|
199
|
+
self.generate_akv_env_file(config_path=config_path, env_path=env_path, fetch_all=fetch_all)
|
|
108
200
|
|
|
109
201
|
@staticmethod
|
|
110
202
|
def generate_env_file(yaml_path='./environments/prd1/step01.yaml', env_path='./.env'):
|