qontract-reconcile 0.10.2.dev14__py3-none-any.whl → 0.10.2.dev15__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 (133) hide show
  1. {qontract_reconcile-0.10.2.dev14.dist-info → qontract_reconcile-0.10.2.dev15.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.2.dev14.dist-info → qontract_reconcile-0.10.2.dev15.dist-info}/RECORD +133 -133
  3. reconcile/acs_rbac.py +2 -4
  4. reconcile/aus/base.py +13 -13
  5. reconcile/aws_ami_share.py +1 -2
  6. reconcile/aws_cloudwatch_log_retention/integration.py +1 -1
  7. reconcile/aws_saml_idp/integration.py +1 -1
  8. reconcile/aws_saml_roles/integration.py +1 -1
  9. reconcile/aws_version_sync/integration.py +3 -3
  10. reconcile/change_owners/change_owners.py +8 -5
  11. reconcile/change_owners/change_types.py +18 -18
  12. reconcile/change_owners/changes.py +8 -9
  13. reconcile/change_owners/decision.py +12 -15
  14. reconcile/change_owners/self_service_roles.py +6 -4
  15. reconcile/change_owners/tester.py +8 -10
  16. reconcile/cli.py +9 -11
  17. reconcile/closedbox_endpoint_monitoring_base.py +1 -1
  18. reconcile/cna/integration.py +2 -2
  19. reconcile/dashdotdb_base.py +2 -2
  20. reconcile/dashdotdb_cso.py +1 -1
  21. reconcile/dashdotdb_dora.py +6 -4
  22. reconcile/dashdotdb_slo.py +1 -1
  23. reconcile/database_access_manager.py +15 -19
  24. reconcile/email_sender.py +4 -8
  25. reconcile/external_resources/secrets_sync.py +2 -2
  26. reconcile/external_resources/state.py +17 -17
  27. reconcile/gabi_authorized_users.py +3 -3
  28. reconcile/gcr_mirror.py +2 -2
  29. reconcile/github_org.py +9 -13
  30. reconcile/gitlab_housekeeping.py +1 -1
  31. reconcile/gitlab_owners.py +10 -12
  32. reconcile/gitlab_permissions.py +5 -4
  33. reconcile/glitchtip/integration.py +14 -14
  34. reconcile/glitchtip_project_alerts/integration.py +3 -4
  35. reconcile/integrations_manager.py +1 -2
  36. reconcile/jenkins_job_builds_cleaner.py +7 -5
  37. reconcile/jenkins_roles.py +10 -6
  38. reconcile/jenkins_worker_fleets.py +5 -4
  39. reconcile/jira_permissions_validator.py +2 -6
  40. reconcile/ldap_groups/integration.py +3 -2
  41. reconcile/ocm_groups.py +5 -5
  42. reconcile/ocm_update_recommended_version.py +2 -2
  43. reconcile/openshift_base.py +15 -20
  44. reconcile/openshift_groups.py +9 -8
  45. reconcile/openshift_namespace_labels.py +3 -4
  46. reconcile/openshift_namespaces.py +1 -1
  47. reconcile/openshift_network_policies.py +1 -1
  48. reconcile/openshift_resources_base.py +4 -4
  49. reconcile/openshift_serviceaccount_tokens.py +1 -1
  50. reconcile/openshift_tekton_resources.py +1 -2
  51. reconcile/openshift_users.py +5 -4
  52. reconcile/prometheus_rules_tester/integration.py +8 -8
  53. reconcile/quay_mirror.py +3 -4
  54. reconcile/quay_mirror_org.py +1 -1
  55. reconcile/rhidp/ocm_oidc_idp/base.py +10 -15
  56. reconcile/run_integration.py +7 -7
  57. reconcile/saas_auto_promotions_manager/publisher.py +1 -1
  58. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +3 -9
  59. reconcile/service_dependencies.py +2 -7
  60. reconcile/skupper_network/reconciler.py +5 -5
  61. reconcile/skupper_network/site_controller.py +3 -3
  62. reconcile/sql_query.py +5 -5
  63. reconcile/status_board.py +24 -24
  64. reconcile/terraform_cloudflare_users.py +2 -2
  65. reconcile/terraform_repo.py +6 -6
  66. reconcile/terraform_users.py +8 -5
  67. reconcile/terraform_vpc_peerings.py +1 -1
  68. reconcile/terraform_vpc_resources/integration.py +1 -1
  69. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -1
  70. reconcile/typed_queries/app_quay_repos_escalation_policies.py +1 -1
  71. reconcile/typed_queries/aws_vpc_requests.py +1 -1
  72. reconcile/typed_queries/aws_vpcs.py +1 -1
  73. reconcile/typed_queries/clusters.py +1 -1
  74. reconcile/typed_queries/clusters_minimal.py +1 -1
  75. reconcile/typed_queries/clusters_with_dms.py +1 -1
  76. reconcile/typed_queries/dynatrace_environments.py +1 -1
  77. reconcile/typed_queries/dynatrace_token_provider_token_specs.py +1 -1
  78. reconcile/typed_queries/reserved_networks.py +1 -1
  79. reconcile/typed_queries/saas_files.py +1 -1
  80. reconcile/typed_queries/slo_documents.py +1 -1
  81. reconcile/typed_queries/status_board.py +1 -2
  82. reconcile/utils/amtool.py +2 -2
  83. reconcile/utils/aws_api.py +10 -10
  84. reconcile/utils/aws_helper.py +1 -1
  85. reconcile/utils/binary.py +1 -2
  86. reconcile/utils/differ.py +4 -7
  87. reconcile/utils/dnsutils.py +4 -12
  88. reconcile/utils/external_resources.py +1 -2
  89. reconcile/utils/gitlab_api.py +2 -4
  90. reconcile/utils/glitchtip/models.py +1 -1
  91. reconcile/utils/helm.py +1 -1
  92. reconcile/utils/instrumented_wrappers.py +2 -2
  93. reconcile/utils/jjb_client.py +1 -1
  94. reconcile/utils/jump_host.py +1 -1
  95. reconcile/utils/metrics.py +6 -11
  96. reconcile/utils/mr/aws_access.py +1 -1
  97. reconcile/utils/mr/base.py +2 -4
  98. reconcile/utils/mr/notificator.py +1 -1
  99. reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +1 -1
  100. reconcile/utils/oc.py +17 -31
  101. reconcile/utils/oc_map.py +1 -1
  102. reconcile/utils/ocm/base.py +4 -2
  103. reconcile/utils/ocm/search_filters.py +4 -3
  104. reconcile/utils/ocm/status_board.py +2 -2
  105. reconcile/utils/ocm/upgrades.py +4 -7
  106. reconcile/utils/ocm_base_client.py +1 -1
  107. reconcile/utils/openshift_resource.py +1 -1
  108. reconcile/utils/promtool.py +1 -1
  109. reconcile/utils/quay_api.py +1 -3
  110. reconcile/utils/raw_github_api.py +3 -10
  111. reconcile/utils/repo_owners.py +5 -5
  112. reconcile/utils/rest_api_base.py +1 -2
  113. reconcile/utils/rosa/rosa_cli.py +3 -3
  114. reconcile/utils/saasherder/saasherder.py +9 -15
  115. reconcile/utils/secret_reader.py +2 -2
  116. reconcile/utils/sharding.py +2 -2
  117. reconcile/utils/state.py +5 -5
  118. reconcile/utils/terraform_client.py +2 -2
  119. reconcile/utils/terrascript/cloudflare_resources.py +4 -6
  120. reconcile/utils/terrascript_aws_client.py +16 -28
  121. reconcile/utils/vault.py +2 -2
  122. reconcile/utils/vcs.py +8 -16
  123. reconcile/vault_replication.py +1 -8
  124. tools/app_interface_reporter.py +1 -1
  125. tools/cli_commands/container_images_report.py +1 -1
  126. tools/cli_commands/cost_report/view.py +4 -2
  127. tools/cli_commands/gpg_encrypt.py +1 -5
  128. tools/qontract_cli.py +14 -13
  129. tools/saas_metrics_exporter/commit_distance/channel.py +1 -1
  130. tools/saas_promotion_state/saas_promotion_state.py +1 -1
  131. tools/sd_app_sre_alert_report.py +3 -3
  132. {qontract_reconcile-0.10.2.dev14.dist-info → qontract_reconcile-0.10.2.dev15.dist-info}/WHEEL +0 -0
  133. {qontract_reconcile-0.10.2.dev14.dist-info → qontract_reconcile-0.10.2.dev15.dist-info}/entry_points.txt +0 -0
