qontract-reconcile 0.10.1rc976__py3-none-any.whl → 0.10.1rc978__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 (110) hide show
  1. {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc978.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc978.dist-info}/RECORD +110 -110
  3. reconcile/aus/healthchecks.py +1 -1
  4. reconcile/aws_account_manager/integration.py +23 -21
  5. reconcile/aws_account_manager/reconciler.py +1 -1
  6. reconcile/aws_saml_idp/integration.py +5 -5
  7. reconcile/aws_saml_roles/integration.py +5 -5
  8. reconcile/aws_version_sync/utils.py +3 -3
  9. reconcile/cli.py +11 -2
  10. reconcile/cna/state.py +2 -2
  11. reconcile/database_access_manager.py +2 -5
  12. reconcile/external_resources/manager.py +3 -3
  13. reconcile/external_resources/model.py +1 -1
  14. reconcile/external_resources/secrets_sync.py +2 -2
  15. reconcile/external_resources/state.py +1 -1
  16. reconcile/gcr_mirror.py +2 -6
  17. reconcile/jira_permissions_validator.py +4 -4
  18. reconcile/ldap_groups/integration.py +4 -7
  19. reconcile/ocm_internal_notifications/integration.py +2 -2
  20. reconcile/openshift_base.py +14 -14
  21. reconcile/openshift_cluster_bots.py +1 -1
  22. reconcile/openshift_clusterrolebindings.py +9 -10
  23. reconcile/openshift_namespace_labels.py +2 -2
  24. reconcile/openshift_namespaces.py +1 -1
  25. reconcile/openshift_resources_base.py +9 -9
  26. reconcile/openshift_rolebindings.py +8 -11
  27. reconcile/openshift_saas_deploy_trigger_base.py +8 -5
  28. reconcile/oum/base.py +1 -1
  29. reconcile/quay_mirror.py +3 -10
  30. reconcile/queries.py +1 -1
  31. reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +2 -2
  32. reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
  33. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +0 -1
  34. reconcile/skupper_network/integration.py +3 -1
  35. reconcile/skupper_network/site_controller.py +8 -8
  36. reconcile/slack_usergroups.py +10 -10
  37. reconcile/status_board.py +1 -1
  38. reconcile/statuspage/status.py +1 -3
  39. reconcile/terraform_cloudflare_dns.py +2 -3
  40. reconcile/terraform_cloudflare_users.py +2 -3
  41. reconcile/terraform_repo.py +5 -3
  42. reconcile/terraform_resources.py +16 -16
  43. reconcile/terraform_tgw_attachments.py +6 -6
  44. reconcile/terraform_vpc_peerings.py +8 -8
  45. reconcile/terraform_vpc_resources/integration.py +1 -1
  46. reconcile/test/test_aws_cloudwatch_log_retention.py +2 -5
  47. reconcile/test/test_github_org.py +18 -16
  48. reconcile/test/test_github_repo_invites.py +10 -10
  49. reconcile/test/test_integrations_manager.py +11 -11
  50. reconcile/test/test_ocm_additional_routers.py +6 -6
  51. reconcile/test/test_ocm_clusters.py +1 -0
  52. reconcile/test/test_ocm_update_recommended_version.py +2 -2
  53. reconcile/test/test_openshift_serviceaccount_tokens.py +5 -5
  54. reconcile/test/test_openshift_tekton_resources.py +3 -3
  55. reconcile/test/test_saasherder.py +48 -48
  56. reconcile/test/test_sql_query.py +1 -1
  57. reconcile/test/test_terraform_cloudflare_resources.py +14 -14
  58. reconcile/test/test_terraform_cloudflare_users.py +4 -4
  59. reconcile/test/test_terraform_resources.py +32 -32
  60. reconcile/test/test_terraform_tgw_attachments.py +5 -5
  61. reconcile/typed_queries/saas_files.py +1 -1
  62. reconcile/unleash_feature_toggles/integration.py +2 -2
  63. reconcile/utils/aggregated_list.py +1 -1
  64. reconcile/utils/aws_api.py +1 -1
  65. reconcile/utils/aws_api_typed/iam.py +4 -2
  66. reconcile/utils/aws_api_typed/service_quotas.py +2 -2
  67. reconcile/utils/binary.py +1 -1
  68. reconcile/utils/clusterhealth/telemeter.py +5 -3
  69. reconcile/utils/config.py +4 -2
  70. reconcile/utils/expiration.py +1 -1
  71. reconcile/utils/external_resources.py +4 -7
  72. reconcile/utils/git.py +1 -3
  73. reconcile/utils/gitlab_api.py +1 -4
  74. reconcile/utils/gql.py +9 -8
  75. reconcile/utils/helm.py +1 -1
  76. reconcile/utils/imap_client.py +3 -1
  77. reconcile/utils/internal_groups/client.py +1 -1
  78. reconcile/utils/jinja2/utils.py +4 -4
  79. reconcile/utils/jobcontroller/models.py +2 -2
  80. reconcile/utils/jump_host.py +1 -1
  81. reconcile/utils/ldap_client.py +1 -1
  82. reconcile/utils/merge_request_manager/merge_request_manager.py +1 -4
  83. reconcile/utils/models.py +2 -5
  84. reconcile/utils/oc.py +18 -28
  85. reconcile/utils/ocm/ocm.py +3 -1
  86. reconcile/utils/ocm/products.py +2 -2
  87. reconcile/utils/ocm/search_filters.py +4 -11
  88. reconcile/utils/ocm_base_client.py +1 -4
  89. reconcile/utils/openshift_resource.py +12 -19
  90. reconcile/utils/quay_api.py +1 -3
  91. reconcile/utils/repo_owners.py +2 -8
  92. reconcile/utils/runtime/runner.py +1 -1
  93. reconcile/utils/saasherder/saasherder.py +4 -4
  94. reconcile/utils/secret_reader.py +2 -2
  95. reconcile/utils/slack_api.py +1 -1
  96. reconcile/utils/sqs_gateway.py +1 -1
  97. reconcile/utils/state.py +4 -4
  98. reconcile/utils/terraform/config_client.py +1 -1
  99. reconcile/utils/terraform_client.py +2 -2
  100. reconcile/utils/terrascript_aws_client.py +13 -23
  101. reconcile/utils/three_way_diff_strategy.py +3 -9
  102. reconcile/utils/unleash/client.py +2 -2
  103. reconcile/utils/vault.py +11 -14
  104. reconcile/utils/vcs.py +1 -1
  105. reconcile/vault_replication.py +1 -1
  106. tools/app_interface_reporter.py +2 -3
  107. tools/qontract_cli.py +1 -1
  108. {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc978.dist-info}/WHEEL +0 -0
  109. {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc978.dist-info}/entry_points.txt +0 -0
  110. {qontract_reconcile-0.10.1rc976.dist-info → qontract_reconcile-0.10.1rc978.dist-info}/top_level.txt +0 -0
