qontract-reconcile 0.10.1rc883__py3-none-any.whl → 0.10.1rc885__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 (276) hide show
  1. {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/RECORD +276 -276
  3. reconcile/acs_rbac.py +1 -2
  4. reconcile/aus/advanced_upgrade_service.py +14 -14
  5. reconcile/aus/aus_label_source.py +1 -2
  6. reconcile/aus/base.py +23 -26
  7. reconcile/aus/cluster_version_data.py +4 -4
  8. reconcile/aus/models.py +2 -3
  9. reconcile/aus/version_gate_approver.py +2 -6
  10. reconcile/aus/version_gates/__init__.py +1 -3
  11. reconcile/aus/version_gates/sts_version_gate_handler.py +2 -3
  12. reconcile/aws_account_manager/integration.py +2 -2
  13. reconcile/aws_ami_cleanup/integration.py +3 -4
  14. reconcile/aws_iam_password_reset.py +2 -5
  15. reconcile/aws_version_sync/integration.py +2 -2
  16. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  17. reconcile/change_owners/approver.py +4 -5
  18. reconcile/change_owners/bundle.py +20 -22
  19. reconcile/change_owners/change_types.py +23 -24
  20. reconcile/change_owners/changes.py +13 -16
  21. reconcile/change_owners/decision.py +2 -5
  22. reconcile/change_owners/diff.py +11 -15
  23. reconcile/change_owners/self_service_roles.py +1 -2
  24. reconcile/change_owners/tester.py +7 -10
  25. reconcile/checkpoint.py +2 -5
  26. reconcile/cli.py +9 -12
  27. reconcile/closedbox_endpoint_monitoring_base.py +8 -11
  28. reconcile/cluster_deployment_mapper.py +2 -5
  29. reconcile/cna/assets/asset.py +4 -7
  30. reconcile/cna/assets/null.py +2 -5
  31. reconcile/cna/integration.py +2 -3
  32. reconcile/cna/state.py +2 -5
  33. reconcile/dashdotdb_base.py +8 -11
  34. reconcile/dashdotdb_cso.py +3 -6
  35. reconcile/dashdotdb_dora.py +10 -14
  36. reconcile/dashdotdb_dvo.py +10 -13
  37. reconcile/dashdotdb_slo.py +5 -8
  38. reconcile/database_access_manager.py +5 -6
  39. reconcile/dynatrace_token_provider/integration.py +2 -5
  40. reconcile/external_resources/integration.py +1 -1
  41. reconcile/external_resources/manager.py +4 -4
  42. reconcile/external_resources/model.py +3 -3
  43. reconcile/external_resources/secrets_sync.py +5 -5
  44. reconcile/external_resources/state.py +5 -5
  45. reconcile/gabi_authorized_users.py +3 -6
  46. reconcile/gcr_mirror.py +1 -1
  47. reconcile/github_org.py +1 -3
  48. reconcile/github_repo_invites.py +2 -5
  49. reconcile/gitlab_housekeeping.py +7 -11
  50. reconcile/gitlab_labeler.py +1 -2
  51. reconcile/gitlab_members.py +2 -5
  52. reconcile/gitlab_permissions.py +1 -3
  53. reconcile/glitchtip/integration.py +2 -5
  54. reconcile/glitchtip_project_alerts/integration.py +3 -6
  55. reconcile/glitchtip_project_dsn/integration.py +4 -7
  56. reconcile/integrations_manager.py +5 -8
  57. reconcile/jenkins/types.py +5 -6
  58. reconcile/jenkins_job_builder.py +9 -12
  59. reconcile/jenkins_roles.py +1 -1
  60. reconcile/jira_watcher.py +2 -2
  61. reconcile/ldap_groups/integration.py +2 -5
  62. reconcile/ocm/types.py +21 -26
  63. reconcile/ocm_addons_upgrade_tests_trigger.py +3 -6
  64. reconcile/ocm_clusters.py +8 -8
  65. reconcile/ocm_internal_notifications/integration.py +1 -2
  66. reconcile/ocm_labels/integration.py +2 -5
  67. reconcile/ocm_machine_pools.py +11 -15
  68. reconcile/ocm_upgrade_scheduler_org_updater.py +2 -5
  69. reconcile/openshift_base.py +27 -29
  70. reconcile/openshift_groups.py +15 -20
  71. reconcile/openshift_namespace_labels.py +8 -14
  72. reconcile/openshift_namespaces.py +5 -8
  73. reconcile/openshift_network_policies.py +2 -4
  74. reconcile/openshift_resources_base.py +19 -29
  75. reconcile/openshift_saas_deploy.py +9 -10
  76. reconcile/openshift_saas_deploy_change_tester.py +7 -10
  77. reconcile/openshift_saas_deploy_trigger_base.py +4 -7
  78. reconcile/openshift_saas_deploy_trigger_cleaner.py +5 -8
  79. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  80. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  81. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  82. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  83. reconcile/openshift_tekton_resources.py +7 -11
  84. reconcile/openshift_upgrade_watcher.py +10 -13
  85. reconcile/openshift_users.py +8 -11
  86. reconcile/oum/base.py +3 -4
  87. reconcile/oum/labelset.py +1 -2
  88. reconcile/oum/metrics.py +2 -2
  89. reconcile/oum/models.py +1 -2
  90. reconcile/oum/standalone.py +2 -3
  91. reconcile/prometheus_rules_tester/integration.py +6 -9
  92. reconcile/quay_membership.py +1 -2
  93. reconcile/quay_mirror.py +12 -13
  94. reconcile/quay_mirror_org.py +10 -10
  95. reconcile/queries.py +4 -7
  96. reconcile/resource_scraper.py +3 -4
  97. reconcile/rhidp/common.py +2 -2
  98. reconcile/saas_auto_promotions_manager/integration.py +5 -6
  99. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +1 -2
  100. reconcile/saas_auto_promotions_manager/publisher.py +5 -6
  101. reconcile/saas_auto_promotions_manager/subscriber.py +3 -4
  102. reconcile/saas_file_validator.py +2 -5
  103. reconcile/signalfx_endpoint_monitoring.py +2 -5
  104. reconcile/skupper_network/integration.py +3 -6
  105. reconcile/skupper_network/models.py +3 -5
  106. reconcile/slack_base.py +4 -7
  107. reconcile/slack_usergroups.py +15 -17
  108. reconcile/sql_query.py +5 -9
  109. reconcile/status_board.py +4 -5
  110. reconcile/statuspage/atlassian.py +14 -15
  111. reconcile/statuspage/integrations/maintenances.py +3 -3
  112. reconcile/statuspage/page.py +8 -8
  113. reconcile/statuspage/state.py +4 -5
  114. reconcile/statuspage/status.py +7 -8
  115. reconcile/templating/lib/rendering.py +8 -8
  116. reconcile/templating/renderer.py +10 -11
  117. reconcile/templating/validator.py +4 -4
  118. reconcile/terraform_aws_route53.py +3 -6
  119. reconcile/terraform_cloudflare_dns.py +9 -12
  120. reconcile/terraform_cloudflare_resources.py +9 -11
  121. reconcile/terraform_cloudflare_users.py +8 -11
  122. reconcile/terraform_init/integration.py +2 -2
  123. reconcile/terraform_repo.py +11 -14
  124. reconcile/terraform_resources.py +20 -21
  125. reconcile/terraform_tgw_attachments.py +32 -36
  126. reconcile/terraform_users.py +6 -7
  127. reconcile/terraform_vpc_resources/integration.py +6 -6
  128. reconcile/test/conftest.py +7 -10
  129. reconcile/test/fixtures.py +1 -1
  130. reconcile/test/saas_auto_promotions_manager/conftest.py +2 -2
  131. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
  132. reconcile/test/test_database_access_manager.py +3 -6
  133. reconcile/test/test_gitlab_labeler.py +2 -5
  134. reconcile/test/test_jump_host.py +5 -8
  135. reconcile/test/test_ocm_machine_pools.py +1 -4
  136. reconcile/test/test_openshift_base.py +3 -6
  137. reconcile/test/test_openshift_cluster_bots.py +5 -5
  138. reconcile/test/test_openshift_namespace_labels.py +2 -3
  139. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +2 -2
  140. reconcile/test/test_saasherder.py +9 -12
  141. reconcile/test/test_slack_base.py +4 -6
  142. reconcile/test/test_status_board.py +4 -7
  143. reconcile/test/test_terraform_tgw_attachments.py +14 -20
  144. reconcile/typed_queries/alerting_services_settings.py +1 -2
  145. reconcile/typed_queries/app_interface_custom_messages.py +2 -3
  146. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -3
  147. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  148. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  149. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  150. reconcile/typed_queries/aws_vpc_requests.py +1 -3
  151. reconcile/typed_queries/aws_vpcs.py +1 -3
  152. reconcile/typed_queries/clusters.py +2 -4
  153. reconcile/typed_queries/clusters_minimal.py +1 -3
  154. reconcile/typed_queries/clusters_with_dms.py +1 -3
  155. reconcile/typed_queries/external_resources.py +3 -4
  156. reconcile/typed_queries/pagerduty_instances.py +1 -2
  157. reconcile/typed_queries/repos.py +2 -3
  158. reconcile/typed_queries/reserved_networks.py +1 -3
  159. reconcile/typed_queries/saas_files.py +49 -59
  160. reconcile/typed_queries/slo_documents.py +1 -3
  161. reconcile/typed_queries/status_board.py +3 -7
  162. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  163. reconcile/typed_queries/terraform_namespaces.py +1 -2
  164. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +1 -3
  165. reconcile/utils/acs/base.py +2 -3
  166. reconcile/utils/acs/notifiers.py +3 -3
  167. reconcile/utils/acs/policies.py +3 -3
  168. reconcile/utils/aggregated_list.py +1 -1
  169. reconcile/utils/amtool.py +1 -2
  170. reconcile/utils/aws_api.py +28 -31
  171. reconcile/utils/binary.py +1 -3
  172. reconcile/utils/clusterhealth/providerbase.py +1 -2
  173. reconcile/utils/clusterhealth/telemeter.py +2 -2
  174. reconcile/utils/deadmanssnitch_api.py +1 -2
  175. reconcile/utils/disabled_integrations.py +4 -6
  176. reconcile/utils/environ.py +1 -1
  177. reconcile/utils/expiration.py +3 -7
  178. reconcile/utils/external_resource_spec.py +3 -4
  179. reconcile/utils/external_resources.py +4 -7
  180. reconcile/utils/filtering.py +1 -2
  181. reconcile/utils/git.py +3 -9
  182. reconcile/utils/git_secrets.py +5 -5
  183. reconcile/utils/github_api.py +5 -9
  184. reconcile/utils/gitlab_api.py +2 -3
  185. reconcile/utils/glitchtip/client.py +2 -4
  186. reconcile/utils/glitchtip/models.py +8 -11
  187. reconcile/utils/gql.py +26 -35
  188. reconcile/utils/grouping.py +1 -3
  189. reconcile/utils/imap_client.py +2 -5
  190. reconcile/utils/internal_groups/client.py +1 -2
  191. reconcile/utils/internal_groups/models.py +8 -9
  192. reconcile/utils/jenkins_api.py +4 -4
  193. reconcile/utils/jinja2/extensions.py +1 -1
  194. reconcile/utils/jinja2/filters.py +4 -4
  195. reconcile/utils/jinja2/utils.py +16 -16
  196. reconcile/utils/jira_client.py +10 -11
  197. reconcile/utils/jjb_client.py +14 -17
  198. reconcile/utils/jobcontroller/controller.py +5 -5
  199. reconcile/utils/jobcontroller/models.py +2 -2
  200. reconcile/utils/jsonpath.py +4 -5
  201. reconcile/utils/jump_host.py +7 -8
  202. reconcile/utils/keycloak.py +3 -7
  203. reconcile/utils/ldap_client.py +2 -3
  204. reconcile/utils/lean_terraform_client.py +13 -17
  205. reconcile/utils/membershipsources/app_interface_resolver.py +1 -1
  206. reconcile/utils/membershipsources/models.py +19 -22
  207. reconcile/utils/metrics.py +13 -15
  208. reconcile/utils/mr/base.py +7 -11
  209. reconcile/utils/mr/glitchtip_access_reporter.py +2 -2
  210. reconcile/utils/mr/notificator.py +1 -2
  211. reconcile/utils/oc.py +32 -38
  212. reconcile/utils/oc_connection_parameters.py +24 -25
  213. reconcile/utils/oc_filters.py +2 -3
  214. reconcile/utils/oc_map.py +9 -15
  215. reconcile/utils/ocm/addons.py +7 -10
  216. reconcile/utils/ocm/base.py +38 -39
  217. reconcile/utils/ocm/clusters.py +6 -9
  218. reconcile/utils/ocm/label_sources.py +1 -2
  219. reconcile/utils/ocm/labels.py +3 -6
  220. reconcile/utils/ocm/ocm.py +11 -14
  221. reconcile/utils/ocm/products.py +1 -3
  222. reconcile/utils/ocm/search_filters.py +16 -17
  223. reconcile/utils/ocm/service_log.py +2 -3
  224. reconcile/utils/ocm/sre_capability_labels.py +4 -8
  225. reconcile/utils/ocm/subscriptions.py +1 -3
  226. reconcile/utils/ocm/syncsets.py +2 -4
  227. reconcile/utils/ocm/upgrades.py +5 -9
  228. reconcile/utils/ocm_base_client.py +13 -16
  229. reconcile/utils/openshift_resource.py +5 -11
  230. reconcile/utils/output.py +2 -3
  231. reconcile/utils/pagerduty_api.py +4 -5
  232. reconcile/utils/prometheus.py +2 -2
  233. reconcile/utils/promotion_state.py +4 -5
  234. reconcile/utils/promtool.py +2 -8
  235. reconcile/utils/quay_api.py +12 -22
  236. reconcile/utils/raw_github_api.py +3 -5
  237. reconcile/utils/rosa/rosa_cli.py +6 -6
  238. reconcile/utils/rosa/session.py +6 -7
  239. reconcile/utils/runtime/desired_state_diff.py +3 -8
  240. reconcile/utils/runtime/environment.py +4 -7
  241. reconcile/utils/runtime/integration.py +4 -4
  242. reconcile/utils/runtime/meta.py +1 -2
  243. reconcile/utils/runtime/runner.py +7 -10
  244. reconcile/utils/runtime/sharding.py +22 -27
  245. reconcile/utils/saasherder/interfaces.py +63 -69
  246. reconcile/utils/saasherder/models.py +30 -35
  247. reconcile/utils/saasherder/saasherder.py +37 -53
  248. reconcile/utils/secret_reader.py +17 -19
  249. reconcile/utils/slack_api.py +15 -17
  250. reconcile/utils/smtp_client.py +1 -2
  251. reconcile/utils/sqs_gateway.py +1 -3
  252. reconcile/utils/state.py +1 -2
  253. reconcile/utils/terraform/config_client.py +4 -5
  254. reconcile/utils/terraform_client.py +12 -8
  255. reconcile/utils/terrascript/cloudflare_client.py +4 -10
  256. reconcile/utils/terrascript/cloudflare_resources.py +10 -13
  257. reconcile/utils/terrascript/models.py +2 -3
  258. reconcile/utils/terrascript/resources.py +1 -2
  259. reconcile/utils/terrascript_aws_client.py +30 -38
  260. reconcile/utils/unleash/client.py +4 -7
  261. reconcile/utils/unleash/server.py +2 -2
  262. reconcile/utils/vault.py +8 -11
  263. reconcile/utils/vaultsecretref.py +2 -3
  264. reconcile/utils/vcs.py +7 -8
  265. reconcile/vault_replication.py +4 -8
  266. reconcile/vpc_peerings_validator.py +4 -9
  267. release/version.py +6 -7
  268. tools/app_interface_reporter.py +2 -2
  269. tools/cli_commands/gpg_encrypt.py +3 -6
  270. tools/cli_commands/systems_and_tools.py +4 -7
  271. tools/qontract_cli.py +12 -17
  272. tools/template_validation.py +1 -1
  273. tools/test/conftest.py +3 -6
  274. {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/WHEEL +0 -0
  275. {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/entry_points.txt +0 -0
  276. {qontract_reconcile-0.10.1rc883.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
1
- from typing import NamedTuple, Optional, Protocol
1
+ from typing import NamedTuple, Protocol
2
2
 
3
3
  import requests
4
4
  from pydantic import BaseModel, Field
@@ -41,7 +41,7 @@ class PrometheusVector(BaseModel):
41
41
  def mandatory_label(self, label_name: str) -> str:
42
42
  return self.metric[label_name]
43
43
 
44
- def label(self, label_name: str, default: Optional[str] = None) -> Optional[str]:
44
+ def label(self, label_name: str, default: str | None = None) -> str | None:
45
45
  return self.metric.get(label_name, default)
46
46
 
47
47
 
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from collections import defaultdict
3
- from typing import Optional
4
3
 
5
4
  from pydantic import (
6
5
  BaseModel,
@@ -20,9 +19,9 @@ class PromotionData(BaseModel):
20
19
  """
21
20
 
22
21
  success: bool
23
- target_config_hash: Optional[str]
24
- saas_file: Optional[str]
25
- check_in: Optional[str]
22
+ target_config_hash: str | None
23
+ saas_file: str | None
24
+ check_in: str | None
26
25
 
27
26
  class Config:
28
27
  smart_union = True
@@ -71,7 +70,7 @@ class PromotionState:
71
70
  target_uid: str = "",
72
71
  pre_check_sha_exists: bool = True,
73
72
  use_cache: bool = False,
74
- ) -> Optional[PromotionData]:
73
+ ) -> PromotionData | None:
75
74
  """
76
75
  Fetch promotion data from S3.
77
76
 
@@ -2,11 +2,7 @@ import copy
2
2
  import os
3
3
  import subprocess
4
4
  import tempfile
5
- from typing import (
6
- Iterable,
7
- Mapping,
8
- MutableMapping,
9
- )
5
+ from collections.abc import Iterable, Mapping, MutableMapping
10
6
 
11
7
  import yaml
12
8
 
@@ -70,9 +66,7 @@ def _run_yaml_spec_cmd(cmd: list[str], yaml_spec: Mapping) -> CommandExecutionRe
70
66
  return CommandExecutionResult(False, f"Error creating temporary file: {e}")
71
67
 
72
68
  try:
73
- result = subprocess.run(
74
- cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True
75
- )
69
+ result = subprocess.run(cmd, capture_output=True, check=True)
76
70
  except subprocess.CalledProcessError as e:
77
71
  msg = f'Error running promtool command [{" ".join(cmd)}]'
78
72
  if e.stdout:
@@ -30,9 +30,7 @@ class QuayApi:
30
30
  if cache_members:
31
31
  return cache_members
32
32
 
33
- url = "{}/organization/{}/team/{}/members?includePending=true".format(
34
- self.api_url, self.organization, team
35
- )
33
+ url = f"{self.api_url}/organization/{self.organization}/team/{team}/members?includePending=true"
36
34
 
37
35
  r = requests.get(url, headers=self.auth_header, timeout=self._timeout)
38
36
  if r.status_code == 404:
@@ -57,7 +55,7 @@ class QuayApi:
57
55
  return members_list
58
56
 
59
57
  def user_exists(self, user):
60
- url = "{}/users/{}".format(self.api_url, user)
58
+ url = f"{self.api_url}/users/{user}"
61
59
  r = requests.get(url, headers=self.auth_header, timeout=self._timeout)
62
60
  if not r.ok:
63
61
  return False
@@ -68,22 +66,18 @@ class QuayApi:
68
66
 
69
67
  :raises HTTPError if there are any problems with the request
70
68
  """
71
- url_team = "{}/organization/{}/team/{}/members/{}".format(
72
- self.api_url, self.organization, team, user
73
- )
69
+ url_team = f"{self.api_url}/organization/{self.organization}/team/{team}/members/{user}"
74
70
 
75
71
  r = requests.delete(url_team, headers=self.auth_header, timeout=self._timeout)
76
72
  if not r.ok:
77
73
  message = r.json().get("message", "")
78
74
 
79
- expected_message = "User {} does not belong to team {}".format(user, team)
75
+ expected_message = f"User {user} does not belong to team {team}"
80
76
 
81
77
  if message != expected_message:
82
78
  r.raise_for_status()
83
79
 
84
- url_org = "{}/organization/{}/members/{}".format(
85
- self.api_url, self.organization, user
86
- )
80
+ url_org = f"{self.api_url}/organization/{self.organization}/members/{user}"
87
81
 
88
82
  r = requests.delete(url_org, headers=self.auth_header, timeout=self._timeout)
89
83
  r.raise_for_status()
@@ -98,9 +92,7 @@ class QuayApi:
98
92
  if user in self.list_team_members(team, cache=True):
99
93
  return True
100
94
 
101
- url = "{}/organization/{}/team/{}/members/{}".format(
102
- self.api_url, self.organization, team, user
103
- )
95
+ url = f"{self.api_url}/organization/{self.organization}/team/{team}/members/{user}"
104
96
  r = requests.put(url, headers=self.auth_header, timeout=self._timeout)
105
97
  r.raise_for_status()
106
98
  return True
@@ -117,7 +109,7 @@ class QuayApi:
117
109
  :raises HTTPError: unsuccessful attempt to create the team
118
110
  """
119
111
 
120
- url = "{}/organization/{}/team/{}".format(self.api_url, self.organization, team)
112
+ url = f"{self.api_url}/organization/{self.organization}/team/{team}"
121
113
 
122
114
  payload = {"role": role}
123
115
 
@@ -140,7 +132,7 @@ class QuayApi:
140
132
  if count > self.LIMIT_FOLLOWS:
141
133
  raise ValueError("Too many page follows")
142
134
 
143
- url = "{}/repository".format(self.api_url)
135
+ url = f"{self.api_url}/repository"
144
136
 
145
137
  # params
146
138
  params = {"namespace": self.organization}
@@ -176,7 +168,7 @@ class QuayApi:
176
168
  """
177
169
  visibility = "public" if public else "private"
178
170
 
179
- url = "{}/repository".format(self.api_url)
171
+ url = f"{self.api_url}/repository"
180
172
 
181
173
  params = {
182
174
  "repo_kind": "image",
@@ -193,14 +185,14 @@ class QuayApi:
193
185
  r.raise_for_status()
194
186
 
195
187
  def repo_delete(self, repo_name):
196
- url = "{}/repository/{}/{}".format(self.api_url, self.organization, repo_name)
188
+ url = f"{self.api_url}/repository/{self.organization}/{repo_name}"
197
189
 
198
190
  # perform request
199
191
  r = requests.delete(url, headers=self.auth_header, timeout=self._timeout)
200
192
  r.raise_for_status()
201
193
 
202
194
  def repo_update_description(self, repo_name, description):
203
- url = "{}/repository/{}/{}".format(self.api_url, self.organization, repo_name)
195
+ url = f"{self.api_url}/repository/{self.organization}/{repo_name}"
204
196
 
205
197
  params = {"description": description}
206
198
 
@@ -217,9 +209,7 @@ class QuayApi:
217
209
  self._repo_change_visibility(repo_name, "private")
218
210
 
219
211
  def _repo_change_visibility(self, repo_name, visibility):
220
- url = "{}/repository/{}/{}/changevisibility".format(
221
- self.api_url, self.organization, repo_name
222
- )
212
+ url = f"{self.api_url}/repository/{self.organization}/{repo_name}/changevisibility"
223
213
 
224
214
  params = {"visibility": visibility}
225
215
 
@@ -72,7 +72,7 @@ class RawGithubApi:
72
72
  return result
73
73
 
74
74
  def org_invitations(self, org):
75
- invitations = self.query("/orgs/{}/invitations".format(org))
75
+ invitations = self.query(f"/orgs/{org}/invitations")
76
76
 
77
77
  return [
78
78
  login
@@ -81,9 +81,7 @@ class RawGithubApi:
81
81
  ]
82
82
 
83
83
  def team_invitations(self, org_id, team_id):
84
- invitations = self.query(
85
- "/organizations/{}/team/{}/invitations".format(org_id, team_id)
86
- )
84
+ invitations = self.query(f"/organizations/{org_id}/team/{team_id}/invitations")
87
85
 
88
86
  return [
89
87
  login
@@ -95,6 +93,6 @@ class RawGithubApi:
95
93
  return self.query("/user/repository_invitations")
96
94
 
97
95
  def accept_repo_invitation(self, invitation_id):
98
- url = self.BASE_URL + "/user/repository_invitations/{}".format(invitation_id)
96
+ url = self.BASE_URL + f"/user/repository_invitations/{invitation_id}"
99
97
  res = self.patch(url)
100
98
  res.raise_for_status()
@@ -2,8 +2,8 @@ import collections
2
2
  import itertools
3
3
  import os
4
4
  import textwrap
5
- from collections.abc import Iterable
6
- from typing import Any, Callable, Optional
5
+ from collections.abc import Callable, Iterable
6
+ from typing import Any
7
7
 
8
8
  from kubernetes.client import (
9
9
  V1Container,
@@ -42,13 +42,13 @@ class LogHandle:
42
42
  ) -> Iterable[str]:
43
43
  if max_lines <= 0:
44
44
  return []
45
- with open(self.log_file, "r", encoding="utf-8") as f:
45
+ with open(self.log_file, encoding="utf-8") as f:
46
46
  if from_file_end:
47
47
  return collections.deque(f, maxlen=max_lines)
48
48
  return [line.rstrip() for line in itertools.islice(f, max_lines)]
49
49
 
50
50
  def write_logs_to_logger(self, logger: Callable[..., None]) -> None:
51
- with open(self.log_file, "r", encoding="utf-8") as f:
51
+ with open(self.log_file, encoding="utf-8") as f:
52
52
  logger(f.read())
53
53
 
54
54
  def exists(self) -> bool:
@@ -67,7 +67,7 @@ class RosaCliResult:
67
67
  self,
68
68
  status: JobStatus,
69
69
  command: str,
70
- log_handle: Optional[LogHandle] = None,
70
+ log_handle: LogHandle | None = None,
71
71
  ) -> None:
72
72
  self.status = status
73
73
  self.command = command
@@ -100,7 +100,7 @@ class RosaCliException(Exception, RosaCliResult):
100
100
  self,
101
101
  status: JobStatus,
102
102
  command: str,
103
- log_handle: Optional[LogHandle] = None,
103
+ log_handle: LogHandle | None = None,
104
104
  ) -> None:
105
105
  Exception.__init__(
106
106
  self, f"ROSA CLI execution failed with status: {status}, cmd: {command}"
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  import tempfile
3
- from typing import Optional
4
3
 
5
4
  from jinja2 import Environment, FileSystemLoader
6
5
  from pydantic import BaseModel
@@ -53,8 +52,8 @@ class RosaSession:
53
52
  ocm_org_id: str,
54
53
  ocm_api: OCMBaseClient,
55
54
  job_controller: K8sJobController,
56
- image: Optional[str] = None,
57
- service_account: Optional[str] = None,
55
+ image: str | None = None,
56
+ service_account: str | None = None,
58
57
  ):
59
58
  self.aws_account_id = aws_account_id
60
59
  self.aws_region = aws_region
@@ -68,8 +67,8 @@ class RosaSession:
68
67
  def assemble_job(
69
68
  self,
70
69
  cmd: str,
71
- annotations: Optional[dict[str, str]] = None,
72
- image: Optional[str] = None,
70
+ annotations: dict[str, str] | None = None,
71
+ image: str | None = None,
73
72
  ) -> RosaJob:
74
73
  return RosaJob(
75
74
  aws_account_id=self.aws_account_id,
@@ -86,8 +85,8 @@ class RosaSession:
86
85
  def cli_execute(
87
86
  self,
88
87
  cmd: str,
89
- annotations: Optional[dict[str, str]] = None,
90
- image: Optional[str] = None,
88
+ annotations: dict[str, str] | None = None,
89
+ image: str | None = None,
91
90
  check_interval_seconds: int = 5,
92
91
  timeout_seconds: int = 60,
93
92
  ) -> RosaCliResult:
@@ -1,13 +1,8 @@
1
1
  import logging
2
2
  import multiprocessing
3
+ from collections.abc import Callable, Iterable, Mapping
3
4
  from dataclasses import dataclass
4
- from typing import (
5
- Any,
6
- Callable,
7
- Iterable,
8
- Mapping,
9
- Optional,
10
- )
5
+ from typing import Any
11
6
 
12
7
  from deepdiff import DeepHash
13
8
  from jsonpath_ng.ext.parser import parse
@@ -177,7 +172,7 @@ def extract_diffs_with_timeout(
177
172
 
178
173
 
179
174
  def build_desired_state_diff(
180
- sharding_config: Optional[DesiredStateShardConfig],
175
+ sharding_config: DesiredStateShardConfig | None,
181
176
  previous_desired_state: Mapping[str, Any],
182
177
  current_desired_state: Mapping[str, Any],
183
178
  ) -> DesiredStateDiff:
@@ -1,7 +1,6 @@
1
1
  import logging
2
2
  import os
3
3
  import sys
4
- from typing import Optional
5
4
 
6
5
  from reconcile.utils import (
7
6
  config,
@@ -19,9 +18,7 @@ DRY_RUN_MAP = {
19
18
  }
20
19
 
21
20
 
22
- def log_fmt(
23
- dry_run: Optional[bool] = None, dry_run_option: Optional[str] = None
24
- ) -> str:
21
+ def log_fmt(dry_run: bool | None = None, dry_run_option: str | None = None) -> str:
25
22
  if dry_run and dry_run_option:
26
23
  raise ValueError("Please set either dry_run or dry_run_option.")
27
24
 
@@ -46,9 +43,9 @@ def log_fmt(
46
43
 
47
44
 
48
45
  def init_env(
49
- log_level: Optional[str] = None,
50
- config_file: Optional[str] = None,
51
- dry_run: Optional[bool] = None,
46
+ log_level: str | None = None,
47
+ config_file: str | None = None,
48
+ dry_run: bool | None = None,
52
49
  print_gql_url: bool = True,
53
50
  ) -> None:
54
51
  # store env configs in environment variables. this way child processes
@@ -2,11 +2,11 @@ from abc import (
2
2
  ABC,
3
3
  abstractmethod,
4
4
  )
5
+ from collections.abc import Callable
5
6
  from dataclasses import dataclass
6
7
  from types import ModuleType
7
8
  from typing import (
8
9
  Any,
9
- Callable,
10
10
  Generic,
11
11
  Optional,
12
12
  TypeVar,
@@ -153,7 +153,7 @@ class QontractReconcileIntegration(ABC, Generic[RunParamsTypeVar]):
153
153
 
154
154
  def __init__(self, params: RunParamsTypeVar) -> None:
155
155
  self.params: RunParamsTypeVar = params
156
- self._secret_reader: Optional[SecretReaderBase] = None
156
+ self._secret_reader: SecretReaderBase | None = None
157
157
 
158
158
  @property
159
159
  @abstractmethod
@@ -169,7 +169,7 @@ class QontractReconcileIntegration(ABC, Generic[RunParamsTypeVar]):
169
169
  self._secret_reader = create_secret_reader(use_vault=vault_settings.vault)
170
170
  return self._secret_reader
171
171
 
172
- def get_early_exit_desired_state(self) -> Optional[dict[str, Any]]:
172
+ def get_early_exit_desired_state(self) -> dict[str, Any] | None:
173
173
  """
174
174
  An integration that wants to support early exit on its desired state
175
175
  must implement this method and return the desired state as a dictionary.
@@ -299,7 +299,7 @@ class ModuleBasedQontractReconcileIntegration(
299
299
  return self.params.module.QONTRACT_INTEGRATION.replace("_", "-")
300
300
  raise NotImplementedError("Integration missing QONTRACT_INTEGRATION.")
301
301
 
302
- def get_early_exit_desired_state(self) -> Optional[dict[str, Any]]:
302
+ def get_early_exit_desired_state(self) -> dict[str, Any] | None:
303
303
  if self._integration_supports(EARLY_EXIT_DESIRED_STATE_FUNCTION):
304
304
  return self.params.module.early_exit_desired_state(
305
305
  *self.params.args, **self.params.kwargs
@@ -1,13 +1,12 @@
1
1
  import dataclasses
2
2
  from dataclasses import dataclass
3
- from typing import Optional
4
3
 
5
4
 
6
5
  @dataclass
7
6
  class IntegrationMeta:
8
7
  name: str
9
8
  args: list[str]
10
- short_help: Optional[str]
9
+ short_help: str | None
11
10
 
12
11
  def to_dict(self):
13
12
  return dataclasses.asdict(self)
@@ -3,7 +3,6 @@ import sys
3
3
  from dataclasses import dataclass
4
4
  from typing import (
5
5
  Any,
6
- Optional,
7
6
  TypeVar,
8
7
  )
9
8
 
@@ -44,7 +43,7 @@ class IntegrationRunConfiguration:
44
43
  potential problems with the integration or the configuration data from app-interface.
45
44
  """
46
45
 
47
- early_exit_compare_sha: Optional[str]
46
+ early_exit_compare_sha: str | None
48
47
  """
49
48
  The SHA of the bundle to compare the current desired state against.
50
49
  """
@@ -66,11 +65,11 @@ class IntegrationRunConfiguration:
66
65
  A debug flag to control whether the URL of the GraphQL endpoint in use is printed.
67
66
  """
68
67
 
69
- def main_bundle_desired_state(self) -> Optional[dict[str, Any]]:
68
+ def main_bundle_desired_state(self) -> dict[str, Any] | None:
70
69
  self.switch_to_main_bundle()
71
70
  return self.integration.get_early_exit_desired_state()
72
71
 
73
- def comparison_bundle_desired_state(self) -> Optional[dict[str, Any]]:
72
+ def comparison_bundle_desired_state(self) -> dict[str, Any] | None:
74
73
  self.switch_to_comparison_bundle()
75
74
  data = ( # pylint: disable=assignment-from-none
76
75
  self.integration.get_early_exit_desired_state()
@@ -78,7 +77,7 @@ class IntegrationRunConfiguration:
78
77
  self.switch_to_main_bundle()
79
78
  return data
80
79
 
81
- def switch_to_main_bundle(self, validate_schemas: Optional[bool] = None) -> None:
80
+ def switch_to_main_bundle(self, validate_schemas: bool | None = None) -> None:
82
81
  final_validate_schemas = (
83
82
  validate_schemas if validate_schemas is not None else self.valdiate_schemas
84
83
  )
@@ -89,9 +88,7 @@ class IntegrationRunConfiguration:
89
88
  print_url=self.print_url,
90
89
  )
91
90
 
92
- def switch_to_comparison_bundle(
93
- self, validate_schemas: Optional[bool] = None
94
- ) -> None:
91
+ def switch_to_comparison_bundle(self, validate_schemas: bool | None = None) -> None:
95
92
  final_validate_schemas = (
96
93
  validate_schemas if validate_schemas is not None else self.valdiate_schemas
97
94
  )
@@ -105,7 +102,7 @@ class IntegrationRunConfiguration:
105
102
 
106
103
  def get_desired_state_diff(
107
104
  run_cfg: IntegrationRunConfiguration,
108
- ) -> Optional[DesiredStateDiff]:
105
+ ) -> DesiredStateDiff | None:
109
106
  """
110
107
  Calculates the desired state diff between the current bundle and the
111
108
  comparison bundle for an integration. If the integration does not support
@@ -172,7 +169,7 @@ def _integration_wet_run(
172
169
 
173
170
  def _integration_dry_run(
174
171
  integration: QontractReconcileIntegration[RunParamsTypeVar],
175
- desired_state_diff: Optional[DesiredStateDiff],
172
+ desired_state_diff: DesiredStateDiff | None,
176
173
  ) -> None:
177
174
  """
178
175
  Runs an integration in dry-run mode, i.e. not actually making any changes
@@ -2,9 +2,7 @@ import copy
2
2
  from collections.abc import Iterable
3
3
  from dataclasses import dataclass
4
4
  from typing import (
5
- Optional,
6
5
  Protocol,
7
- Union,
8
6
  )
9
7
 
10
8
  from pydantic import BaseModel
@@ -46,16 +44,15 @@ from reconcile.utils.runtime.meta import IntegrationMeta
46
44
 
47
45
  class ShardSpec(BaseModel):
48
46
  # Base Sharding
49
- shards: Optional[str] = ""
50
- shard_id: Optional[str] = ""
51
- shard_spec_overrides: Optional[
52
- Union[
53
- AWSAccountShardSpecOverrideV1,
54
- OpenshiftClusterShardSpecOverrideV1,
55
- CloudflareDNSZoneShardSpecOverrideV1,
56
- OCMOrganizationShardSpecOverrideV1,
57
- ]
58
- ] = None
47
+ shards: str | None = ""
48
+ shard_id: str | None = ""
49
+ shard_spec_overrides: (
50
+ AWSAccountShardSpecOverrideV1
51
+ | OpenshiftClusterShardSpecOverrideV1
52
+ | CloudflareDNSZoneShardSpecOverrideV1
53
+ | OCMOrganizationShardSpecOverrideV1
54
+ | None
55
+ ) = None
59
56
 
60
57
  # Key sharding
61
58
  shard_key: str = ""
@@ -136,7 +133,7 @@ class AWSAccountShardingStrategy:
136
133
 
137
134
  def __init__(
138
135
  self,
139
- aws_accounts: Optional[Iterable[sharding_aws_accounts.AWSAccountV1]] = None,
136
+ aws_accounts: Iterable[sharding_aws_accounts.AWSAccountV1] | None = None,
140
137
  ):
141
138
  if not aws_accounts:
142
139
  self.aws_accounts = (
@@ -162,7 +159,7 @@ class AWSAccountShardingStrategy:
162
159
  ]
163
160
 
164
161
  def get_shard_spec_overrides(
165
- self, sharding: Optional[IntegrationShardingV1]
162
+ self, sharding: IntegrationShardingV1 | None
166
163
  ) -> dict[str, AWSAccountShardSpecOverrideV1]:
167
164
  spos: dict[str, AWSAccountShardSpecOverrideV1] = {}
168
165
 
@@ -183,7 +180,7 @@ class AWSAccountShardingStrategy:
183
180
  self,
184
181
  aws_account: sharding_aws_accounts.AWSAccountV1,
185
182
  integration_spec: IntegrationSpecV1,
186
- spo: Optional[AWSAccountShardSpecOverrideV1],
183
+ spo: AWSAccountShardSpecOverrideV1 | None,
187
184
  ) -> ShardSpec:
188
185
  return ShardSpec(
189
186
  shard_key=aws_account.name,
@@ -213,7 +210,7 @@ class OCMOrganizationShardingStrategy:
213
210
 
214
211
  def __init__(
215
212
  self,
216
- ocm_organizations: Optional[Iterable[MinimalOCMOrganization]] = None,
213
+ ocm_organizations: Iterable[MinimalOCMOrganization] | None = None,
217
214
  ):
218
215
  if not ocm_organizations:
219
216
  self.ocm_organizations = (
@@ -226,7 +223,7 @@ class OCMOrganizationShardingStrategy:
226
223
  self.ocm_organizations = list(ocm_organizations)
227
224
 
228
225
  def get_shard_spec_overrides(
229
- self, sharding: Optional[IntegrationShardingV1]
226
+ self, sharding: IntegrationShardingV1 | None
230
227
  ) -> dict[str, OCMOrganizationShardSpecOverrideV1]:
231
228
  spos: dict[str, OCMOrganizationShardSpecOverrideV1] = {}
232
229
 
@@ -249,7 +246,7 @@ class OCMOrganizationShardingStrategy:
249
246
  self,
250
247
  org: MinimalOCMOrganization,
251
248
  integration_spec: IntegrationSpecV1,
252
- spo: Optional[OCMOrganizationShardSpecOverrideV1],
249
+ spo: OCMOrganizationShardSpecOverrideV1 | None,
253
250
  ) -> ShardSpec:
254
251
  return ShardSpec(
255
252
  shard_key=org.org_id,
@@ -276,7 +273,7 @@ class OCMOrganizationShardingStrategy:
276
273
  class OpenshiftClusterShardingStrategy:
277
274
  IDENTIFIER = "per-openshift-cluster"
278
275
 
279
- def __init__(self, clusters: Optional[Iterable[ClusterV1]] = None):
276
+ def __init__(self, clusters: Iterable[ClusterV1] | None = None):
280
277
  if not clusters:
281
278
  self.clusters = get_clusters_minimal()
282
279
  else:
@@ -300,7 +297,7 @@ class OpenshiftClusterShardingStrategy:
300
297
  ]
301
298
 
302
299
  def get_shard_spec_overrides(
303
- self, sharding: Optional[IntegrationShardingV1]
300
+ self, sharding: IntegrationShardingV1 | None
304
301
  ) -> dict[str, OpenshiftClusterShardSpecOverrideV1]:
305
302
  spos: dict[str, OpenshiftClusterShardSpecOverrideV1] = {}
306
303
 
@@ -324,7 +321,7 @@ class OpenshiftClusterShardingStrategy:
324
321
  self,
325
322
  cluster: ClusterV1,
326
323
  integration_spec: IntegrationSpecV1,
327
- spo: Optional[OpenshiftClusterShardSpecOverrideV1],
324
+ spo: OpenshiftClusterShardSpecOverrideV1 | None,
328
325
  ) -> ShardSpec:
329
326
  return ShardSpec(
330
327
  shard_key=cluster.name,
@@ -335,7 +332,7 @@ class OpenshiftClusterShardingStrategy:
335
332
  )
336
333
 
337
334
  def build_sub_shards(
338
- self, base_shard: ShardSpec, spo: Optional[OpenshiftClusterShardSpecOverrideV1]
335
+ self, base_shard: ShardSpec, spo: OpenshiftClusterShardSpecOverrideV1 | None
339
336
  ) -> list[ShardSpec]:
340
337
  sub_shards = []
341
338
  if spo and spo.sub_sharding and spo.sub_sharding.strategy:
@@ -374,9 +371,7 @@ class CloudflareDnsZoneShardingStrategy:
374
371
 
375
372
  IDENTIFIER = "per-cloudflare-dns-zone"
376
373
 
377
- def __init__(
378
- self, cloudflare_zones: Optional[Iterable[CloudflareDnsZoneV1]] = None
379
- ):
374
+ def __init__(self, cloudflare_zones: Iterable[CloudflareDnsZoneV1] | None = None):
380
375
  if not cloudflare_zones:
381
376
  self.cloudflare_zones = (
382
377
  terraform_cloudflare_zones.query(query_func=gql.get_api().query).zones
@@ -389,7 +384,7 @@ class CloudflareDnsZoneShardingStrategy:
389
384
  return f"{dns_zone.account.name}-{dns_zone.identifier}"
390
385
 
391
386
  def get_shard_spec_overrides(
392
- self, sharding: Optional[IntegrationShardingV1]
387
+ self, sharding: IntegrationShardingV1 | None
393
388
  ) -> dict[str, CloudflareDNSZoneShardSpecOverrideV1]:
394
389
  spos: dict[str, CloudflareDNSZoneShardSpecOverrideV1] = {}
395
390
 
@@ -414,7 +409,7 @@ class CloudflareDnsZoneShardingStrategy:
414
409
  self,
415
410
  dns_zone: CloudflareDnsZoneV1,
416
411
  integration_spec: IntegrationSpecV1,
417
- spo: Optional[CloudflareDNSZoneShardSpecOverrideV1],
412
+ spo: CloudflareDNSZoneShardSpecOverrideV1 | None,
418
413
  ) -> ShardSpec:
419
414
  return ShardSpec(
420
415
  shard_key=self._get_shard_key(dns_zone),