@@ -74,47 +74,47 @@ class DynamoDBStateAdapter:
74
74
  MODCONF_DRIFT_MINS = "drift_detection_minutes"
75
75
  MODCONF_TIMEOUT_MINS = "timeout_minutes"
76
76
 
77
- def _get_value(self, item: Mapping[str, Any], key: str, _type: str = "S") -> Any:
78
- return item[key][_type]
77
+ def _get_value(self, item: Mapping[str, Any], key: str, type: str = "S") -> Any:
78
+ return item[key][type]
79
79
 
80
80
  def deserialize(
81
81
  self,
82
82
  item: Mapping[str, Any],
83
83
  partial_data: bool = False,
84
84
  ) -> ExternalResourceState:
85
- _key = self._get_value(item, self.ER_KEY, _type="M")
85
+ key_ = self._get_value(item, self.ER_KEY, type="M")
86
86
  key = ExternalResourceKey(
87
- provision_provider=self._get_value(_key, self.ER_KEY_PROVISION_PROVIDER),
88
- provisioner_name=self._get_value(_key, self.ER_KEY_PROVISIONER_NAME),
89
- provider=self._get_value(_key, self.ER_KEY_PROVIDER),
90
- identifier=self._get_value(_key, self.ER_KEY_IDENTIFIER),
87
+ provision_provider=self._get_value(key_, self.ER_KEY_PROVISION_PROVIDER),
88
+ provisioner_name=self._get_value(key_, self.ER_KEY_PROVISIONER_NAME),
89
+ provider=self._get_value(key_, self.ER_KEY_PROVIDER),
90
+ identifier=self._get_value(key_, self.ER_KEY_IDENTIFIER),
91
91
  )
