qontract-reconcile 0.10.1rc884__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.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc884.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 +5 -5
  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 +3 -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.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/WHEEL +0 -0
  275. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/entry_points.txt +0 -0
  276. {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc885.dist-info}/top_level.txt +0 -0
@@ -7,9 +7,7 @@ from collections.abc import (
7
7
  )
8
8
  from typing import (
9
9
  Any,
10
- Optional,
11
10
  TypedDict,
12
- Union,
13
11
  cast,
14
12
  )
15
13
 
@@ -69,7 +67,7 @@ class ValidationError(Exception):
69
67
  class AccountProviderInfo(BaseModel):
70
68
  name: str
71
69
  uid: str
72
- assume_role: Optional[str]
70
+ assume_role: str | None
73
71
  assume_region: str
74
72
  assume_cidr: str
75
73
 
@@ -78,9 +76,9 @@ class Requester(BaseModel):
78
76
  tgw_id: str
79
77
  tgw_arn: str
80
78
  region: str
81
- routes: Optional[list[dict]]
82
- rules: Optional[list[dict]]
83
- hostedzones: Optional[list[str]]
79
+ routes: list[dict] | None
80
+ rules: list[dict] | None
81
+ hostedzones: list[str] | None
84
82
  cidr_block: str
85
83
  account: AccountProviderInfo
86
84
 
@@ -88,11 +86,11 @@ class Requester(BaseModel):
88
86
  class Accepter(BaseModel):
89
87
  cidr_block: str
90
88
  region: str
91
- vpc_id: Optional[str]
92
- route_table_ids: Optional[list[str]]
93
- subnets_id_az: Optional[list[dict]]
89
+ vpc_id: str | None
90
+ route_table_ids: list[str] | None
91
+ subnets_id_az: list[dict] | None
94
92
  account: AccountProviderInfo
95
- api_security_group_id: Optional[str]
93
+ api_security_group_id: str | None
96
94
 
97
95
 
98
96
  class DesiredStateItem(BaseModel):
@@ -122,9 +120,9 @@ class RunnerParams(TypedDict):
122
120
 
123
121
  def _build_desired_state_tgw_attachments(
124
122
  clusters: Iterable[ClusterV1],
125
- ocm_map: Optional[OCMMap],
123
+ ocm_map: OCMMap | None,
126
124
  awsapi: AWSApi,
127
- account_name: Optional[str] = None,
125
+ account_name: str | None = None,
128
126
  ) -> tuple[list[DesiredStateItem], bool]:
