qontract-reconcile 0.10.2.dev256__py3-none-any.whl → 0.10.2.dev258__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.
Files changed (96) hide show
  1. {qontract_reconcile-0.10.2.dev256.dist-info → qontract_reconcile-0.10.2.dev258.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.2.dev256.dist-info → qontract_reconcile-0.10.2.dev258.dist-info}/RECORD +96 -95
  3. reconcile/aus/advanced_upgrade_service.py +1 -1
  4. reconcile/aus/base.py +2 -2
  5. reconcile/aus/version_gates/sts_version_gate_handler.py +2 -2
  6. reconcile/aws_account_manager/reconciler.py +22 -20
  7. reconcile/aws_iam_keys.py +5 -5
  8. reconcile/aws_iam_password_reset.py +5 -5
  9. reconcile/aws_saml_roles/integration.py +5 -5
  10. reconcile/aws_version_sync/integration.py +4 -3
  11. reconcile/cli.py +16 -12
  12. reconcile/closedbox_endpoint_monitoring_base.py +1 -0
  13. reconcile/database_access_manager.py +4 -4
  14. reconcile/dynatrace_token_provider/integration.py +2 -2
  15. reconcile/external_resources/manager.py +2 -2
  16. reconcile/external_resources/model.py +1 -1
  17. reconcile/external_resources/secrets_sync.py +2 -2
  18. reconcile/gabi_authorized_users.py +3 -3
  19. reconcile/github_org.py +2 -2
  20. reconcile/gitlab_housekeeping.py +1 -1
  21. reconcile/gitlab_mr_sqs_consumer.py +1 -1
  22. reconcile/glitchtip/integration.py +2 -2
  23. reconcile/jenkins_worker_fleets.py +5 -5
  24. reconcile/ldap_groups/integration.py +3 -3
  25. reconcile/ocm_clusters.py +2 -2
  26. reconcile/ocm_internal_notifications/integration.py +2 -2
  27. reconcile/ocm_labels/integration.py +3 -2
  28. reconcile/openshift_base.py +12 -11
  29. reconcile/openshift_cluster_bots.py +2 -2
  30. reconcile/openshift_resources_base.py +3 -3
  31. reconcile/openshift_rhcs_certs.py +2 -2
  32. reconcile/openshift_saas_deploy.py +1 -1
  33. reconcile/quay_membership.py +4 -4
  34. reconcile/rhidp/common.py +3 -2
  35. reconcile/run_integration.py +7 -4
  36. reconcile/saas_auto_promotions_manager/dependencies.py +95 -0
  37. reconcile/saas_auto_promotions_manager/integration.py +85 -165
  38. reconcile/skupper_network/integration.py +3 -3
  39. reconcile/slack_usergroups.py +4 -4
  40. reconcile/status_board.py +3 -3
  41. reconcile/terraform_cloudflare_dns.py +5 -5
  42. reconcile/terraform_cloudflare_users.py +15 -17
  43. reconcile/terraform_resources.py +6 -6
  44. reconcile/terraform_vpc_peerings.py +9 -9
  45. reconcile/unleash_feature_toggles/integration.py +1 -1
  46. reconcile/utils/aggregated_list.py +2 -2
  47. reconcile/utils/aws_api_typed/iam.py +2 -2
  48. reconcile/utils/aws_api_typed/organization.py +4 -4
  49. reconcile/utils/aws_api_typed/service_quotas.py +4 -4
  50. reconcile/utils/aws_api_typed/support.py +9 -9
  51. reconcile/utils/aws_helper.py +1 -1
  52. reconcile/utils/config.py +8 -4
  53. reconcile/utils/deadmanssnitch_api.py +2 -4
  54. reconcile/utils/glitchtip/models.py +18 -12
  55. reconcile/utils/gql.py +4 -4
  56. reconcile/utils/internal_groups/client.py +2 -2
  57. reconcile/utils/jinja2/utils.py +7 -3
  58. reconcile/utils/jjb_client.py +2 -2
  59. reconcile/utils/models.py +2 -1
  60. reconcile/utils/mr/__init__.py +3 -3
  61. reconcile/utils/mr/app_interface_reporter.py +2 -2
  62. reconcile/utils/mr/aws_access.py +5 -2
  63. reconcile/utils/mr/base.py +3 -3
  64. reconcile/utils/mr/user_maintenance.py +1 -1
  65. reconcile/utils/oc.py +11 -11
  66. reconcile/utils/oc_connection_parameters.py +4 -4
  67. reconcile/utils/ocm/base.py +3 -3
  68. reconcile/utils/ocm/products.py +8 -8
  69. reconcile/utils/ocm/search_filters.py +2 -2
  70. reconcile/utils/openshift_resource.py +21 -18
  71. reconcile/utils/pagerduty_api.py +5 -5
  72. reconcile/utils/quay_api.py +2 -2
  73. reconcile/utils/rosa/rosa_cli.py +1 -1
  74. reconcile/utils/rosa/session.py +2 -2
  75. reconcile/utils/runtime/desired_state_diff.py +7 -7
  76. reconcile/utils/saasherder/interfaces.py +1 -0
  77. reconcile/utils/saasherder/models.py +1 -1
  78. reconcile/utils/saasherder/saasherder.py +1 -1
  79. reconcile/utils/secret_reader.py +20 -20
  80. reconcile/utils/slack_api.py +5 -5
  81. reconcile/utils/slo_document_manager.py +6 -6
  82. reconcile/utils/state.py +8 -8
  83. reconcile/utils/terraform_client.py +3 -3
  84. reconcile/utils/terrascript/cloudflare_client.py +2 -2
  85. reconcile/utils/terrascript/cloudflare_resources.py +1 -0
  86. reconcile/utils/terrascript_aws_client.py +12 -11
  87. reconcile/utils/vault.py +22 -22
  88. reconcile/vault_replication.py +15 -15
  89. tools/cli_commands/erv2.py +3 -2
  90. tools/cli_commands/gpg_encrypt.py +9 -9
  91. tools/cli_commands/systems_and_tools.py +1 -1
  92. tools/qontract_cli.py +13 -14
  93. tools/saas_promotion_state/saas_promotion_state.py +4 -4
  94. tools/template_validation.py +5 -5
  95. {qontract_reconcile-0.10.2.dev256.dist-info → qontract_reconcile-0.10.2.dev258.dist-info}/WHEEL +0 -0
  96. {qontract_reconcile-0.10.2.dev256.dist-info → qontract_reconcile-0.10.2.dev258.dist-info}/entry_points.txt +0 -0