92
- _reconciliation = self._get_value(item, self.RECONC, _type="M")
92
+ reconciliation = self._get_value(item, self.RECONC, type="M")
93
93
 
94
94
  if partial_data:
95
95
  r = Reconciliation(
96
96
  key=key,
97
97
  resource_hash=self._get_value(
98
- _reconciliation, self.RECONC_RESOURCE_HASH
98
+ reconciliation, self.RECONC_RESOURCE_HASH
99
99
  ),
100
100
  )
101
101
  else:
102
- _modconf = self._get_value(_reconciliation, self.MODCONF, _type="M")
102
+ modconf = self._get_value(reconciliation, self.MODCONF, type="M")
103
103
  r = Reconciliation(
104
104
  key=key,
105
105
  resource_hash=self._get_value(
106
- _reconciliation, self.RECONC_RESOURCE_HASH
106
+ reconciliation, self.RECONC_RESOURCE_HASH
107
107
  ),
108
- input=self._get_value(_reconciliation, self.RECONC_INPUT),
109
- action=self._get_value(_reconciliation, self.RECONC_ACTION),
108
+ input=self._get_value(reconciliation, self.RECONC_INPUT),
109
+ action=self._get_value(reconciliation, self.RECONC_ACTION),
110
110
  module_configuration=ExternalResourceModuleConfiguration(
111
- image=self._get_value(_modconf, self.MODCONF_IMAGE),
112
- version=self._get_value(_modconf, self.MODCONF_VERSION),
111
+ image=self._get_value(modconf, self.MODCONF_IMAGE),
112
+ version=self._get_value(modconf, self.MODCONF_VERSION),
113
113
  reconcile_drift_interval_minutes=self._get_value(
114
- _modconf, self.MODCONF_DRIFT_MINS, _type="N"
114
+ modconf, self.MODCONF_DRIFT_MINS, type="N"
115
115
  ),
116
116
  reconcile_timeout_minutes=self._get_value(
117
- _modconf, self.MODCONF_TIMEOUT_MINS, _type="N"
117
+ modconf, self.MODCONF_TIMEOUT_MINS, type="N"
118
118
  ),
119
119
  ),
120
120
  )