129
127
  """
130
128
  Fetch state for TGW attachments between a cluster and all TGWs
@@ -143,10 +141,10 @@ def _build_desired_state_tgw_attachments(
143
141
 
144
142
  def _build_desired_state_items(
145
143
  clusters: Iterable[ClusterV1],
146
- ocm_map: Optional[OCMMap],
144
+ ocm_map: OCMMap | None,
147
145
  awsapi: AWSApi,
148
- account_name: Optional[str] = None,
149
- ) -> Generator[Optional[DesiredStateItem], Any, None]:
146
+ account_name: str | None = None,
147
+ ) -> Generator[DesiredStateItem | None, Any, None]:
150
148
  for cluster_info in clusters:
151
149
  ocm = ocm_map.get(cluster_info.name) if ocm_map and cluster_info.ocm else None
152
150
  for peer_connection in cluster_info.peering.connections: # type: ignore[union-attr]
@@ -162,9 +160,9 @@ def _build_desired_state_items(
162
160
  def _build_desired_state_tgw_connection(
163
161
  peer_connection: ClusterPeeringConnectionAccountTGWV1,
164
162
  cluster_info: ClusterV1,
165
- ocm: Optional[OCM],
163
+ ocm: OCM | None,
166
164
  awsapi: AWSApi,
167
- ) -> Generator[Optional[DesiredStateItem], Any, None]:
165
+ ) -> Generator[DesiredStateItem | None, Any, None]:
168
166
  cluster_name = cluster_info.name
169
167
  cluster_region = cluster_info.spec.region if cluster_info.spec is not None else ""
170
168
  cluster_cidr_block = (
@@ -226,7 +224,7 @@ def _build_account_with_assume_role(
226
224
  cluster: ClusterV1,
227
225
  region: str,
228
226
  cidr_block: str,
229
- ocm: Optional[OCM],
227
+ ocm: OCM | None,
230
228
  ) -> AccountProviderInfo:
231
229
  account = peer_connection.account
232
230
  # assume_role is the role to assume to provision the
@@ -313,7 +311,7 @@ def _build_requester(
313
311
  def _build_ocm_map(
314
312
  clusters: Iterable[ClusterV1],
315
313
  vault_settings: AppInterfaceSettingsV1,
316
- ) -> Optional[OCMMap]:
314
+ ) -> OCMMap | None:
317
315
  ocm_clusters = [c.dict(by_alias=True) for c in clusters if c.ocm]
318
316
  return (
319
317
  OCMMap(
@@ -338,7 +336,7 @@ def _validate_tgw_connection_names(desired_state: Iterable[DesiredStateItem]) ->
338
336
  def _populate_tgw_attachments_working_dirs(
339
337
  ts: Terrascript,
340
338
  desired_state: Iterable[DesiredStateItem],
341
- print_to_file: Optional[str],
339
+ print_to_file: str | None,
342
340
  ) -> dict[str, str]:
343
341
  accounts_by_infra_account_name: dict[str, list[dict[str, Any]]] = {}
344
342
  for item in desired_state:
@@ -353,14 +351,12 @@ def _populate_tgw_attachments_working_dirs(
353
351
 
354
352
 
355
353
  def _is_tgw_peer_connection(
356
- peer_connection: Union[
357
- ClusterPeeringConnectionAccountTGWV1,
358
- ClusterPeeringConnectionAccountV1,
359
- ClusterPeeringConnectionAccountVPCMeshV1,
360
- ClusterPeeringConnectionClusterRequesterV1,
361
- ClusterPeeringConnectionV1,
362
- ],
363
- account_name: Optional[str],
354
+ peer_connection: ClusterPeeringConnectionAccountTGWV1
355
+ | ClusterPeeringConnectionAccountV1
356
+ | ClusterPeeringConnectionAccountVPCMeshV1
357
+ | ClusterPeeringConnectionClusterRequesterV1
358
+ | ClusterPeeringConnectionV1,
359
+ account_name: str | None,
364
360
  ) -> bool:
365
361
  if peer_connection.provider != TGW_CONNECTION_PROVIDER:
366
362
  return False
@@ -372,7 +368,7 @@ def _is_tgw_peer_connection(
372
368
 
373
369
  def _is_tgw_cluster(
374
370
  cluster: ClusterV1,
375
- account_name: Optional[str] = None,
371
+ account_name: str | None = None,
376
372
  ) -> bool:
377
373
  return any(
378
374
  _is_tgw_peer_connection(pc, account_name)
@@ -382,7 +378,7 @@ def _is_tgw_cluster(
382
378
 
383
379
  def _filter_tgw_clusters(
384
380
  clusters: Iterable[ClusterV1],
385
- account_name: Optional[str] = None,
381
+ account_name: str | None = None,
386
382
  ) -> list[ClusterV1]:
387
383
  return [c for c in clusters if _is_tgw_cluster(c, account_name)]
388
384
 
@@ -408,7 +404,7 @@ def _filter_tgw_accounts(
408
404
 
409
405
 
410
406
  def _fetch_desired_state_data_source(
411
- account_name: Optional[str] = None,
407
+ account_name: str | None = None,
412
408
  ) -> DesiredStateDataSource:
413
409
  clusters = get_clusters_with_peering(gql.get_api())
414
410
  tgw_clusters = _filter_tgw_clusters(clusters, account_name)
@@ -420,11 +416,11 @@ def _fetch_desired_state_data_source(
420
416
 
421
417
 
422
418
  def setup(
423
- account_name: Optional[str],
419
+ account_name: str | None,
424
420
  desired_state_data_source: DesiredStateDataSource,
425
421
  tgw_accounts: list[dict[str, Any]],
426
422
  thread_pool_size: int = 10,
427
- print_to_file: Optional[str] = None,
423
+ print_to_file: str | None = None,
428
424
  ) -> tuple[SecretReaderBase, AWSApi, Terraform, Terrascript]:
429
425
  tgw_clusters = desired_state_data_source.clusters
430
426
  all_accounts = [a.dict(by_alias=True) for a in desired_state_data_source.accounts]
@@ -498,11 +494,11 @@ def runner(
498
494
  @defer
499
495
  def run(
500
496
  dry_run: bool,
501
- print_to_file: Optional[str] = None,
497
+ print_to_file: str | None = None,
502
498
  enable_deletion: bool = False,
503
499
  thread_pool_size: int = 10,
504
- account_name: Optional[str] = None,
505
- defer: Optional[Callable] = None,
500
+ account_name: str | None = None,
501
+ defer: Callable | None = None,
506
502
  enable_extended_early_exit: bool = False,
507
503
  extended_early_exit_cache_ttl_seconds: int = 3600,
508
504
  log_cached_log_output: bool = False,
@@ -2,7 +2,6 @@ import sys
2
2
  from textwrap import indent
3
3
  from typing import (
4
4
  Any,
5
- Optional,
6
5
  cast,
7
6
  )
8
7
 
@@ -109,8 +108,8 @@ def setup(
109
108
  print_to_file,
110
109
  thread_pool_size: int,
111
110
  skip_reencrypt_accounts: list[str],
112
- appsre_pgp_key: Optional[str] = None,
113
- account_name: Optional[str] = None,
111
+ appsre_pgp_key: str | None = None,
112
+ account_name: str | None = None,
114
113
  ) -> tuple[list[dict[str, Any]], dict[str, str], bool, AWSApi]:
115
114
  accounts = [
116
115
  a
@@ -173,7 +172,7 @@ Encrypted password: {}
173
172
  if account not in skip_reencrypt_accounts:
174
173
  continue
175
174
  to = user_name
176
- subject = "Invitation to join the {} AWS account".format(account)
175
+ subject = f"Invitation to join the {account} AWS account"
177
176
  body = msg_template.format(account, console_url, user_name, enc_password)
178
177
  mails.append((to, subject, body))
179
178
 
@@ -224,7 +223,7 @@ def get_reencrypt_settings():
224
223
  if reencrypt_settings.skip_aws_accounts:
225
224
  skip_accounts = [s.name for s in reencrypt_settings.skip_aws_accounts]
226
225
 
227
- appsre_pgp_key: Optional[str] = None
226
+ appsre_pgp_key: str | None = None
228
227
  if reencrypt_settings is not None:
229
228
  appsre_pgp_key = reencrypt_settings.public_gpg_key
230
229
 
@@ -233,11 +232,11 @@ def get_reencrypt_settings():
233
232
 
234
233
  def run(
235
234
  dry_run: bool,
236
- print_to_file: Optional[str] = None,
235
+ print_to_file: str | None = None,
237
236
  enable_deletion: bool = False,
238
237
  thread_pool_size: int = 10,
239
238
  send_mails: bool = True,
240
- account_name: Optional[str] = None,
239
+ account_name: str | None = None,
241
240
  ):
242
241
  skip_accounts, appsre_pgp_key, reencrypt_settings = get_reencrypt_settings()
243
242
 
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  import sys
3
- from collections.abc import Mapping, MutableMapping
4
- from typing import Any, Iterable, Optional
3
+ from collections.abc import Iterable, Mapping, MutableMapping
4
+ from typing import Any
5
5
 
6
6
  import jinja2
7
7
 
@@ -41,8 +41,8 @@ AWS_PROVIDER_VERSION = "5.7.1"
41
41
 
42
42
 
43
43
  class TerraformVpcResourcesParams(PydanticRunParams):
44
- account_name: Optional[str]
45
- print_to_file: Optional[str]
44
+ account_name: str | None
45
+ print_to_file: str | None
46
46
  thread_pool_size: int
47
47
  enable_deletion: bool = False
48
48
 
@@ -53,7 +53,7 @@ class TerraformVpcResources(QontractReconcileIntegration[TerraformVpcResourcesPa
53
53
  return QONTRACT_INTEGRATION.replace("_", "-")
54
54
 
55
55
  def _filter_accounts(
56
- self, data: Iterable[VPCRequest], account_name: Optional[str]
56
+ self, data: Iterable[VPCRequest], account_name: str | None
57
57
  ) -> list[AWSAccountV1]:
58
58
  """Return a list of accounts extracted from the provided VPCRequests.