@@ -18,11 +18,11 @@ from reconcile.utils import (
18
18
  from reconcile.utils.vault import VaultClient
19
19
 
20
20
 
21
- class VaultForbidden(Exception):
21
+ class VaultForbiddenError(Exception):
22
22
  pass
23
23
 
24
24
 
25
- class SecretNotFound(Exception):
25
+ class SecretNotFoundError(Exception):
26
26
  pass
27
27
 
28
28
 
@@ -162,11 +162,11 @@ class VaultSecretReader(SecretReaderBase):
162
162
  )
163
163
  )
164
164
  except Forbidden:
165
- raise VaultForbidden(
165
+ raise VaultForbiddenError(
166
166
  f"permission denied reading vault secret at {path}"
167
167
  ) from None
168
- except vault.SecretNotFound as e:
169
- raise SecretNotFound(*e.args) from e
168
+ except vault.SecretNotFoundError as e:
169
+ raise SecretNotFoundError(*e.args) from e
170
170
  return data
171
171
 
172
172
  def _read(
@@ -181,8 +181,8 @@ class VaultSecretReader(SecretReaderBase):
181
181
  version=version,
182
182
  )
183
183
  )
184
- except vault.SecretNotFound as e:
185
- raise SecretNotFound(*e.args) from e
184
+ except vault.SecretNotFoundError as e:
185
+ raise SecretNotFoundError(*e.args) from e
186
186
  return data
187
187
 
188
188
 
@@ -203,8 +203,8 @@ class ConfigSecretReader(SecretReaderBase):
203
203
  version=version,
204
204
  )
205
205
  )
206
- except config.SecretNotFound as e:
207
- raise SecretNotFound(*e.args) from e
206
+ except config.SecretNotFoundError as e:
207
+ raise SecretNotFoundError(*e.args) from e
208
208
  return data
209
209
 
210
210
  def _read_all(
@@ -219,8 +219,8 @@ class ConfigSecretReader(SecretReaderBase):
219
219
  version=version,
220
220
  )
221
221
  )
222
- except config.SecretNotFound as e:
223
- raise SecretNotFound(*e.args) from e
222
+ except config.SecretNotFoundError as e:
223
+ raise SecretNotFoundError(*e.args) from e
224
224
  return data