@@ -67,7 +67,7 @@ def fetch_desired_state(
67
67
  expiration_date = datetime.strptime(g["expirationDate"], "%Y-%m-%d").date()
68
68
  if (expiration_date - date.today()).days > EXPIRATION_DAYS_MAX:
69
69
  raise RunnerException(
70
- f'The maximum expiration date of {g["name"]} shall not '
70
+ f"The maximum expiration date of {g['name']} shall not "
71
71
  f"exceed {EXPIRATION_DAYS_MAX} days from today"
72
72
  )
73
73
  for i in g["instances"]:
@@ -92,8 +92,8 @@ def fetch_desired_state(
92
92
  break
93
93
  if not found:
94
94
  raise RunnerException(
95
- f'[gabi:{g["name"]} (path: {g["path"]})] Could not find RDS identifier {identifier} '
96
- f'for account {account} in namespace {namespace["name"]}. '
95
+ f"[gabi:{g['name']} (path: {g['path']})] Could not find RDS identifier {identifier} "
96
+ f"for account {account} in namespace {namespace['name']}. "
97
97
  "If this is a removed read only instance, consider updating the identifier to the source replica."
98
98
  )
99
99
  users = get_usernames(g["users"], cluster)
reconcile/gcr_mirror.py CHANGED
@@ -147,7 +147,7 @@ class QuayMirror:
147
147
  for org, data in summary.items():
148
148
  for item in data:
149
149
  image = Image(
150
- f'{item["server_url"]}/{org}/{item["name"]}',
150
+ f"{item['server_url']}/{org}/{item['name']}",
151
151
  session=self.session,
152
152
  timeout=REQUEST_TIMEOUT,
153
153
  )
@@ -267,7 +267,7 @@ class QuayMirror:
267
267
  raw_data = self.secret_reader.read_all(push_secret)
268
268
  project = project_data["name"]
269
269
  token = base64.b64decode(raw_data["token"]).decode()
270
- creds[project] = f'{raw_data["user"]}:{token}'
270
+ creds[project] = f"{raw_data['user']}:{token}"
271
271
  return creds
272
272
 
273
273
 
reconcile/github_org.py CHANGED
@@ -120,7 +120,7 @@ def get_config(default=False):
120
120
  raise KeyError("default github org config not found")
121
121
  if len(found_defaults) > 1:
122
122
  raise KeyError(
123
- "multiple default github org configs found: " f"{found_defaults}"
123
+ f"multiple default github org configs found: {found_defaults}"
124
124
  )
125
125
 
126
126
  return config
@@ -206,15 +206,11 @@ def fetch_desired_state(infer_clusters=True):
206
206
  if not permissions:
207
207
  continue
208
208
 
209
- members = []
210
-
211
- for user in role["users"]:
212
- members.append(user["github_username"])
213
-
214
- for bot in role["bots"]:
215
- if "github_username" in bot:
216
- members.append(bot["github_username"])
217
- members = [m.lower() for m in members]
209
+ user_members = [user["github_username"] for user in role["users"]]
210
+ bot_members = [
211
+ bot["github_username"] for bot in role["bots"] if "github_username" in bot
212
+ ]
213
+ members = [m.lower() for m in user_members + bot_members]
218
214
 
219
215
  for permission in permissions:
220
216
  if permission["service"] == "github-org":
@@ -436,9 +432,9 @@ def run(dry_run):
436
432
  current_orgs = {item["params"]["org"] for item in current_state.dump()}
437
433
  desired_orgs = {item["params"]["org"] for item in desired_state.dump()}
438
434
 
439
- assert (
440
- current_orgs == desired_orgs
441
- ), f"Current orgs ({current_orgs}) don't match desired orgs ({desired_orgs})"
435
+ assert current_orgs == desired_orgs, (
436
+ f"Current orgs ({current_orgs}) don't match desired orgs ({desired_orgs})"
437
+ )
442
438
 
443
439
  # Calculate diff
444
440
  diff = current_state.diff(desired_state)
@@ -174,7 +174,7 @@ def clean_pipelines(
174
174
  gl_piplelines.get(p["id"]).cancel()
175
175
  except gitlab.exceptions.GitlabPipelineCancelError as err:
176
176
  logging.error(
177
- f'unable to cancel {p["web_url"]} - '
177
+ f"unable to cancel {p['web_url']} - "
178
178
  f"error message {err.error_message}"
179
179
  )
180
180
 
@@ -198,7 +198,7 @@ class MRApproval:
198
198
  markdown_report = ""
199
199
 
200
200
  closest_approvers = []
201
- for _, owners in report.items():
201
+ for owners in report.values():
202
202
  new_group = []
203
203
 
204
204
  if "closest_approvers" not in owners:
@@ -232,10 +232,10 @@ class MRApproval:
232
232
  )
233
233
 
234
234
  for group in sorted(closest_approvers):
235
- markdown_report += f'* {", ".join(group)}\n'
235
+ markdown_report += f"* {', '.join(group)}\n"
236
236
 
237
237
  approvers = set()
238
- for _, owners in report.items():
238
+ for owners in report.values():
239
239
  if "approvers" not in owners:
240
240
  continue
241
241
 
@@ -254,10 +254,10 @@ class MRApproval:
254
254
  "\nIn case of emergency, the override approvers "
255
255
  "(from parent directories) are:\n\n"
256
256
  )
257
- markdown_report += f'* {", ".join(sorted(approvers))}\n'
257
+ markdown_report += f"* {', '.join(sorted(approvers))}\n"
258
258
 
259
259
  closest_reviewers = set()
260
- for _, owners in report.items():
260
+ for owners in report.values():
261
261
  if "closest_reviewers" not in owners:
262
262
  continue
263
263
 
@@ -274,11 +274,11 @@ class MRApproval:
274
274
  closest_reviewers.add(closest_reviewer)
275
275
 
276
276
  if closest_reviewers:
277
- markdown_report += "\nRelevant reviewers (with no " "merge rights) are:\n\n"
278
- markdown_report += f'* {", ".join(sorted(closest_reviewers))}\n'
277
+ markdown_report += "\nRelevant reviewers (with no merge rights) are:\n\n"
278
+ markdown_report += f"* {', '.join(sorted(closest_reviewers))}\n"
279
279
 
280
280
  reviewers = set()
281
- for _, owners in report.items():
281
+ for owners in report.values():
282
282
  if "reviewers" not in owners:
283
283
  continue
284
284
 
@@ -303,7 +303,7 @@ class MRApproval:
303
303
  "merge rights) from parent "
304
304
  "directories are:\n\n"
305
305
  )