59
59
  If account_name is given returns the account object with that name."""
@@ -6,10 +6,7 @@ from collections.abc import (
6
6
  MutableMapping,
7
7
  )
8
8
  from pathlib import Path
9
- from typing import (
10
- Any,
11
- Optional,
12
- )
9
+ from typing import Any
13
10
  from unittest.mock import MagicMock, create_autospec
14
11
 
15
12
  import pytest
@@ -96,14 +93,14 @@ def vault_secret():
96
93
  @pytest.fixture
97
94
  def data_factory() -> (
98
95
  Callable[
99
- [type[BaseModel], Optional[MutableMapping[str, Any]]],
96
+ [type[BaseModel], MutableMapping[str, Any] | None],
100
97
  MutableMapping[str, Any],
101
98
  ]
102
99
  ):
103
100
  """Set default values to None."""
104
101
 
105
102
  def _data_factory(
106
- klass: type[BaseModel], data: Optional[MutableMapping[str, Any]] = None
103
+ klass: type[BaseModel], data: MutableMapping[str, Any] | None = None
107
104
  ) -> MutableMapping[str, Any]:
108
105
  return data_default_none(klass, data or {})
109
106
 
@@ -117,14 +114,14 @@ class GQLClassFactoryError(Exception):
117
114
  @pytest.fixture
118
115
  def gql_class_factory() -> (
119
116
  Callable[
120
- [type[BaseModel], Optional[MutableMapping[str, Any]]],
117
+ [type[BaseModel], MutableMapping[str, Any] | None],
121
118
  BaseModel,
122
119
  ]
123
120
  ):
124
121
  """Create a GQL class from a fixture and set default values to None."""
125
122
 
126
123
  def _gql_class_factory(
127
- klass: type[BaseModel], data: Optional[MutableMapping[str, Any]] = None
124
+ klass: type[BaseModel], data: MutableMapping[str, Any] | None = None
128
125
  ) -> BaseModel:
129
126
  try:
130
127
  return klass(**data_default_none(klass, data or {}))
@@ -137,8 +134,8 @@ def gql_class_factory() -> (
137
134
 
138
135
 
139
136
  @pytest.fixture
140
- def gql_api_builder() -> Callable[[Optional[Mapping]], GqlApi]:
141
- def builder(data: Optional[Mapping] = None) -> GqlApi:
137
+ def gql_api_builder() -> Callable[[Mapping | None], GqlApi]:
138
+ def builder(data: Mapping | None = None) -> GqlApi:
142
139
  gql_api = create_autospec(GqlApi)
143
140
  gql_api.query.return_value = data
144
141
  return gql_api
@@ -14,7 +14,7 @@ class Fixtures:
14
14
  )
15
15
 
16
16
  def get(self, fixture):
17
- with open(self.path(fixture), "r", encoding="locale") as f:
17
+ with open(self.path(fixture), encoding="locale") as f:
18
18
  return f.read().strip()
19
19
 
20
20
  def get_anymarkup(self, fixture):
@@ -5,7 +5,7 @@ from collections.abc import (
5
5
  Mapping,
6
6
  MutableMapping,
7
7
  )
8
- from datetime import datetime, timezone
8
+ from datetime import UTC, datetime
9
9
  from typing import Any
10
10
  from unittest.mock import (
11
11
  MagicMock,
@@ -140,7 +140,7 @@ def subscriber_builder(
140
140
  success=publisher_data.get("SUCCESSFUL_DEPLOYMENT", True),
141
141
  target_config_hash=publisher_data.get("CONFIG_HASH", ""),
142
142
  saas_file=publisher_name,
143
- check_in=publisher_data.get("CHECK_IN", datetime.now(timezone.utc)),
143
+ check_in=publisher_data.get("CHECK_IN", datetime.now(UTC)),
144
144
  )
145
145
  channel.publishers.append(publisher)
146
146
  channels.append(channel)
@@ -14,10 +14,10 @@ def file_contents() -> Callable[[str], tuple[str, str]]:
14
14
  "files",
15
15
  )
16
16
 
17
- with open(f"{path}/{case}.yml", "r", encoding="locale") as f:
17
+ with open(f"{path}/{case}.yml", encoding="locale") as f:
18
18
  a = f.read().strip()
19
19
 
20
- with open(f"{path}/{case}.result.yml", "r", encoding="locale") as f:
20
+ with open(f"{path}/{case}.result.yml", encoding="locale") as f:
21
21
  b = f.read().strip()
22
22
 
23
23
  return (a, b)
@@ -1,9 +1,6 @@
1
1
  from collections import defaultdict
2
- from typing import (
3
- Any,
4
- Callable,
5
- Optional,
6
- )
2
+ from collections.abc import Callable
3
+ from typing import Any
7
4
  from unittest.mock import MagicMock
8
5
 
9
6
  import pytest
@@ -266,7 +263,7 @@ def test_generate_revoke_changed(
266
263
  db_connection_parameter: DatabaseConnectionParameters,
267
264
  db_admin_connection_parameter: DatabaseConnectionParameters,
268
265
  expected: str,
269
- current: Optional[DatabaseAccessV1],
266
+ current: DatabaseAccessV1 | None,
270
267
  ):
271
268
  s = PSQLScriptGenerator(
272
269
  db_access=db_access_complete,
@@ -1,7 +1,4 @@
1
- from typing import (
2
- Any,
3
- Optional,
4
- )
1
+ from typing import Any
5
2
  from unittest.mock import (
6
3
  create_autospec,
7
4
  patch,
@@ -50,7 +47,7 @@ class TestOnboardingGuesser:
50
47
  self.gql.return_value = gqlapi_mock
51
48
  gqlapi_mock.query.side_effect = self.mock_gql_query
52
49
 
53
- def mock_gql_query(self, query: str) -> Optional[dict[str, Any]]:
50
+ def mock_gql_query(self, query: str) -> dict[str, Any] | None:
54
51
  """Mock for GqlApi.query using test_data set in setUp"""
55
52
  if query == APPS_QUERY:
56
53
  return {"apps": self.test_data.apps}
@@ -1,8 +1,5 @@
1
1
  import os
2
- from typing import (
3
- Any,
4
- Optional,
5
- )
2
+ from typing import Any
6
3
  from unittest.mock import create_autospec
7
4
 
8
5
  import pytest
@@ -55,7 +52,7 @@ def test_base_jumphost(fs: Any, parameters: JumphostParameters, expected_port: i
55
52
  jumphost = JumpHostBase(parameters=parameters)
56
53
  assert os.path.exists(jumphost._identity_file)
57
54
 
58
- with open(jumphost._identity_file, "r", encoding="locale") as f:
55
+ with open(jumphost._identity_file, encoding="locale") as f:
59
56
  assert f.read() == parameters.key
60
57
 
61
58
  assert jumphost._port == expected_port
@@ -99,8 +96,8 @@ def test_base_jumphost(fs: Any, parameters: JumphostParameters, expected_port: i
99
96
  def test_ssh_jumphost(
100
97
  fs: Any,
101
98
  parameters: JumphostParameters,
102
- local_port: Optional[int],
103
- remote_port: Optional[int],
99
+ local_port: int | None,
100
+ remote_port: int | None,
104
101
  ):
105
102
  gql_mock = create_autospec(spec=gql.GqlApi)
106
103
  gql_mock.get_resource.side_effect = [{"content": EXPECTED_KNOWN_HOSTS_CONTENT}]
@@ -113,5 +110,5 @@ def test_ssh_jumphost(
113
110
  if local_port:
114
111
  assert jumphost._local_port == local_port
115
112
 
116
- with open(known_hosts_file, "r", encoding="locale") as f:
113
+ with open(known_hosts_file, encoding="locale") as f:
117
114
  assert f.read() == EXPECTED_KNOWN_HOSTS_CONTENT
@@ -1,10 +1,7 @@
1
1
  from collections.abc import (
2
2
  Callable,
3
3
  Iterable,
4
- )
5
- from typing import (
6
4
  Mapping,
7
- Optional,
8
5
  )
9
6
  from unittest.mock import create_autospec
10
7
 
@@ -49,7 +46,7 @@ class PoolStub(AbstractPool):
49
46
  def has_diff(self, pool: ClusterMachinePoolV1) -> bool:
50
47
  return True
51
48
 
52
- def invalid_diff(self, pool: ClusterMachinePoolV1) -> Optional[str]:
49
+ def invalid_diff(self, pool: ClusterMachinePoolV1) -> str | None:
53
50
  return None
54
51
 
55
52
  def deletable(self) -> bool:
@@ -1,9 +1,6 @@
1
1
  import logging
2
- from typing import (
3
- Any,
4
- Mapping,
5
- Optional,
6
- )
2
+ from collections.abc import Mapping
3
+ from typing import Any
7
4
  from unittest.mock import patch
8
5
 
9
6
  import pytest
@@ -754,7 +751,7 @@ def build_openshift_resource(
754
751
  kind: str,
755
752
  api_version: str,
756
753
  name: str,
757
- extra_body: Optional[dict[str, Any]],
754
+ extra_body: dict[str, Any] | None,
758
755
  integration: str = "",
759
756
  integration_version: str = "",
760
757
  error_details: str = "",
@@ -131,10 +131,10 @@ def test_oc(mocker: MockerFixture) -> None:
131
131
  assert ocb.oc(*args) is None
132
132
  run_mock.assert_called_once_with(run_args, **run_kwargs)
133
133
 
134
- ret_mock.stdout = "{}".encode()
134
+ ret_mock.stdout = b"{}"
135
135
  assert ocb.oc(*args) == {}
136
136
 
137
- ret_mock.stdout = "".encode()
137
+ ret_mock.stdout = b""
138
138
  assert ocb.oc(*args) is None
139
139
 
140
140
  run_mock.side_effect = CalledProcessError(returncode=4, cmd="oc")
@@ -152,7 +152,7 @@ def test_retrieve_token(mocker: MockerFixture) -> None:
152
152
  ocb.retrieve_token("kc", "ns", "sa")
153
153
  assert oc_mock.call_count == 3
154
154
 
155
- oc_mock.return_value = {"data": {"token": base64.b64encode("Got It!".encode())}}
155
+ oc_mock.return_value = {"data": {"token": base64.b64encode(b"Got It!")}}
156
156
  assert ocb.retrieve_token("kc", "ns", "sa") == "Got It!"
157
157
 
158
158
 
@@ -220,7 +220,7 @@ def test_run_no_cluster_admin(
220
220
  mocker: MockerFixture, integ_params: dict[str, Any], cluster: Callable
221
221
  ) -> None:
222
222
  mocks = _setup_mocks(mocker, filtered_clusters=[cluster(server_url="https://api")])
223
- mocks.oc.return_value = {"data": {"token": base64.b64encode("mytoken".encode())}}
223
+ mocks.oc.return_value = {"data": {"token": base64.b64encode(b"mytoken")}}
224
224
  ocb.run(**integ_params)
225
225
  assert mocks.oc.call_count == 3
226
226
  mocks.vault.assert_called_once()
@@ -233,7 +233,7 @@ def test_run_cluster_admin(
233
233
  mocks = _setup_mocks(
234
234
  mocker, filtered_clusters=[cluster(server_url="https://api", admin=True)]
235
235
  )
236
- mocks.oc.return_value = {"data": {"token": base64.b64encode("mytoken".encode())}}
236
+ mocks.oc.return_value = {"data": {"token": base64.b64encode(b"mytoken")}}
237
237
  ocb.run(**integ_params)
238
238
  assert mocks.oc.call_count == 8
239
239
  mocks.vault.assert_called_once()
@@ -1,5 +1,4 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional
3
2
  from unittest import TestCase
4
3
  from unittest.mock import (
5
4
  Mock,
@@ -37,8 +36,8 @@ class NS:
37
36
 
38
37
  cluster: str
39
38
  name: str
40
- current: Optional[dict[str, str]]
41
- managed: Optional[list[str]]
39
+ current: dict[str, str] | None
40
+ managed: list[str] | None
42
41
  desired: dict[str, str]
43
42
  exists: bool = True
44
43
 
@@ -1,4 +1,4 @@
1
- from datetime import datetime, timezone
1
+ from datetime import UTC, datetime
2
2
  from typing import Any
3
3
 
4
4
  import pytest
@@ -15,7 +15,7 @@ fxt = Fixtures("openshift_saas_deploy_trigger_cleaner")
15
15
 
16
16
  @pytest.fixture
17
17
  def now() -> datetime:
18
- return datetime(2024, 4, 4, 0, 0, 0, 0, tzinfo=timezone.utc)
18
+ return datetime(2024, 4, 4, 0, 0, 0, 0, tzinfo=UTC)
19
19
 
20
20
 
21
21
  # A fixture simulating the output of getting PipelineRuns from a namespace, simplified
@@ -3,11 +3,8 @@ from collections.abc import (
3
3
  Iterable,
4
4
  MutableMapping,
5
5
  )
6
- from datetime import datetime, timedelta, timezone
7
- from typing import (
8
- Any,
9
- Optional,
10
- )
6
+ from datetime import UTC, datetime, timedelta
7
+ from typing import Any
11
8
  from unittest import TestCase
12
9
  from unittest.mock import (
13
10
  MagicMock,
@@ -70,12 +67,12 @@ class MockSecretReader(SecretReaderBase):
70
67
  """