@@ -252,29 +252,31 @@ class AwsAccountMgmtIntegration(
252
252
  )
253
253
 
254
254
  secret = self.secret_reader.read_all_secret(payer_account.automation_token)
255
- with AWSApi(
256
- AWSStaticCredentials(
257
- access_key_id=secret["aws_access_key_id"],
258
- secret_access_key=secret["aws_secret_access_key"],
259
- region=payer_account.resources_default_region,
260
- )
261
- ) as payer_account_aws_api:
262
- with payer_account_aws_api.assume_role(
255
+ with (
256
+ AWSApi(
257
+ AWSStaticCredentials(
258
+ access_key_id=secret["aws_access_key_id"],
259
+ secret_access_key=secret["aws_secret_access_key"],
260
+ region=payer_account.resources_default_region,
261
+ )
262
+ ) as payer_account_aws_api,
263
+ payer_account_aws_api.assume_role(
263
264
  account_id=payer_account.uid,
264
265
  role=aws_account_manager_role,
265
- ) as acct_manager_role_aws_api:
266
- self.create_accounts(
267
- acct_manager_role_aws_api,
268
- reconciler,
269
- merge_request_manager,
270
- account_template,
271
- payer_account.account_requests or [],
272
- )
273
- self.reconcile_organization_accounts(
274
- acct_manager_role_aws_api,
275
- reconciler,
276
- payer_account.organization_accounts or [],
277
- )
266
+ ) as acct_manager_role_aws_api,
267
+ ):
268
+ self.create_accounts(
269
+ acct_manager_role_aws_api,
270
+ reconciler,
271
+ merge_request_manager,
272
+ account_template,
273
+ payer_account.account_requests or [],
274
+ )
275
+ self.reconcile_organization_accounts(
276
+ acct_manager_role_aws_api,
277
+ reconciler,
278
+ payer_account.organization_accounts or [],
279
+ )
278
280
 