306
- markdown_report += f'* {", ".join(sorted(reviewers))}\n'
306
+ markdown_report += f"* {', '.join(sorted(reviewers))}\n"
307
307
 
308
308
  return markdown_report.rstrip()
309
309
 
@@ -328,9 +328,7 @@ def act(repo, dry_run, instance, settings, defer=None):
328
328
 
329
329
  if mr_approval.top_commit_created_at is None:
330
330
  _LOG.info([
331
- f"Project:{gitlab_cli.project.id} "
332
- f"Merge Request:{mr.iid} "
333
- f"- skipping"
331
+ f"Project:{gitlab_cli.project.id} Merge Request:{mr.iid} - skipping"
334
332
  ])
335
333
  continue
336
334
 
@@ -91,11 +91,12 @@ class GroupPermissionHandler:
91
91
  current_state: dict[str, GroupSpec],
92
92
  ) -> None:
93
93
  # gather list of app-interface managed repos
94
- managed_repos: set[str] = set()
95
94
  instance = queries.get_gitlab_instance()
96
- for project_request in instance.get("projectRequests", []):
97
- for r in project_request.get("projects", []):
98
- managed_repos.add(f"{instance['url']}/{project_request['group']}/{r}")
95
+ managed_repos = {
96
+ f"{instance['url']}/{project_request['group']}/{r}"
97
+ for project_request in instance.get("projectRequests", [])
98
+ for r in project_request.get("projects", [])
99
+ }
99
100
 
100
101
  # get the diff data