71
68
 
72
69
  def _read(
73
- self, path: str, field: str, format: Optional[str], version: Optional[int]
70
+ self, path: str, field: str, format: str | None, version: int | None
74
71
  ) -> str:
75
72
  return "secret"
76
73
 
77
74
  def _read_all(
78
- self, path: str, field: str, format: Optional[str], version: Optional[int]
75
+ self, path: str, field: str, format: str | None, version: int | None
79
76
  ) -> dict[str, str]:
80
77
  return {"param": "secret"}
81
78
 
@@ -88,7 +85,7 @@ def inject_gql_class_factory(
88
85
  def _gql_class_factory(
89
86
  self: Any,
90
87
  klass: type[BaseModel],
91
- data: Optional[MutableMapping[str, Any]] = None,
88
+ data: MutableMapping[str, Any] | None = None,
92
89
  ) -> BaseModel:
93
90
  return gql_class_factory(klass, data)
94
91
 
@@ -1230,14 +1227,14 @@ class TestSoakDays(TestCase):
1230
1227
  "saas_file": self.saas_file.name,
1231
1228
  "target_config_hash": "ed2af38cf21f268c",
1232
1229
  # the deployment happened 1 hour ago
1233
- "check_in": str(datetime.now(timezone.utc) - timedelta(hours=1)),
1230
+ "check_in": str(datetime.now(UTC) - timedelta(hours=1)),
1234
1231
  },