225
225
 
226
226
 
@@ -279,13 +279,13 @@ class SecretReader(SecretReaderBase):
279
279
  if self.settings and self.settings.get("vault"):
280
280
  try:
281
281
  data = self.vault_client.read(params) # type: ignore[attr-defined] # mypy doesn't recognize the VaultClient.__new__ method
282
- except vault.SecretNotFound as e:
283
- raise SecretNotFound(*e.args) from e
282
+ except vault.SecretNotFoundError as e:
283
+ raise SecretNotFoundError(*e.args) from e
284
284
  else:
285
285
  try:
286
286
  data = config.read(params)
287
- except config.SecretNotFound as e:
288
- raise SecretNotFound(*e.args) from e
287
+ except config.SecretNotFoundError as e:
288
+ raise SecretNotFoundError(*e.args) from e
289
289
 
290
290
  return data
291
291
 
@@ -314,15 +314,15 @@ class SecretReader(SecretReaderBase):
314
314
  try:
315
315
  data = self.vault_client.read_all(params) # type: ignore[attr-defined] # mypy doesn't recognize the VaultClient.__new__ method
316
316
  except Forbidden:
317
- raise VaultForbidden(
317
+ raise VaultForbiddenError(
318
318
  f"permission denied reading vault secret at {path}"
319
319
  ) from None
320
- except vault.SecretNotFound as e:
321
- raise SecretNotFound(*e.args) from e
320
+ except vault.SecretNotFoundError as e:
321
+ raise SecretNotFoundError(*e.args) from e
322
322
  else:
323
323
  try:
324
324
  data = config.read_all(params)
325
- except config.SecretNotFound as e:
326
- raise SecretNotFound(*e.args) from e
325
+ except config.SecretNotFoundError as e:
326
+ raise SecretNotFoundError(*e.args) from e
327
327
 
328
328
  return data
@@ -28,11 +28,11 @@ MAX_RETRIES = 5
28
28
  TIMEOUT = 30
29
29
 
30
30
 
31
- class UserNotFoundException(Exception):
31
+ class UserNotFoundError(Exception):
32
32
  pass
33
33
 
34
34
 
35
- class UsergroupNotFoundException(Exception):
35
+ class UsergroupNotFoundError(Exception):
36
36
  pass
37
37
 
38
38
 
@@ -296,7 +296,7 @@ class SlackApi:
296
296
  def get_usergroup_id(self, handle: str) -> str | None:
297
297
  try:
298
298
  return self.get_usergroup(handle)["id"]
299
- except UsergroupNotFoundException:
299
+ except UsergroupNotFoundError:
300
300
  return None
301
301
 
302
302
  def _initiate_usergroups(self) -> None:
@@ -317,7 +317,7 @@ class SlackApi:
317
317
  self._initiate_usergroups()
318
318
  usergroup = [g for g in self.usergroups if g["handle"] == handle]
319
319
  if len(usergroup) != 1:
320
- raise UsergroupNotFoundException(handle)
320
+ raise UsergroupNotFoundError(handle)
321
321
  return usergroup[0]
322
322
 
323
323
  def create_usergroup(self, handle: str) -> str:
@@ -398,7 +398,7 @@ class SlackApi:
398
398
  result = self._sc.users_lookupByEmail(email=f"{user_name}@{mail_address}")
399
399
  except SlackApiError as e:
400
400
  if e.response["error"] == "users_not_found":
401
- raise UserNotFoundException(e.response["error"]) from None
401
+ raise UserNotFoundError(e.response["error"]) from None
402
402
  raise
403
403
 
404
404
  return result["user"]["id"]
@@ -24,15 +24,15 @@ DEFAULT_RETRIES = 3
24
24
  DEFAULT_THREAD_POOL_SIZE = 10
25
25
 
26
26
 
27
- class EmptySLOResult(Exception):
27
+ class EmptySLOResultError(Exception):
28
28
  pass
29
29
 
30
30
 
31
- class EmptySLOValue(Exception):
31
+ class EmptySLOValueError(Exception):
32
32
  pass
33
33
 
34
34
 
35
- class InvalidSLOValue(Exception):
35
+ class InvalidSLOValueError(Exception):
36
36
  pass
37
37
 
38
38
 
@@ -104,13 +104,13 @@ class PrometheusClient(ApiBase):
104
104
  def _extract_current_slo_value(self, data: dict[str, Any]) -> float:
105
105
  result = data["data"]["result"]
106
106
  if not result:
107
- raise EmptySLOResult("prometheus returned empty result")
107
+ raise EmptySLOResultError("prometheus returned empty result")
108
108
  slo_value = result[0]["value"]
109
109
  if not slo_value:
110
- raise EmptySLOValue("prometheus returned empty SLO value")
110
+ raise EmptySLOValueError("prometheus returned empty SLO value")
111
111
  slo_value = float(slo_value[1])
112
112
  if isnan(slo_value):
113
- raise InvalidSLOValue("slo value should be a number")
113
+ raise InvalidSLOValueError("slo value should be a number")
114
114
  return slo_value
115
115
 
116
116
 
reconcile/utils/state.py CHANGED
@@ -39,7 +39,7 @@ from reconcile.utils.secret_reader import (
39
39
  )
40
40
 
41
41
 
42
- class StateInaccessibleException(Exception):
42
+ class StateInaccessibleError(Exception):
43
43
  pass
44
44
 
45
45
 
@@ -180,7 +180,7 @@ def acquire_state_settings(
180
180
  state_bucket_account_name, query_func=query_func
181
181
  )
182
182
  if not account:
183
- raise StateInaccessibleException(
183
+ raise StateInaccessibleError(
184
184
  f"The AWS account {state_bucket_account_name} that holds the state bucket can't be found in app-interface."
185
185
  )
186
186
  secret = secret_reader.read_all_secret(account.automation_token)
@@ -203,11 +203,11 @@ def acquire_state_settings(
203
203
  access_key_id=secret["aws_access_key_id"],
204
204
  secret_access_key=secret["aws_secret_access_key"],
205
205
  )
206
- raise StateInaccessibleException(
206
+ raise StateInaccessibleError(
207
207
  f"The app-interface state provider {ai_settings.provider} is not supported."
208
208
  )
209
209
 
210
- raise StateInaccessibleException(
210
+ raise StateInaccessibleError(
211
211
  "app-interface state must be configured to use stateful integrations. "
212
212
  "use one of the following options to provide state config: "
213
213
  "* env vars APP_INTERFACE_STATE_BUCKET, APP_INTERFACE_STATE_BUCKET_REGION, APP_INTERFACE_STATE_AWS_PROFILE and AWS_CONFIG (hosting the requested profile) \n"
@@ -218,7 +218,7 @@ def acquire_state_settings(
218
218
  )
219
219
 
220
220
 
221
- class AbortStateTransaction(Exception):
221
+ class AbortStateTransactionError(Exception):
222
222
  """Raise to abort a state transaction."""
223
223
 
224
224
 
@@ -249,7 +249,7 @@ class State:
249
249
  try:
250
250
  self.client.head_bucket(Bucket=self.bucket)
251
251
  except ClientError as details:
252
- raise StateInaccessibleException(
252
+ raise StateInaccessibleError(
253
253
  f"Bucket {self.bucket} is not accessible - {details!s}"
254
254
  ) from None
255
255
 
@@ -299,7 +299,7 @@ class State:
299
299
  if error_code == "404":
300
300
  return False, {}
301
301
 
302
- raise StateInaccessibleException(
302
+ raise StateInaccessibleError(
303
303
  f"Can not access state key {key_path} "
304
304
  f"in bucket {self.bucket} - {details!s}"
305
305
  ) from None
@@ -436,7 +436,7 @@ class State:
436
436
  state_obj = TransactionStateObj(key, value=current_value)
437
437
  try:
438
438
  yield state_obj
439
- except AbortStateTransaction:
439
+ except AbortStateTransactionError:
440
440
  return
441
441
  else:
442
442
  if state_obj.changed and state_obj.value != current_value:
@@ -913,13 +913,13 @@ class TerraformClient: # pylint: disable=too-many-public-methods
913
913
  )
914
914
 
915
915
 
916
- class TerraformPlanFailed(Exception):
916
+ class TerraformPlanFailedError(Exception):
917
917
  pass
918
918
 
919
919
 
920
- class TerraformApplyFailed(Exception):
920
+ class TerraformApplyFailedError(Exception):
921
921
  pass
922
922
 
923
923
 
924
- class TerraformDeletionDetected(Exception):
924
+ class TerraformDeletionDetectedError(Exception):
925
925
  pass
@@ -302,9 +302,9 @@ def _get_terraform_s3_state_key_name(
302
302
  return sharding_strategy.get_object_key(integration)
303
303
 
304
304
 
305
- class IntegrationUndefined(Exception):
305
+ class IntegrationUndefinedError(Exception):
306
306
  pass
307
307
 
308
308
 
309
- class InvalidTerraformState(Exception):
309
+ class InvalidTerraformStateError(Exception):
310
310
  pass
@@ -1,3 +1,4 @@
1
+ # ruff: noqa: N801
1
2
  from collections.abc import (
2
3
  Iterable,
3
4
  MutableMapping,
@@ -1,3 +1,4 @@
1
+ # ruff: noqa: N801
1
2
  import base64
2
3
  import enum
3
4
  import json
@@ -303,7 +304,7 @@ AWS_US_GOV_ELB_ACCOUNT_IDS = {
303
304
  }
304
305
 
305
306
 
306
- class OutputResourceNameNotUniqueException(Exception):
307
+ class OutputResourceNameNotUniqueError(Exception):
307
308
  def __init__(self, namespace, duplicates):
308
309
  self.namespace, self.duplicates = namespace, duplicates
309
310
  super().__init__(
@@ -319,7 +320,7 @@ class RDSParameterGroupValidationError(Exception):
319
320
  pass
320
321
 
321
322
 
322
- class StateInaccessibleException(Exception):
323
+ class StateInaccessibleError(Exception):
323
324
  pass
324
325
 
325
326
 
@@ -1659,7 +1660,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
1659
1660
  name_counter = Counter(spec.output_resource_name for spec in specs)
1660
1661
  duplicates = [name for name, count in name_counter.items() if count > 1]
1661
1662
  if duplicates:
1662
- raise OutputResourceNameNotUniqueException(
1663
+ raise OutputResourceNameNotUniqueError(
1663
1664
  namespace_info.get("name"), duplicates
1664
1665
  )
1665
1666
  for spec in specs:
@@ -4566,7 +4567,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
4566
4567
  publishing_options blocks which will be further used
4567
4568
  by the consumer.
4568
4569
  """
4569
- ES_LOG_GROUP_RETENTION_DAYS = 90
4570
+ es_log_group_retention_days = 90
4570
4571
  tf_resources = []
4571
4572
  publishing_options = []
4572
4573
 
@@ -4590,7 +4591,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
4590
4591
  log_group_values = {
4591
4592
  "name": log_type_identifier,
4592
4593
  "tags": values["tags"],
4593
- "retention_in_days": ES_LOG_GROUP_RETENTION_DAYS,
4594
+ "retention_in_days": es_log_group_retention_days,
4594
4595
  }
4595
4596
  region = values.get("region") or self.default_regions.get(account)
4596
4597
  if self._multiregion_account(account):
@@ -5066,12 +5067,12 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
5066
5067
  + "does not have required key [certificate]"
5067
5068
  )
5068
5069
 
5069
- caCertificate = secret_data.get("caCertificate", None)
5070
+ ca_certificate = secret_data.get("caCertificate", None)
5071
+ if ca_certificate is not None:
5072
+ values["certificate_chain"] = ca_certificate
5070
5073
 
5071
5074
  values["private_key"] = key
5072
5075
  values["certificate_body"] = certificate
5073
- if caCertificate is not None:
5074
- values["certificate_chain"] = caCertificate
5075
5076
 
5076
5077
  domain = common_values.get("domain", None)
5077
5078
  if domain is not None:
@@ -5115,9 +5116,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
5115
5116
  output_name = output_prefix + "__certificate"
5116
5117
  output_value = certificate
5117
5118
  tf_resources.append(Output(output_name, value=output_value, sensitive=True))
5118
- if caCertificate is not None:
5119
+ if ca_certificate is not None:
5119
5120
  output_name = output_prefix + "__caCertificate"
5120
- output_value = caCertificate
5121
+ output_value = ca_certificate
5121
5122
  tf_resources.append(
5122
5123
  Output(output_name, value=output_value, sensitive=True)
5123
5124
  )
@@ -6016,7 +6017,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
6016
6017
  try:
6017
6018
  s3_client.head_bucket(Bucket=bucket_name)
6018
6019
  except ClientError as details:
6019
- raise StateInaccessibleException(
6020
+ raise StateInaccessibleError(
6020
6021
  f"Bucket {bucket_name} is not accessible - {details!s}"
6021
6022
  ) from None
6022
6023
 
reconcile/utils/vault.py CHANGED
@@ -18,27 +18,27 @@ LOG = logging.getLogger(__name__)
18
18
  VAULT_AUTO_REFRESH_INTERVAL = int(os.getenv("VAULT_AUTO_REFRESH_INTERVAL") or 600)
19
19
 
20
20
 
21
- class PathAccessForbidden(Exception):
21
+ class PathAccessForbiddenError(Exception):
22
22
  pass
23
23
 
24
24
 
25
- class SecretNotFound(Exception):
25
+ class SecretNotFoundError(Exception):
26
26
  pass
27
27
 
28
28
 
29
- class SecretAccessForbidden(Exception):
29
+ class SecretAccessForbiddenError(Exception):
30
30
  pass
31
31
 
32
32
 
33
- class SecretVersionIsNone(Exception):
33
+ class SecretVersionIsNoneError(Exception):
34
34
  pass
35
35
 
36
36
 
37
- class SecretVersionNotFound(Exception):
37
+ class SecretVersionNotFoundError(Exception):
38
38
  pass
39
39
 
40
40
 
41
- class SecretFieldNotFound(Exception):
41
+ class SecretFieldNotFoundError(Exception):
42
42
  pass
43
43
 
44
44
 
@@ -189,7 +189,7 @@ class _VaultClient:
189
189
  data = secret_data
190
190
 
191
191
  if data is None:
192
- raise SecretNotFound
192
+ raise SecretNotFoundError
193
193
 
194
194
  return data, version
195
195
 
@@ -223,7 +223,7 @@ class _VaultClient:
223
223
  read_path = "/".join(path_split[1:])
224
224
  if version is None:
225
225
  msg = f"version can not be null for secret with path '{path}'."
226
- raise SecretVersionIsNone(msg)
226
+ raise SecretVersionIsNoneError(msg)
227
227
  if version == SECRET_VERSION_LATEST:
228
228
  # https://github.com/hvac/hvac/blob/
229
229
  # ec048ded30d21c13c21cfa950d148c8bfc1467b0/
@@ -237,12 +237,12 @@ class _VaultClient:
237
237
  )
238
238
  except InvalidPath:
239
239
  msg = f"version '{version}' not found for secret with path '{path}'."
240
- raise SecretVersionNotFound(msg) from None
240
+ raise SecretVersionNotFoundError(msg) from None
241
241
  except hvac.exceptions.Forbidden:
242
242
  msg = f"permission denied accessing secret '{path}'"
243
- raise SecretAccessForbidden(msg) from None
243
+ raise SecretAccessForbiddenError(msg) from None
244
244
  if secret is None or "data" not in secret or "data" not in secret["data"]:
245
- raise SecretNotFound(path)
245
+ raise SecretNotFoundError(path)
246
246
 
247
247
  data = secret["data"]["data"]
248
248
  secret_version = secret["data"]["metadata"]["version"]
@@ -253,10 +253,10 @@ class _VaultClient:
253
253
  secret = self._client.read(path)
254
254
  except hvac.exceptions.Forbidden:
255
255
  msg = f"permission denied accessing secret '{path}'"
256
- raise SecretAccessForbidden(msg) from None
256
+ raise SecretAccessForbiddenError(msg) from None
257
257
 
258
258
  if secret is None or "data" not in secret:
259
- raise SecretNotFound(path)
259
+ raise SecretNotFoundError(path)
260
260
 
261
261
  return secret["data"]
262
262
 
@@ -285,7 +285,7 @@ class _VaultClient:
285
285
  data = self._read_v1(secret_path, secret_field)
286
286
 
287
287
  if data is None:
288
- raise SecretNotFound
288
+ raise SecretNotFoundError
289
289
 
290
290
  return (
291
291
  base64.b64decode(data).decode("utf-8")
@@ -298,7 +298,7 @@ class _VaultClient:
298
298
  try:
299
299
  secret_field = data[field]
300
300
  except KeyError:
301
- raise SecretFieldNotFound(f"{path}/{field} ({version})") from None
301
+ raise SecretFieldNotFoundError(f"{path}/{field} ({version})") from None
302
302
  return secret_field
303
303
 
304
304
  def _read_v1(self, path, field):
@@ -306,7 +306,7 @@ class _VaultClient:
306
306
  try:
307
307
  secret_field = data[field]
308
308
  except KeyError:
309
- raise SecretFieldNotFound(f"{path}/{field}") from None
309
+ raise SecretFieldNotFoundError(f"{path}/{field}") from None
310
310
  return secret_field
311
311
 
312
312
  @retry()
@@ -345,7 +345,7 @@ class _VaultClient:
345
345
  if current_data == data and not force:
346
346
  logging.debug(f"current data is up-to-date, skipping {path}")
347
347
  return
348
- except SecretVersionNotFound:
348
+ except SecretVersionNotFoundError:
349
349
  # if the secret is not found we need to write it
350
350
  logging.debug(f"secret not found in {path}, will create it")
351
351
 
@@ -358,14 +358,14 @@ class _VaultClient:
358
358
  self._read_all_v2.cache_clear()
359
359
  except hvac.exceptions.Forbidden:
360
360
  msg = f"permission denied accessing secret '{path}'"
361
- raise SecretAccessForbidden(msg) from None
361
+ raise SecretAccessForbiddenError(msg) from None
362
362
 
363
363
  def _write_v1(self, path, data):
364
364
  try:
365
365
  self._client.write(path, **data)
366
366
  except hvac.exceptions.Forbidden:
367
367
  msg = f"permission denied accessing secret '{path}'"
368
- raise SecretAccessForbidden(msg) from None
368
+ raise SecretAccessForbiddenError(msg) from None
369
369
 
370
370
  def _list_kv2(self, path: str) -> dict:
371
371
  try:
@@ -376,14 +376,14 @@ class _VaultClient:
376
376
  return response
377
377
  except hvac.exceptions.Forbidden:
378
378
  msg = f"permission denied accessing path '{path}'"
379
- raise PathAccessForbidden(msg) from None
379
+ raise PathAccessForbiddenError(msg) from None
380
380
 
381
381
  def _list(self, path: str) -> dict:
382
382
  try:
383
383
  return self._client.list(path)
384
384
  except hvac.exceptions.Forbidden:
385
385
  msg = f"permission denied accessing path '{path}'"
386
- raise PathAccessForbidden(msg) from None
386
+ raise PathAccessForbiddenError(msg) from None
387
387
 
388
388
  def list(self, path: str) -> list[str]:
389
389
  """Returns a list of secrets in a given path."""
@@ -420,7 +420,7 @@ class _VaultClient:
420
420
  self._client.delete(path)
421
421
  except hvac.exceptions.Forbidden:
422
422
  msg = f"permission denied accessing secret '{path}'"
423
- raise SecretAccessForbidden(msg) from None
423
+ raise SecretAccessForbiddenError(msg) from None
424
424
 
425
425
 
426
426
  class VaultClient:
@@ -26,9 +26,9 @@ from reconcile.gql_definitions.vault_policies.vault_policies import (
26
26
  )
27
27
  from reconcile.utils import gql
28
28
  from reconcile.utils.vault import (
29
- SecretAccessForbidden,
30
- SecretNotFound,
31
- SecretVersionNotFound,
29
+ SecretAccessForbiddenError,
30
+ SecretNotFoundError,
31
+ SecretVersionNotFoundError,
32
32
  VaultClient,
33
33
  _VaultClient,
34
34
  )
@@ -37,15 +37,15 @@ QONTRACT_INTEGRATION = "vault-replication"
37
37
  SECRET_PATH_PATTERN = re.compile(r"^[\w/-]+?(?P<folder>/\*?)?$")
38
38
 
39
39
 
40
- class VaultInvalidPaths(Exception):
40
+ class VaultInvalidPathsError(Exception):
41
41
  pass
42
42
 
43
43
 
44
- class VaultInvalidAuthMethod(Exception):
44
+ class VaultInvalidAuthMethodError(Exception):
45
45
  pass
46
46
 
47
47
 
48
- class VaultInvalidPolicy(Exception):
48
+ class VaultInvalidPolicyError(Exception):
49
49
  pass
50
50
 
51
51
 
@@ -64,7 +64,7 @@ def deep_copy_versions(
64
64
 
65
65
  try:
66
66
  secret, src_version = source_vault.read_all_with_version(secret_dict)
67
- except (SecretNotFound, SecretVersionNotFound):
67
+ except (SecretNotFoundError, SecretVersionNotFoundError):
68
68
  # Handle the case where the difference between the source and destination
69
69
  # versions is greater than the number of versions in the source vault.
70
70
  # By default the secret engines store up to 10 versions of a secret.
@@ -119,7 +119,7 @@ def copy_vault_secret(
119
119
 
120
120
  try:
121
121
  source_data, version = source_vault.read_all_with_version(secret_dict)
122
- except SecretAccessForbidden:
122
+ except SecretAccessForbiddenError:
123
123
  # Raise exception if we can't read the secret from the source vault.
124
124
  # This is likely to be related to the approle permissions.
125
125
  logging.error([
@@ -128,7 +128,7 @@ def copy_vault_secret(
128
128
  path,
129
129
  ])
130
130
  raise
131
- except SecretNotFound:
131
+ except SecretNotFoundError:
132
132
  # If the secret is present in vault, but there are no versions of it
133
133
  # we want to be aware of it, but not cause a failure of the complete
134
134
  # integration
@@ -161,7 +161,7 @@ def copy_vault_secret(
161
161
  current_source_version=version,
162
162
  path=path,
163
163
  )
164
- except (SecretVersionNotFound, SecretNotFound):
164
+ except (SecretVersionNotFoundError, SecretNotFoundError):
165
165
  logging.info(["replicate_vault_secret", "Secret not found", path])
166
166
  # Handle v1 secrets where version is None and we don't need to deep sync.
167
167
  if version is None:
@@ -194,7 +194,7 @@ def check_invalid_paths(
194
194
  # Exit if we have paths not present in the policy that needs to be replicated
195
195
  # this is to prevent to replicate secrets that are not allowed.
196
196
  logging.error(["replicate_vault_secret", "Invalid paths", invalid_paths])
197
- raise VaultInvalidPaths
197
+ raise VaultInvalidPathsError
198
198
 
199
199
 
200
200
  def list_invalid_paths(
@@ -236,7 +236,7 @@ def get_policy_secret_list(
236
236
  match = SECRET_PATH_PATTERN.match(path)
237
237
  if not match:
238
238
  logging.error(["get_policy_secret_list", "Invalid path to replicate", path])
239
- raise VaultInvalidPaths
239
+ raise VaultInvalidPathsError
240
240
 
241
241
  if match.group("folder"):
242
242
  # Remove the * at the end of the path because list method expects
@@ -304,7 +304,7 @@ def get_vault_credentials(
304
304
  VaultInstanceV1_VaultReplicationConfigV1_VaultInstanceAuthV1_VaultInstanceAuthApproleV1,
305
305
  ):
306
306
  # Exit if the auth method is not approle as is the only one supported
307
- raise VaultInvalidAuthMethod
307
+ raise VaultInvalidAuthMethodError
308
308
 
309
309
  role_id = {
310
310
  "path": vault_auth.role_id.path,
@@ -359,7 +359,7 @@ def replicate_paths(
359
359
  if path.policy is None:
360
360
  # Exit if the replication config is empty, this should never happen
361
361
  # as policy is a required field in the schema but makes mypy happy.
362
- raise VaultInvalidPolicy(
362
+ raise VaultInvalidPolicyError(
363
363
  "Policy is required when using policy provider"
364
364
  )
365
365
  policy_paths = get_policy_paths(
@@ -402,7 +402,7 @@ def get_secrets_from_templated_path(path: str, vault_list: Iterable[str]) -> lis
402
402
  suffix = cap_groups.group(3)
403
403
  else:
404
404
  # Exit if the path is not a valid formatted template on the secret path
405
- raise VaultInvalidPaths
405
+ raise VaultInvalidPathsError
406
406
 
407
407
  secret_start, secret_end = _get_start_end_secret(path)
408
408
 
@@ -39,6 +39,9 @@ from reconcile.utils import gql
39
39
  from reconcile.utils.exceptions import FetchResourceError
40
40
  from reconcile.utils.secret_reader import SecretReaderBase
41
41
 
42
+ UP = "\x1b[1A"
43
+ CLEAR = "\x1b[2K"
44
+
42
45
 
43
46
  def progress_spinner() -> Progress:
44
47
  """Display shiny progress spinner."""
@@ -56,8 +59,6 @@ def pause_progress_spinner(progress: Progress | None) -> Iterator:
56
59
  """Pause the progress spinner."""
57
60
  if progress:
58
61
  progress.stop()
59
- UP = "\x1b[1A"
60
- CLEAR = "\x1b[2K"
61
62
  for task in progress.tasks:
62
63
  if task.finished:
63
64
  continue