101
102
  diff_data = diff_mappings(
@@ -97,7 +97,7 @@ def fetch_desired_state(
97
97
  project = Project(
98
98
  name=glitchtip_project.name,
99
99
  platform=glitchtip_project.platform,
100
- slug=glitchtip_project.project_id if glitchtip_project.project_id else "",
100
+ slug=glitchtip_project.project_id or "",
101
101
  event_throttle_rate=glitchtip_project.event_throttle_rate or 0,
102
102
  )
103
103
  # Check project is unique within an organization
@@ -108,24 +108,24 @@ def fetch_desired_state(
108
108
 
109
109
  # Get users via roles
110
110
  for role in glitchtip_team.roles:
111
- for role_user in role.users:
112
- users.append(
113
- User(
114
- email=f"{role_user.org_username}@{mail_domain}",
115
- role=get_user_role(organization, role),
116
- )
111
+ users.extend(
112
+ User(
113
+ email=f"{role_user.org_username}@{mail_domain}",
114
+ role=get_user_role(organization, role),
117
115
  )
116
+ for role_user in role.users
117
+ )
118
118
 
119
119
  # Get users via ldap
120
120
  for ldap_group in glitchtip_team.ldap_groups or []:
121
- for member in internal_groups_client.group(ldap_group).members:
122
- users.append(
123
- User(
124
- email=f"{member.id}@{mail_domain}",
125
- role=glitchtip_team.members_organization_role
126
- or DEFAULT_MEMBER_ROLE,
127
- )
121
+ users.extend(
122
+ User(
123
+ email=f"{member.id}@{mail_domain}",
124
+ role=glitchtip_team.members_organization_role
125
+ or DEFAULT_MEMBER_ROLE,
128
126
  )
127
+ for member in internal_groups_client.group(ldap_group).members
128
+ )
129
129
 
130
130
  # set(users) will take the first occurrence of a user, so the users from roles will be preferred
131
131
  team = Team(name=glitchtip_team.name, users=set(users))
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import operator
2
3
  from collections import defaultdict
3
4
  from collections.abc import (
4
5
  Callable,
@@ -192,9 +193,7 @@ class GlitchtipProjectAlertsIntegration(
192
193
  project = Project(
193
194
  name=glitchtip_project.name,
194
195
  platform=None,
195
- slug=glitchtip_project.project_id
196
- if glitchtip_project.project_id
197
- else "",
196
+ slug=glitchtip_project.project_id or "",
198
197
  alerts=alerts,
199
198
  )
200
199
 
@@ -238,7 +237,7 @@ class GlitchtipProjectAlertsIntegration(
238
237
  current_project.alerts,
239
238
  desired_project.alerts,
240
239
  key=lambda g: g.name,
241
- equal=lambda g1, g2: g1 == g2,
240
+ equal=operator.eq,
242
241
  )
243
242
 
244
243
  for alert_to_add in diff_result.add.values():
@@ -59,8 +59,7 @@ INTEGRATION_UPSTREAM_REPOS_PARAM = "INTEGRATION_UPSTREAM_REPOS"
59
59
 
60
60
  def get_image_tag_from_ref(ref: str, upstream: str) -> str:
61
61
  gh_prefix = "https://github.com/"
62
- if upstream.startswith(gh_prefix):
63
- upstream = upstream[len(gh_prefix) :]
62
+ upstream = upstream.removeprefix(gh_prefix)
64
63
  settings = queries.get_app_interface_settings()
65
64
  gh_token = get_default_config()["token"]
66
65
  github = Github(gh_token, base_url=GH_BASE_URL)
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import operator
2
3
  import re
3
4
  import time
4
5
 
@@ -36,7 +37,7 @@ def delete_builds(jenkins, builds_todel, dry_run=True):
36
37
 
37
38
  def get_last_build_ids(builds):
38
39
  builds_to_keep = []
39
- sorted_builds = sorted(builds, key=lambda b: b["timestamp"], reverse=True)
40
+ sorted_builds = sorted(builds, key=operator.itemgetter("timestamp"), reverse=True)
40
41
  if sorted_builds:
41
42
  last_build = sorted_builds[0]
42
43
  builds_to_keep.append(last_build["id"])
@@ -88,14 +89,15 @@ def run(dry_run):
88
89
  continue
89
90
 
90
91
  # Process cleanup rules, pre-compile as regexes
91
- cleanup_rules = []
92
- for rule in instance_cleanup_rules:
93
- cleanup_rules.append({
92
+ cleanup_rules = [
93
+ {
94
94
  "name": rule["name"],
95
95
  "name_re": re.compile(rule["name"]),
96
96
  "keep_hours": rule["keep_hours"],
97
97
  "keep_ms": hours_to_ms(rule["keep_hours"]),
98
- })
98
+ }
99
+ for rule in instance_cleanup_rules
100
+ ]
99
101
 
100
102
  token = instance["token"]
101
103
  instance_name = instance["name"]
@@ -85,12 +85,14 @@ def get_current_state(jenkins_map):
85
85
  if role_name == "anonymous":
86
86
  continue
87
87
 
88
- for user in users:
89
- current_state.append({
88
+ current_state.extend(
89
+ {
90
90
  "instance": instance,
91
91
  "role": role_name,
92
92
  "user": user,
93
- })
93
+ }
94
+ for user in users
95
+ )
94
96
 
95
97
  return current_state
96
98
 
@@ -105,12 +107,14 @@ def get_desired_state():
105
107
  if p["service"] != "jenkins-role":
106
108
  continue
107
109
 
108
- for u in r["users"]:
109
- desired_state.append({
110
+ desired_state.extend(
111
+ {
110
112
  "instance": p["instance"]["name"],
111
113
  "role": p["role"],
112
114
  "user": u["org_username"],
113
- })
115
+ }
116
+ for u in r["users"]
117
+ )
114
118
  for u in r["bots"]:
115
119
  if u["org_username"] is None:
116
120
  continue
@@ -71,7 +71,7 @@ def get_desired_state(
71
71
  if not found:
72
72
  raise ValueError(
73
73
  f"Could not find asg identifier {identifier} "
74
- f'for account {account} in namespace {namespace["name"]}'
74
+ f"for account {account} in namespace {namespace['name']}"
75
75
  )
76
76
  return desired_state
77
77
 
@@ -105,9 +105,10 @@ def act(
105
105
  logging.info(["update_jenkins_worker_fleet", instance_name, fleet.name])
106
106
 
107
107
  if not dry_run:
108
- d_clouds = []
109
- for d in desired_state:
110
- d_clouds.append({"eC2Fleet": d.dict(by_alias=True, exclude_none=True)})
108
+ d_clouds = [
109
+ {"eC2Fleet": d.dict(by_alias=True, exclude_none=True)}
110
+ for d in desired_state
111
+ ]
111
112
  config = {"jenkins": {"clouds": d_clouds}}
112
113
  jenkins.apply_jcasc_config(config)
113
114
 
@@ -107,7 +107,7 @@ def board_is_valid(
107
107
  )
108
108
  error |= ValidationError.INVALID_COMPONENT
109
109
 
110
- issue_type = board.issue_type if board.issue_type else default_issue_type
110
+ issue_type = board.issue_type or default_issue_type
111
111
  project_issue_types = jira.project_issue_types()
112
112
  project_issue_types_str = [i.name for i in project_issue_types]
113
113
  if issue_type not in project_issue_types_str:
@@ -128,11 +128,7 @@ def board_is_valid(
128
128
  )
129
129
  error |= ValidationError.INVALID_ISSUE_TYPE
130
130
 
131
- reopen_state = (
132
- board.issue_reopen_state
133
- if board.issue_reopen_state
134
- else default_reopen_state
135
- )
131
+ reopen_state = board.issue_reopen_state or default_reopen_state
136
132
  if reopen_state.lower() not in [t.lower() for t in available_states]:
137
133
  logging.error(
138
134
  f"[{board.name}] '{reopen_state}' is not a valid state in project. Valid states: {available_states}"
@@ -1,5 +1,6 @@
1
1
  import contextlib
2
2
  import logging
3
+ import operator
3
4
  from collections.abc import (
4
5
  Callable,
5
6
  Iterable,
@@ -86,7 +87,7 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
86
87
  owner = Entity(
87
88
  type=EntityType.SERVICE_ACCOUNT,
88
89
  # OIDC service accounts are named service-account-<client_id>
89
- id=f'service-account-{secret["client_id"]}',
90
+ id=f"service-account-{secret['client_id']}",
90
91
  )
91
92
  desired_groups_for_roles = self.get_desired_groups_for_roles(
92
93
  roles,
@@ -241,7 +242,7 @@ class LdapGroupsIntegration(QontractReconcileIntegration[LdapGroupsIntegrationPa
241
242
  current_groups,
242
243
  desired_groups,
243
244
  key=lambda g: g.name,
244
- equal=lambda g1, g2: g1 == g2,
245
+ equal=operator.eq,
245
246
  )
246
247
  # Internal Groups API does not support listing all managed groups, therefore
247
248
  # we need to keep track of them ourselves.
reconcile/ocm_groups.py CHANGED
@@ -19,16 +19,16 @@ QONTRACT_INTEGRATION = "ocm-groups"
19
19
 
20
20
 
21
21
  def get_cluster_state(group_items, ocm_map):
22
- results = []
23
22
  cluster = group_items["cluster"]
24
23
  ocm = ocm_map.get(cluster)
25
24
  group_name = group_items["group_name"]
26
25
  group = ocm.get_group_if_exists(cluster, group_name)
27
26
  if group is None:
28
- return results
29
- for user in group["users"] or []:
30
- results.append({"cluster": cluster, "group": group_name, "user": user})
31
- return results
27
+ return []
28
+ return [
29
+ {"cluster": cluster, "group": group_name, "user": user}
30
+ for user in group["users"] or []
31
+ ]
32
32
 
33
33
 
34
34
  def fetch_current_state(clusters, thread_pool_size):
@@ -19,8 +19,8 @@ QONTRACT_INTEGRATION = "ocm-update-recommended-version"
19
19
 
20
20
  def get_highest(version_set: set[str]) -> str:
21
21
  def _compare(v1: str, v2: str) -> int:
22
- _v1 = semver.VersionInfo.parse(v1)
23
- return _v1.compare(v2)
22
+ v1_ = semver.VersionInfo.parse(v1)
23
+ return v1_.compare(v2)
24
24
 
25
25
  sorted_version_set = sorted(
26
26
  version_set, key=functools.cmp_to_key(_compare), reverse=True
@@ -220,17 +220,17 @@ def init_specs_to_fetch(
220
220
 
221
221
  # Initialize desired state specs
222
222
  openshift_resources = namespace_info.get("openshiftResources")
223
- for openshift_resource in openshift_resources or []:
224
- state_specs.append(
225
- DesiredStateSpec(
226
- oc=oc,
227
- cluster=cluster,
228
- namespace=namespace,
229
- resource=openshift_resource,
230
- parent=namespace_info,
231
- privileged=privileged,
232
- )
223
+ state_specs.extend(
224
+ DesiredStateSpec(
225
+ oc=oc,
226
+ cluster=cluster,
227
+ namespace=namespace,
228
+ resource=openshift_resource,
229
+ parent=namespace_info,
230
+ privileged=privileged,
233
231
  )
232
+ for openshift_resource in openshift_resources or []
233
+ )
234
234
 
235
235
  elif clusters:
236
236
  # set namespace to something indicative
@@ -488,7 +488,7 @@ def apply(
488
488
  obsolete_rs["metadata"]["ownerReferences"] = owner_references
489
489
  oc.apply(namespace=namespace, resource=OR(obsolete_rs, "", ""))
490
490
  except (MayNotChangeOnceSetError, PrimaryClusterIPCanNotBeUnsetError):
491
- if resource_type not in {"Service"}:
491
+ if resource_type != "Service":
492
492
  raise
493
493
 
494
494
  oc.delete(namespace=namespace, kind=resource_type, name=resource.name)
@@ -882,10 +882,7 @@ def apply_action(
882
882
  if resource_type != "Secret"
883
883
  else f"error applying Secret {resource.name}: REDACTED"
884
884
  )
885
- msg = (
886
- f"[{cluster}/{namespace}] {err} "
887
- f"(error details: {resource.error_details})"
888
- )
885
+ msg = f"[{cluster}/{namespace}] {err} (error details: {resource.error_details})"
889
886
  logging.error(msg)
890
887
 
891
888
 
@@ -956,7 +953,7 @@ def _realize_resource_data_3way_diff(
956
953
  actions: list[dict] = []
957
954
 
958
955
  if ri.has_error_registered(cluster=cluster):
959
- msg = f"[{cluster}] skipping realize_data for " "cluster with errors"
956
+ msg = f"[{cluster}] skipping realize_data for cluster with errors"
960
957
  logging.error(msg)
961
958
  return actions
962
959
 
@@ -1212,8 +1209,7 @@ def validate_realized_data(actions: Iterable[dict[str, str]], oc_map: ClusterMap
1212
1209
  state = status.get("state")
1213
1210
  if state != "AtLatestKnown":
1214
1211
  logging.info(
1215
- f"Subscription {name} state is invalid. "
1216
- f"Current state: {state}"
1212
+ f"Subscription {name} state is invalid. Current state: {state}"
1217
1213
  )
1218
1214
  raise ValidationError(name)
1219
1215
  elif kind == "Job":
@@ -1311,8 +1307,7 @@ def aggregate_shared_resources(namespace_info, shared_resources_type):
1311
1307
  ]
1312
1308
  if shared_resources_type not in supported_shared_resources_types:
1313
1309
  raise KeyError(
1314
- f"shared_resource_type must be one of "
1315
- f"{supported_shared_resources_types}."
1310
+ f"shared_resource_type must be one of {supported_shared_resources_types}."
1316
1311
  )
1317
1312
  shared_resources = namespace_info.get("sharedResources")
1318
1313
  namespace_type_resources = namespace_info.get(shared_resources_type)
@@ -41,12 +41,11 @@ QONTRACT_INTEGRATION = "openshift-groups"
41
41
  def get_cluster_state(
42
42
  group_items: Mapping[str, str], oc_map: ClusterMap
43
43
  ) -> list[dict[str, str]]:
44
- results: list[dict[str, str]] = []
45
44
  cluster = group_items["cluster"]
46
45
  oc = oc_map.get(cluster)
47
46
  if isinstance(oc, OCLogMsg):
48
47
  logging.log(level=oc.log_level, msg=oc.message)
49
- return results
48
+ return []
50
49
  group_name = group_items["group_name"]
51
50
  try:
52
51
  group = oc.get_group_if_exists(group_name)
@@ -55,10 +54,11 @@ def get_cluster_state(
55
54
  logging.error(msg)
56
55
  raise e
57
56
  if group is None:
58
- return results
59
- for user in group["users"] or []:
60
- results.append({"cluster": cluster, "group": group_name, "user": user})
61
- return results
57
+ return []
58
+ return [
59
+ {"cluster": cluster, "group": group_name, "user": user}
60
+ for user in group["users"] or []
61
+ ]
62
62
 
63
63
 
64
64
  def create_groups_list(
@@ -74,8 +74,9 @@ def create_groups_list(
74
74
  if isinstance(oc, OCLogMsg):
75
75
  logging.log(level=oc.log_level, msg=oc.message)
76
76
  groups = cluster_info["managedGroups"] or []
77
- for group_name in groups:
78
- groups_list.append({"cluster": cluster, "group_name": group_name})
77
+ groups_list.extend(
78
+ {"cluster": cluster, "group_name": group_name} for group_name in groups
79
+ )
79
80
  return groups_list
80
81
 
81
82