1235
1232
  {
1236
1233
  "success": True,
1237
1234
  "saas_file": self.saas_file.name,
1238
1235
  "target_config_hash": "ed2af38cf21f268c",
1239
1236
  # the deployment happened 47 hours ago
1240
- "check_in": str(datetime.now(timezone.utc) - timedelta(hours=47)),
1237
+ "check_in": str(datetime.now(UTC) - timedelta(hours=47)),
1241
1238
  },
1242
1239
  ]
1243
1240
  self.state_mock.get.side_effect = publisher_states
@@ -1254,14 +1251,14 @@ class TestSoakDays(TestCase):
1254
1251
  "saas_file": self.saas_file.name,
1255
1252
  "target_config_hash": "ed2af38cf21f268c",
1256
1253
  # the deployment happened 12 hours ago
1257
- "check_in": str(datetime.now(timezone.utc) - timedelta(hours=12)),
1254
+ "check_in": str(datetime.now(UTC) - timedelta(hours=12)),
1258
1255
  },
1259
1256
  {
1260
1257
  "success": True,
1261
1258
  "saas_file": self.saas_file.name,
1262
1259
  "target_config_hash": "ed2af38cf21f268c",
1263
1260
  # the deployment happened 1 hour ago
1264
- "check_in": str(datetime.now(timezone.utc) - timedelta(hours=1)),
1261
+ "check_in": str(datetime.now(UTC) - timedelta(hours=1)),
1265
1262
  },
1266
1263
  ]
1267
1264
  self.state_mock.get.side_effect = publisher_states
@@ -1,5 +1,3 @@
1
- from typing import Optional
2
-
3
1
  import pytest
4
2
  from pydantic import (
5
3
  BaseModel,
@@ -157,8 +155,8 @@ def test_permissions_workspace(
157
155
 
158
156
 
159
157
  class ClientGlobalConfig(BaseModel):
160
- max_retries: Optional[int]
161
- timeout: Optional[int]
158
+ max_retries: int | None
159
+ timeout: int | None
162
160
 
163
161
 
164
162
  class ClientMethodConfig(BaseModel):
@@ -167,8 +165,8 @@ class ClientMethodConfig(BaseModel):
167
165
 
168
166
 
169
167
  class ClientConfig(BaseModel):
170
- q_global: Optional[ClientGlobalConfig]
171
- methods: Optional[list[ClientMethodConfig]]
168
+ q_global: ClientGlobalConfig | None
169
+ methods: list[ClientMethodConfig] | None
172
170
 
173
171
 
174
172
  def test_get_slackapi():