279
281
  def reconcile_non_organization_accounts(
280
282
  self,
@@ -204,7 +204,7 @@ class AWSReconciler:
204
204
  except AWSResourceAlreadyExistsException:
205
205
  raise AbortStateTransaction(
206
206
  f"A quota increase for this {new_quota.service_code}/{new_quota.quota_code} already exists. Try it again later."
207
- )
207
+ ) from None
208
208
  ids.append(req.id)
209
209
 
210
210
  _state.value = {"last_applied_quotas": quotas_dict, "ids": ids}
@@ -163,11 +163,11 @@ class AwsSamlIdpIntegration(QontractReconcileIntegration[AwsSamlIdpIntegrationPa
163
163
  if defer:
164
164
  defer(tf.cleanup)
165
165
 
166
- runner_params: RunnerParams = dict(
167
- tf=tf,
168
- dry_run=dry_run,
169
- enable_deletion=self.params.enable_deletion,
170
- )
166
+ runner_params: RunnerParams = {
167
+ "tf": tf,
168
+ "dry_run": dry_run,
169
+ "enable_deletion": self.params.enable_deletion,
170
+ }
171
171
 
172
172
  if self.params.enable_extended_early_exit and get_feature_toggle_state(
173
173
  f"{QONTRACT_INTEGRATION}-extended-early-exit", default=True
@@ -281,11 +281,11 @@ class AwsSamlRolesIntegration(
281
281
  if defer:
282
282
  defer(tf.cleanup)
283
283
 
284
- runner_params: RunnerParams = dict(
285
- tf=tf,
286
- dry_run=dry_run,
287
- enable_deletion=self.params.enable_deletion,
288
- )
284
+ runner_params: RunnerParams = {
285
+ "tf": tf,
286
+ "dry_run": dry_run,
287
+ "enable_deletion": self.params.enable_deletion,
288
+ }
289
289
 
290
290
  if self.params.enable_extended_early_exit and get_feature_toggle_state(
291
291
  f"{QONTRACT_INTEGRATION}-extended-early-exit", default=True
@@ -48,13 +48,13 @@ def get_values(gql_get_resource_func: Callable, path: str) -> dict[str, Any]:
48
48
  try:
49
49
  raw_values = gql_get_resource_func(path)
50
50
  except GqlGetResourceError as e:
51
- raise FetchResourceError(str(e))
51
+ raise FetchResourceError(str(e)) from e
52
52
  try:
53
53
  values = anymarkup.parse(raw_values["content"], force_types=None)
54
54
  values.pop("$schema", None)
55
- except anymarkup.AnyMarkupError:
55
+ except anymarkup.AnyMarkupError as e:
56
56
  e_msg = "Could not parse data. Skipping resource: {}"
57
- raise FetchResourceError(e_msg.format(path))
57
+ raise FetchResourceError(e_msg.format(path)) from e
58
58
  return values
59
59
 
60
60
 
reconcile/cli.py CHANGED
@@ -2710,11 +2710,20 @@ def ocm_upgrade_scheduler_org_updater(ctx, gitlab_project_id):
2710
2710
  @integration.command(
2711
2711
  short_help="Manage Addons Upgrade Policy schedules in OCM organizations."
2712
2712
  )
2713
+ @click.option(
2714
+ "--ocm-env",
2715
+ help="The OCM environment the integration should operator on. If none is specified, all environments will be operated on.",
2716
+ required=False,
2717
+ envvar="OCM_ENV",
2718
+ )
2713
2719
  @org_id_multiple
2714
2720
  @exclude_org_id
2715
2721
  @click.pass_context
2716
2722
  def ocm_addons_upgrade_scheduler_org(
2717
- ctx, org_id: Iterable[str], exclude_org_id: Iterable[str]
2723
+ ctx,
2724
+ ocm_env: str,
2725
+ org_id: Iterable[str],
2726
+ exclude_org_id: Iterable[str],
2718
2727
  ) -> None:
2719
2728
  from reconcile.aus.base import AdvancedUpgradeSchedulerBaseIntegrationParams
2720
2729
  from reconcile.aus.ocm_addons_upgrade_scheduler_org import (
@@ -2724,7 +2733,7 @@ def ocm_addons_upgrade_scheduler_org(
2724
2733
  run_class_integration(
2725
2734
  integration=OCMAddonsUpgradeSchedulerOrgIntegration(
2726
2735
  AdvancedUpgradeSchedulerBaseIntegrationParams(
2727
- ocm_environment="ocm-integration",
2736
+ ocm_environment=ocm_env,
2728
2737
  ocm_organization_ids=set(org_id),
2729
2738
  excluded_ocm_organization_ids=set(exclude_org_id),
2730
2739
  )
reconcile/cna/state.py CHANGED
@@ -36,10 +36,10 @@ class State:
36
36
  def __eq__(self, other: object) -> bool:
37
37
  if not isinstance(other, State):
38
38
  return False
39
- if not set(list(self._assets.keys())) == set(list(other._assets.keys())):
39
+ if not set(self._assets.keys()) == set(other._assets.keys()):
40
40
  return False
41
41
  for kind in list(self._assets.keys()):
42
- if not set(list(self._assets[kind])) == set(list(other._assets[kind])):
42
+ if not set(self._assets[kind]) == set(other._assets[kind]):
43
43
  return False
44
44
  for name, asset in self._assets[kind].items():
45
45
  if asset != other._assets[kind][name]:
@@ -406,13 +406,10 @@ class JobStatus(BaseModel):
406
406
  conditions: list[JobStatusCondition]
407
407
 
408
408
  def is_complete(self) -> bool:
409
- return True if self.conditions else False
409
+ return bool(self.conditions)
410
410
 
411
411
  def has_errors(self) -> bool:
412
- for condition in self.conditions:
413
- if condition.type == "Failed":
414
- return True
415
- return False
412
+ return any(condition.type == "Failed" for condition in self.conditions)
416
413
 
417
414
 
418
415
  def _populate_resources(
@@ -210,10 +210,10 @@ class ExternalResourcesManager:
210
210
  """
211
211
  need_secret_sync = False
212
212
 
213
- if state.resource_status not in set([
213
+ if state.resource_status not in {
214
214
  ResourceStatus.DELETE_IN_PROGRESS,
215
215
  ResourceStatus.IN_PROGRESS,
216
- ]):
216
+ }:
217
217
  return False
218
218
 
219
219
  logging.info(
@@ -374,5 +374,5 @@ class ExternalResourcesManager:
374
374
  for r in triggered:
375
375
  self.reconciler.get_resource_reconcile_logs(reconciliation=r)
376
376
 
377
- if ReconcileStatus.ERROR in [rs for rs in results.values()]:
377
+ if ReconcileStatus.ERROR in list(results.values()):
378
378
  raise Exception("Some Resources have reconciliation errors.")
@@ -118,7 +118,7 @@ class ExternalResourcesInventory(MutableMapping):
118
118
  return self._inventory[key]
119
119
  except KeyError:
120
120
  msg = f"Resource spec not found: Provider {provider}, Id: {identifier}"
121
- raise FetchResourceError(msg)
121
+ raise FetchResourceError(msg) from None
122
122
 
123
123
 
124
124
  class Action(StrEnum):
@@ -52,7 +52,7 @@ class VaultSecret(BaseModel):
52
52
  class SecretHelper:
53
53
  @staticmethod
54
54
  def get_comparable_secret(resource: OpenshiftResource) -> OpenshiftResource:
55
- metadata = {k: v for k, v in resource.body["metadata"].items()}
55
+ metadata = dict(resource.body["metadata"].items())
56
56
  metadata["annotations"] = {
57
57
  k: v
58
58
  for k, v in metadata.get("annotations", {}).items()
@@ -177,7 +177,7 @@ class SecretsReconciler:
177
177
  """
178
178
  self._populate_secret_data(specs)
179
179
 
180
- to_sync_specs = [spec for spec in self._specs_with_secret(specs)]
180
+ to_sync_specs = list(self._specs_with_secret(specs))
181
181
  ocmap = self._init_ocmap(to_sync_specs)
182
182
 
183
183
  for spec in to_sync_specs:
@@ -235,7 +235,7 @@ class ExternalResourcesStateDynamoDB:
235
235
  return partials
236
236
 
237
237
  def get_all_resource_keys(self) -> set[ExternalResourceKey]:
238
- return {k for k in self.partial_resources.keys()}
238
+ return set(self.partial_resources)
239
239
 
240
240
  def get_keys_by_status(
241
241
  self, resource_status: ResourceStatus
reconcile/gcr_mirror.py CHANGED
@@ -124,12 +124,8 @@ class QuayMirror:
124
124
  @staticmethod
125
125
  def sync_tag(tags, tags_exclude, candidate):
126
126
  if tags is not None:
127
- for tag in tags:
128
- if re.match(tag, candidate):
129
- return True
130
- # When tags is defined, we don't look at
131
- # tags_exclude
132
- return False
127
+ # When tags is defined, we don't look at tags_exclude
128
+ return any(re.match(tag, candidate) for tag in tags)
133
129
 
134
130
  if tags_exclude is not None:
135
131
  for tag_exclude in tags_exclude:
@@ -277,10 +277,10 @@ def run(
277
277
  ) -> None:
278
278
  gql_api = gql.get_api()
279
279
  boards = get_jira_boards(query_func=gql_api.query)
280
- runner_params: RunnerParams = dict(
281
- exit_on_permission_errors=exit_on_permission_errors,
282
- boards=boards,
283
- )
280
+ runner_params: RunnerParams = {
281
+ "exit_on_permission_errors": exit_on_permission_errors,
282
+ "boards": boards,
283
+ }
284
284
  if enable_extended_early_exit and get_feature_toggle_state(
285
285
  "jira-permissions-validator-extended-early-exit",
286
286
  default=True,
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import logging
2
3
  from collections.abc import (
3
4
  Callable,
@@ -142,7 +143,7 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
142
143
  def get_roles(self, query_func: Callable) -> list[RoleV1]:
143
144
  """Return the roles with ldap_group set."""
144
145
  data = roles_query(query_func, variables={})
145
- roles = [role for role in data.roles or []]
146
+ roles = list(data.roles or [])
146
147
  if duplicates := find_duplicates(
147
148
  role.ldap_group.name for role in roles if role.ldap_group
148
149
  ):
@@ -224,10 +225,8 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
224
225
  """Reach out to the internal groups API and fetch all managed groups."""
225
226
  groups = []
226
227
  for group_name in group_names:
227
- try:
228
+ with contextlib.suppress(NotFound):
228
229
  groups.append(internal_groups_client.group(group_name))
229
- except NotFound:
230
- pass
231
230
  return groups
232
231
 
233
232
  def reconcile(
@@ -263,10 +262,8 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
263
262
  for group_to_remove in diff_result.delete.values():
264
263
  logging.info(["delete_ldap_group", group_to_remove.name])
265
264
  if not dry_run:
266
- try:
265
+ with contextlib.suppress(NotFound):
267
266
  internal_groups_client.delete_group(group_to_remove.name)
268
- except NotFound:
269
- pass
270
267
  self._managed_groups.remove(group_to_remove.name)
271
268
 
272
269
  for diff_pair in diff_result.change.values():
@@ -36,6 +36,7 @@ class OcmInternalNotifications(QontractReconcileIntegration[NoParams]):
36
36
  self.slack = slackapi_from_queries(
37
37
  integration_name=self.name, init_usergroups=False
38
38
  )
39
+ self.slack_get_user_id_by_name = lru_cache()(self._slack_get_user_id_by_name)
39
40
 
40
41
  @property
41
42
  def name(self) -> str:
@@ -44,8 +45,7 @@ class OcmInternalNotifications(QontractReconcileIntegration[NoParams]):
44
45
  def get_environments(self, query_func: Callable) -> list[OCMEnvironment]:
45
46
  return ocm_environment_query(query_func).environments
46
47
 
47
- @lru_cache
48
- def slack_get_user_id_by_name(
48
+ def _slack_get_user_id_by_name(
49
49
  self, user_name: str, mail_address: str
50
50
  ) -> str | None:
51
51
  try:
@@ -850,7 +850,7 @@ def apply_action(
850
850
  resource=resource,
851
851
  wait_for_namespace=options.wait_for_namespace,
852
852
  recycle_pods=options.recycle_pods,
853
- privileged=True if options.privileged else False,
853
+ privileged=bool(options.privileged),
854
854
  )
855
855
 
856
856
  except StatusCodeError as e:
@@ -884,8 +884,8 @@ def delete_action(
884
884
  namespace=namespace,
885
885
  resource_type=resource_type,
886
886
  name=resource_name,
887
- enable_deletion=True if options.enable_deletion else False,
888
- privileged=True if options.privileged else False,
887
+ enable_deletion=bool(options.enable_deletion),
888
+ privileged=bool(options.privileged),
889
889
  )
890
890
  except StatusCodeError as e:
891
891
  ri.register_error()
@@ -938,9 +938,10 @@ def _realize_resource_data_3way_diff(
938
938
  logging.error(msg)
939
939
  return actions
940
940
 
941
- options.enable_deletion = False if ri.has_error_registered() else True
941
+ # don't delete resources if there are errors
942
+ options.enable_deletion = not ri.has_error_registered()
942
943
  # only allow to override enable_deletion if no errors were found
943
- if options.enable_deletion is True and options.override_enable_deletion is False:
944
+ if options.enable_deletion and options.override_enable_deletion is False:
944
945
  options.enable_deletion = False
945
946
 
946
947
  diff_result = differ.diff_mappings(
@@ -1359,8 +1360,9 @@ def aggregate_shared_resources_typed(
1359
1360
  case HasOpenshiftServiceAccountTokensAndSharedResources():
1360
1361
  shared_type_resources_items = []
1361
1362
  for ost_shared_resources_item in namespace.shared_resources:
1362
- if shared_type_resources := getattr(
1363
- ost_shared_resources_item, "openshift_service_account_tokens"
1363
+ if (
1364
+ shared_type_resources
1365
+ := ost_shared_resources_item.openshift_service_account_tokens
1364
1366
  ):
1365
1367
  shared_type_resources_items.extend(shared_type_resources)
1366
1368
  if namespace.openshift_service_account_tokens:
@@ -1372,8 +1374,9 @@ def aggregate_shared_resources_typed(
1372
1374
  case HasOpenShiftResourcesAndSharedResources():
1373
1375
  shared_type_resources_items = []
1374
1376
  for or_shared_resources_item in namespace.shared_resources:
1375
- if shared_type_resources := getattr(
1376
- or_shared_resources_item, "openshift_resources"
1377
+ if (
1378
+ shared_type_resources
1379
+ := or_shared_resources_item.openshift_resources
1377
1380
  ):
1378
1381
  shared_type_resources_items.extend(shared_type_resources)
1379
1382
  if namespace.openshift_resources:
@@ -1405,10 +1408,7 @@ def determine_user_keys_for_access(
1405
1408
  return ["github_username"]
1406
1409
 
1407
1410
  for auth in auth_list:
1408
- if isinstance(auth, HasService):
1409
- service = auth.service
1410
- else:
1411
- service = auth["service"]
1411
+ service = auth.service if isinstance(auth, HasService) else auth["service"]
1412
1412
  try:
1413
1413
  if AUTH_METHOD_USER_KEY[service] in user_keys:
1414
1414
  continue
@@ -1416,7 +1416,7 @@ def determine_user_keys_for_access(
1416
1416
  except KeyError:
1417
1417
  raise NotImplementedError(
1418
1418
  f"[{cluster_name}] auth service not implemented: {service}"
1419
- )
1419
+ ) from None
1420
1420
  return user_keys
1421
1421
 
1422
1422
 
@@ -208,7 +208,7 @@ def create_cluster_bots(
208
208
  mode="w+", encoding="locale", delete=True
209
209
  ) as kc:
210
210
  kc.write(kubeconfig_content)
211
- kc.flush
211
+ kc.flush()
212
212
  logging.info(
213
213
  f"[{cluster.name}] create {config.dedicated_admin_sa} service account"
214
214
  )
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import sys
2
3
 
3
4
  import reconcile.openshift_base as ob
@@ -118,7 +119,9 @@ def fetch_desired_state(ri, oc_map):
118
119
  oc_resource, resource_name = construct_user_oc_resource(
119
120
  permission["cluster_role"], username
120
121
  )
121
- try:
122
+ with contextlib.suppress(ResourceKeyExistsError):
123
+ # a user may have a Role assigned to them
124
+ # from multiple app-interface roles
122
125
  ri.add_desired(
123
126
  cluster,
124
127
  namespace_cluster_scope,
@@ -126,10 +129,7 @@ def fetch_desired_state(ri, oc_map):
126
129
  resource_name,
127
130
  oc_resource,
128
131
  )
129
- except ResourceKeyExistsError:
130
- # a user may have a Role assigned to them
131
- # from multiple app-interface roles
132
- pass
132
+
133
133
  for sa in service_accounts:
134
134
  if ri is None:
135
135
  continue
@@ -137,7 +137,10 @@ def fetch_desired_state(ri, oc_map):
137
137
  oc_resource, resource_name = construct_sa_oc_resource(
138
138
  permission["cluster_role"], namespace, sa_name
139
139
  )
140
- try:
140
+
141
+ with contextlib.suppress(ResourceKeyExistsError):
142
+ # a ServiceAccount may have a Role assigned to it
143
+ # from multiple app-interface roles
141
144
  ri.add_desired(
142
145
  cluster,
143
146
  namespace_cluster_scope,
@@ -145,10 +148,6 @@ def fetch_desired_state(ri, oc_map):
145
148
  resource_name,
146
149
  oc_resource,
147
150
  )
148
- except ResourceKeyExistsError:
149
- # a ServiceAccount may have a Role assigned to it
150
- # from multiple app-interface roles
151
- pass
152
151
 
153
152
  return users_desired_state
154
153
 
@@ -164,7 +164,7 @@ class LabelInventory:
164
164
  desired = types[DESIRED]
165
165
  managed = self.get(cluster, ns, MANAGED, [])
166
166
  current = self.get(cluster, ns, CURRENT, {})
167
- changed = self.setdefault(cluster, ns, CHANGED, {})
167
+ changed = self.setdefault(cluster, ns, CHANGED, {}) # noqa: B909
168
168
 
169
169
  # cleanup managed items
170
170
  for k in managed:
@@ -192,7 +192,7 @@ class LabelInventory:
192
192
  changed[k] = v
193
193
 
194
194
  # remove old labels
195
- for k, v in current.items():
195
+ for k, _ in current.items():
196
196
  if k in managed and k not in desired:
197
197
  changed[k] = None
198
198
 
@@ -127,7 +127,7 @@ def check_results(
127
127
  desired_state: Iterable[Mapping[str, str]], results: Iterable[Any]
128
128
  ) -> bool:
129
129
  err = False
130
- for s, e in zip(desired_state, results):
130
+ for s, e in zip(desired_state, results, strict=False):
131
131
  if isinstance(e, Exception):
132
132
  err = True
133
133
  msg = (
@@ -287,7 +287,7 @@ def check_alertmanager_config(
287
287
  f"error validating alertmanager config in {path}: "
288
288
  f"missing key {alertmanager_config_key}"
289
289
  )
290
- raise FetchResourceError(e_msg)
290
+ raise FetchResourceError(e_msg) from None
291
291
 
292
292
  if decode_base64:
293
293
  config = base64.b64decode(config).decode("utf-8")
@@ -329,10 +329,10 @@ def fetch_provider_resource(
329
329
  except TypeError:
330
330
  body_type = type(body).__name__
331
331
  e_msg = f"invalid resource type {body_type} found in path: {path}"
332
- raise FetchResourceError(e_msg)
332
+ raise FetchResourceError(e_msg) from None
333
333
  except anymarkup.AnyMarkupError:
334
334
  e_msg = f"Could not parse data. Skipping resource: {path}"
335
- raise FetchResourceError(e_msg)
335
+ raise FetchResourceError(e_msg) from None
336
336
 
337
337
  if validate_json:
338
338
  files = body["data"]
@@ -341,7 +341,7 @@ def fetch_provider_resource(
341
341
  json.loads(file_content)
342
342
  except ValueError:
343
343
  e_msg = f"invalid json in {path} under {file_name}"
344
- raise FetchResourceError(e_msg)
344
+ raise FetchResourceError(e_msg) from None
345
345
 
346
346
  if validate_alertmanager_config:
347
347
  if body["kind"] == "Secret":
@@ -383,7 +383,7 @@ def fetch_provider_resource(
383
383
  body, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION, error_details=path
384
384
  )
385
385
  except ConstructResourceError as e:
386
- raise FetchResourceError(str(e))
386
+ raise FetchResourceError(str(e)) from None
387
387
 
388
388
 
389
389
  def fetch_provider_vault_secret(
@@ -430,7 +430,7 @@ def fetch_provider_vault_secret(
430
430
  try:
431
431
  return OR(body, integration, integration_version, error_details=path)
432
432
  except ConstructResourceError as e:
433
- raise FetchResourceError(str(e))
433
+ raise FetchResourceError(str(e)) from None
434
434
 
435
435
 
436
436
  # check to ensure that all of the keys are valid by looking to see if there are
@@ -554,7 +554,7 @@ def fetch_openshift_resource(
554
554
  )
555
555
  except Exception as e:
556
556
  msg = f"could not render template at path {path}\n{e}"
557
- raise ResourceTemplateRenderError(msg)
557
+ raise ResourceTemplateRenderError(msg) from None
558
558
  elif provider == "vault-secret":
559
559
  path = resource["path"]
560
560
  version = resource["version"]
@@ -588,7 +588,7 @@ def fetch_openshift_resource(
588
588
  settings=settings,
589
589
  )
590
590
  except (SecretVersionNotFound, SecretVersionIsNone) as e:
591
- raise FetchSecretError(e)
591
+ raise FetchSecretError(e) from None
592
592
  elif provider == "route":
593
593
  path = resource["resource"]["path"]
594
594
  _locked_debug_log(f"Processing {provider}: {path}")
@@ -628,7 +628,7 @@ def fetch_openshift_resource(
628
628
  )
629
629
  except Exception as e:
630
630
  msg = f"could not render template at path {path}\n{e}"
631
- raise ResourceTemplateRenderError(msg)
631
+ raise ResourceTemplateRenderError(msg) from None
632
632
 
633
633
  else:
634
634
  raise UnknownProviderError(provider)
@@ -1,3 +1,4 @@
1
+ import contextlib
1
2
  import sys
2
3
 
3
4
  import reconcile.openshift_base as ob
@@ -136,7 +137,9 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
136
137
  oc_resource, resource_name = construct_user_oc_resource(
137
138
  permission["role"], username
138
139
  )
139
- try:
140
+ with contextlib.suppress(ResourceKeyExistsError):
141
+ # a user may have a Role assigned to them
142
+ # from multiple app-interface roles
140
143
  ri.add_desired(
141
144
  cluster,
142
145
  perm_namespace_name,
@@ -145,10 +148,7 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
145
148
  oc_resource,
146
149
  privileged=privileged,
147
150
  )
148
- except ResourceKeyExistsError:
149
- # a user may have a Role assigned to them
150
- # from multiple app-interface roles
151
- pass
151
+
152
152
  for sa in service_accounts:
153
153
  if ri is None:
154
154
  continue
@@ -156,7 +156,9 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
156
156
  oc_resource, resource_name = construct_sa_oc_resource(
157
157
  permission["role"], sa_namespace_name, sa_name
158
158
  )
159
- try:
159
+ with contextlib.suppress(ResourceKeyExistsError):
160
+ # a ServiceAccount may have a Role assigned to it
161
+ # from multiple app-interface roles
160
162
  ri.add_desired(
161
163
  cluster,
162
164
  perm_namespace_name,
@@ -165,11 +167,6 @@ def fetch_desired_state(ri, oc_map, enforced_user_keys=None):
165
167
  oc_resource,
166
168
  privileged=privileged,
167
169
  )
168
- except ResourceKeyExistsError:
169
- # a ServiceAccount may have a Role assigned to it
170
- # from multiple app-interface roles
171
- pass
172
-
173
170
  return users_desired_state
174
171
 
175
172
 
@@ -313,11 +313,14 @@ def _pipeline_exists(
313
313
  if isinstance(oc, OCLogMsg):
314
314
  logging.error(oc.message)
315
315
  raise RuntimeError(f"No OC client for {tkn_cluster_name}: {oc.message}")
316
- if oc.get(
317
- namespace=tkn_namespace_name, kind="Pipeline", name=name, allow_not_found=True
318
- ):
319
- return True
320
- return False
316
+ return bool(
317
+ oc.get(
318
+ namespace=tkn_namespace_name,
319
+ kind="Pipeline",
320
+ name=name,
321
+ allow_not_found=True,
322
+ )
323
+ )
321
324
 
322
325
 
323
326
  def _construct_tekton_trigger_resource(
reconcile/oum/base.py CHANGED
@@ -265,7 +265,7 @@ def reconcile_cluster_roles(
265
265
  }
266
266
  # only process roles present in the desired state and ignore the ones that are not
267
267
  # this way a role can still be managed manually while another one is managed by this integration
268
- for group in desired_groups.keys():
268
+ for group in desired_groups:
269
269
  desired_members = desired_groups.get(group, set())
270
270
  current_members = current_groups.get(group, set())
271
271