qontract-reconcile 0.10.1rc879__py3-none-any.whl → 0.10.1rc894__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 (291) hide show
  1. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/METADATA +1 -1
  2. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/RECORD +291 -284
  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 +9 -14
  13. reconcile/aws_account_manager/reconciler.py +51 -1
  14. reconcile/aws_account_manager/utils.py +3 -0
  15. reconcile/aws_ami_cleanup/integration.py +3 -4
  16. reconcile/aws_iam_password_reset.py +2 -5
  17. reconcile/aws_version_sync/integration.py +2 -2
  18. reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
  19. reconcile/change_owners/approver.py +4 -5
  20. reconcile/change_owners/bundle.py +20 -22
  21. reconcile/change_owners/change_types.py +23 -24
  22. reconcile/change_owners/changes.py +13 -16
  23. reconcile/change_owners/decision.py +2 -5
  24. reconcile/change_owners/diff.py +11 -15
  25. reconcile/change_owners/self_service_roles.py +1 -2
  26. reconcile/change_owners/tester.py +7 -10
  27. reconcile/checkpoint.py +2 -5
  28. reconcile/cli.py +26 -12
  29. reconcile/closedbox_endpoint_monitoring_base.py +8 -11
  30. reconcile/cluster_deployment_mapper.py +2 -5
  31. reconcile/cna/assets/asset.py +4 -7
  32. reconcile/cna/assets/null.py +2 -5
  33. reconcile/cna/integration.py +2 -3
  34. reconcile/cna/state.py +2 -5
  35. reconcile/dashdotdb_base.py +8 -11
  36. reconcile/dashdotdb_cso.py +3 -6
  37. reconcile/dashdotdb_dora.py +10 -14
  38. reconcile/dashdotdb_dvo.py +10 -13
  39. reconcile/dashdotdb_slo.py +5 -8
  40. reconcile/database_access_manager.py +5 -6
  41. reconcile/dynatrace_token_provider/integration.py +3 -6
  42. reconcile/dynatrace_token_provider/integration_v2.py +20 -0
  43. reconcile/dynatrace_token_provider/meta.py +1 -0
  44. reconcile/external_resources/integration.py +1 -1
  45. reconcile/external_resources/manager.py +4 -4
  46. reconcile/external_resources/model.py +3 -3
  47. reconcile/external_resources/secrets_sync.py +5 -5
  48. reconcile/external_resources/state.py +5 -5
  49. reconcile/gabi_authorized_users.py +3 -6
  50. reconcile/gcr_mirror.py +1 -1
  51. reconcile/github_org.py +1 -3
  52. reconcile/github_repo_invites.py +2 -5
  53. reconcile/gitlab_housekeeping.py +7 -11
  54. reconcile/gitlab_labeler.py +1 -2
  55. reconcile/gitlab_members.py +2 -5
  56. reconcile/gitlab_permissions.py +1 -3
  57. reconcile/glitchtip/integration.py +5 -8
  58. reconcile/glitchtip_project_alerts/integration.py +57 -33
  59. reconcile/glitchtip_project_dsn/integration.py +8 -11
  60. reconcile/gql_definitions/aws_account_manager/aws_accounts.py +6 -0
  61. reconcile/gql_definitions/fragments/aws_account_managed.py +8 -0
  62. reconcile/gql_definitions/glitchtip/glitchtip_project.py +4 -4
  63. reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +27 -7
  64. reconcile/integrations_manager.py +5 -8
  65. reconcile/jenkins/types.py +5 -6
  66. reconcile/jenkins_job_builder.py +9 -12
  67. reconcile/jenkins_roles.py +1 -1
  68. reconcile/jira_watcher.py +2 -2
  69. reconcile/ldap_groups/integration.py +2 -5
  70. reconcile/ocm/types.py +21 -26
  71. reconcile/ocm_addons_upgrade_tests_trigger.py +3 -6
  72. reconcile/ocm_clusters.py +8 -8
  73. reconcile/ocm_internal_notifications/integration.py +1 -2
  74. reconcile/ocm_labels/integration.py +2 -5
  75. reconcile/ocm_machine_pools.py +11 -15
  76. reconcile/ocm_upgrade_scheduler_org_updater.py +2 -5
  77. reconcile/openshift_base.py +29 -30
  78. reconcile/openshift_groups.py +15 -20
  79. reconcile/openshift_namespace_labels.py +8 -14
  80. reconcile/openshift_namespaces.py +5 -8
  81. reconcile/openshift_network_policies.py +2 -4
  82. reconcile/openshift_resources_base.py +19 -29
  83. reconcile/openshift_saas_deploy.py +9 -10
  84. reconcile/openshift_saas_deploy_change_tester.py +7 -10
  85. reconcile/openshift_saas_deploy_trigger_base.py +4 -7
  86. reconcile/openshift_saas_deploy_trigger_cleaner.py +5 -8
  87. reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
  88. reconcile/openshift_saas_deploy_trigger_images.py +1 -2
  89. reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
  90. reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
  91. reconcile/openshift_tekton_resources.py +7 -11
  92. reconcile/openshift_upgrade_watcher.py +10 -13
  93. reconcile/openshift_users.py +8 -11
  94. reconcile/oum/base.py +3 -4
  95. reconcile/oum/labelset.py +1 -2
  96. reconcile/oum/metrics.py +2 -2
  97. reconcile/oum/models.py +1 -2
  98. reconcile/oum/standalone.py +2 -3
  99. reconcile/prometheus_rules_tester/integration.py +6 -9
  100. reconcile/quay_membership.py +1 -2
  101. reconcile/quay_mirror.py +12 -13
  102. reconcile/quay_mirror_org.py +10 -10
  103. reconcile/queries.py +4 -7
  104. reconcile/resource_scraper.py +3 -4
  105. reconcile/rhidp/common.py +2 -2
  106. reconcile/saas_auto_promotions_manager/integration.py +5 -6
  107. reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +1 -2
  108. reconcile/saas_auto_promotions_manager/publisher.py +5 -6
  109. reconcile/saas_auto_promotions_manager/subscriber.py +36 -15
  110. reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +8 -0
  111. reconcile/saas_file_validator.py +2 -5
  112. reconcile/signalfx_endpoint_monitoring.py +2 -5
  113. reconcile/skupper_network/integration.py +3 -6
  114. reconcile/skupper_network/models.py +3 -5
  115. reconcile/slack_base.py +4 -7
  116. reconcile/slack_usergroups.py +15 -17
  117. reconcile/sql_query.py +5 -9
  118. reconcile/status_board.py +4 -5
  119. reconcile/statuspage/atlassian.py +14 -15
  120. reconcile/statuspage/integrations/maintenances.py +3 -3
  121. reconcile/statuspage/page.py +8 -8
  122. reconcile/statuspage/state.py +4 -5
  123. reconcile/statuspage/status.py +7 -8
  124. reconcile/templating/lib/rendering.py +8 -8
  125. reconcile/templating/renderer.py +10 -11
  126. reconcile/templating/validator.py +4 -4
  127. reconcile/terraform_aws_route53.py +3 -6
  128. reconcile/terraform_cloudflare_dns.py +9 -12
  129. reconcile/terraform_cloudflare_resources.py +9 -11
  130. reconcile/terraform_cloudflare_users.py +8 -11
  131. reconcile/terraform_init/integration.py +2 -2
  132. reconcile/terraform_repo.py +11 -14
  133. reconcile/terraform_resources.py +20 -21
  134. reconcile/terraform_tgw_attachments.py +32 -36
  135. reconcile/terraform_users.py +6 -7
  136. reconcile/terraform_vpc_resources/integration.py +6 -6
  137. reconcile/test/conftest.py +7 -10
  138. reconcile/test/fixtures.py +1 -1
  139. reconcile/test/saas_auto_promotions_manager/conftest.py +3 -2
  140. reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
  141. reconcile/test/test_database_access_manager.py +3 -6
  142. reconcile/test/test_gitlab_labeler.py +2 -5
  143. reconcile/test/test_jump_host.py +5 -8
  144. reconcile/test/test_ocm_machine_pools.py +1 -4
  145. reconcile/test/test_openshift_base.py +3 -6
  146. reconcile/test/test_openshift_cluster_bots.py +5 -5
  147. reconcile/test/test_openshift_namespace_labels.py +2 -3
  148. reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +2 -2
  149. reconcile/test/test_saasherder.py +9 -12
  150. reconcile/test/test_slack_base.py +4 -6
  151. reconcile/test/test_status_board.py +4 -7
  152. reconcile/test/test_terraform_tgw_attachments.py +14 -20
  153. reconcile/typed_queries/alerting_services_settings.py +1 -2
  154. reconcile/typed_queries/app_interface_custom_messages.py +2 -3
  155. reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -3
  156. reconcile/typed_queries/app_interface_repo_url.py +1 -2
  157. reconcile/typed_queries/app_interface_state_settings.py +1 -3
  158. reconcile/typed_queries/app_interface_vault_settings.py +1 -2
  159. reconcile/typed_queries/aws_vpc_requests.py +1 -3
  160. reconcile/typed_queries/aws_vpcs.py +1 -3
  161. reconcile/typed_queries/clusters.py +2 -4
  162. reconcile/typed_queries/clusters_minimal.py +1 -3
  163. reconcile/typed_queries/clusters_with_dms.py +1 -3
  164. reconcile/typed_queries/dynatrace_environments.py +14 -0
  165. reconcile/typed_queries/external_resources.py +3 -4
  166. reconcile/typed_queries/pagerduty_instances.py +1 -2
  167. reconcile/typed_queries/repos.py +2 -3
  168. reconcile/typed_queries/reserved_networks.py +1 -3
  169. reconcile/typed_queries/saas_files.py +49 -59
  170. reconcile/typed_queries/slo_documents.py +1 -3
  171. reconcile/typed_queries/status_board.py +3 -7
  172. reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
  173. reconcile/typed_queries/terraform_namespaces.py +1 -2
  174. reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +1 -3
  175. reconcile/utils/acs/base.py +2 -3
  176. reconcile/utils/acs/notifiers.py +3 -3
  177. reconcile/utils/acs/policies.py +3 -3
  178. reconcile/utils/aggregated_list.py +1 -1
  179. reconcile/utils/amtool.py +1 -2
  180. reconcile/utils/aws_api.py +28 -31
  181. reconcile/utils/aws_api_typed/account.py +23 -0
  182. reconcile/utils/aws_api_typed/api.py +20 -9
  183. reconcile/utils/binary.py +1 -3
  184. reconcile/utils/clusterhealth/providerbase.py +1 -2
  185. reconcile/utils/clusterhealth/telemeter.py +2 -2
  186. reconcile/utils/deadmanssnitch_api.py +1 -2
  187. reconcile/utils/disabled_integrations.py +4 -6
  188. reconcile/utils/environ.py +1 -1
  189. reconcile/utils/expiration.py +3 -7
  190. reconcile/utils/external_resource_spec.py +3 -4
  191. reconcile/utils/external_resources.py +4 -7
  192. reconcile/utils/filtering.py +1 -2
  193. reconcile/utils/git.py +3 -9
  194. reconcile/utils/git_secrets.py +5 -5
  195. reconcile/utils/github_api.py +5 -9
  196. reconcile/utils/gitlab_api.py +2 -3
  197. reconcile/utils/glitchtip/client.py +2 -4
  198. reconcile/utils/glitchtip/models.py +8 -11
  199. reconcile/utils/gql.py +26 -35
  200. reconcile/utils/grouping.py +1 -3
  201. reconcile/utils/imap_client.py +2 -5
  202. reconcile/utils/internal_groups/client.py +1 -2
  203. reconcile/utils/internal_groups/models.py +8 -9
  204. reconcile/utils/jenkins_api.py +4 -4
  205. reconcile/utils/jinja2/extensions.py +1 -1
  206. reconcile/utils/jinja2/filters.py +4 -4
  207. reconcile/utils/jinja2/utils.py +16 -16
  208. reconcile/utils/jira_client.py +10 -11
  209. reconcile/utils/jjb_client.py +14 -17
  210. reconcile/utils/jobcontroller/controller.py +5 -5
  211. reconcile/utils/jobcontroller/models.py +2 -2
  212. reconcile/utils/jsonpath.py +4 -5
  213. reconcile/utils/jump_host.py +7 -8
  214. reconcile/utils/keycloak.py +3 -7
  215. reconcile/utils/ldap_client.py +2 -3
  216. reconcile/utils/lean_terraform_client.py +13 -17
  217. reconcile/utils/membershipsources/app_interface_resolver.py +1 -1
  218. reconcile/utils/membershipsources/models.py +19 -22
  219. reconcile/utils/metrics.py +13 -15
  220. reconcile/utils/mr/base.py +7 -11
  221. reconcile/utils/mr/glitchtip_access_reporter.py +2 -2
  222. reconcile/utils/mr/notificator.py +1 -2
  223. reconcile/utils/oc.py +38 -38
  224. reconcile/utils/oc_connection_parameters.py +24 -25
  225. reconcile/utils/oc_filters.py +2 -3
  226. reconcile/utils/oc_map.py +9 -15
  227. reconcile/utils/ocm/addons.py +7 -10
  228. reconcile/utils/ocm/base.py +38 -39
  229. reconcile/utils/ocm/clusters.py +6 -9
  230. reconcile/utils/ocm/label_sources.py +1 -2
  231. reconcile/utils/ocm/labels.py +3 -6
  232. reconcile/utils/ocm/ocm.py +11 -14
  233. reconcile/utils/ocm/products.py +1 -3
  234. reconcile/utils/ocm/search_filters.py +16 -17
  235. reconcile/utils/ocm/service_log.py +2 -3
  236. reconcile/utils/ocm/sre_capability_labels.py +4 -8
  237. reconcile/utils/ocm/subscriptions.py +1 -3
  238. reconcile/utils/ocm/syncsets.py +2 -4
  239. reconcile/utils/ocm/upgrades.py +5 -9
  240. reconcile/utils/ocm_base_client.py +13 -16
  241. reconcile/utils/openshift_resource.py +5 -11
  242. reconcile/utils/output.py +2 -3
  243. reconcile/utils/pagerduty_api.py +4 -5
  244. reconcile/utils/prometheus.py +2 -2
  245. reconcile/utils/promotion_state.py +4 -5
  246. reconcile/utils/promtool.py +2 -8
  247. reconcile/utils/quay_api.py +12 -22
  248. reconcile/utils/raw_github_api.py +3 -5
  249. reconcile/utils/rosa/rosa_cli.py +6 -6
  250. reconcile/utils/rosa/session.py +6 -7
  251. reconcile/utils/runtime/desired_state_diff.py +3 -8
  252. reconcile/utils/runtime/environment.py +4 -7
  253. reconcile/utils/runtime/integration.py +4 -4
  254. reconcile/utils/runtime/meta.py +1 -2
  255. reconcile/utils/runtime/runner.py +7 -10
  256. reconcile/utils/runtime/sharding.py +22 -27
  257. reconcile/utils/saasherder/interfaces.py +63 -69
  258. reconcile/utils/saasherder/models.py +30 -35
  259. reconcile/utils/saasherder/saasherder.py +39 -54
  260. reconcile/utils/secret_reader.py +17 -19
  261. reconcile/utils/slack_api.py +15 -17
  262. reconcile/utils/smtp_client.py +1 -2
  263. reconcile/utils/sqs_gateway.py +1 -3
  264. reconcile/utils/state.py +1 -2
  265. reconcile/utils/terraform/config_client.py +4 -5
  266. reconcile/utils/terraform_client.py +12 -8
  267. reconcile/utils/terrascript/cloudflare_client.py +4 -10
  268. reconcile/utils/terrascript/cloudflare_resources.py +10 -13
  269. reconcile/utils/terrascript/models.py +2 -3
  270. reconcile/utils/terrascript/resources.py +1 -2
  271. reconcile/utils/terrascript_aws_client.py +50 -38
  272. reconcile/utils/unleash/client.py +4 -7
  273. reconcile/utils/unleash/server.py +2 -2
  274. reconcile/utils/vault.py +8 -11
  275. reconcile/utils/vaultsecretref.py +2 -3
  276. reconcile/utils/vcs.py +7 -8
  277. reconcile/vault_replication.py +4 -8
  278. reconcile/vpc_peerings_validator.py +4 -9
  279. release/version.py +6 -7
  280. tools/app_interface_reporter.py +2 -2
  281. tools/cli_commands/gpg_encrypt.py +3 -6
  282. tools/cli_commands/systems_and_tools.py +4 -7
  283. tools/qontract_cli.py +105 -17
  284. tools/saas_promotion_state/__init__.py +0 -0
  285. tools/saas_promotion_state/saas_promotion_state.py +105 -0
  286. tools/template_validation.py +1 -1
  287. tools/test/conftest.py +45 -6
  288. tools/test/test_saas_promotion_state.py +187 -0
  289. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/WHEEL +0 -0
  290. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/entry_points.txt +0 -0
  291. {qontract_reconcile-0.10.1rc879.dist-info → qontract_reconcile-0.10.1rc894.dist-info}/top_level.txt +0 -0
@@ -3,10 +3,7 @@ import logging
3
3
  from collections import defaultdict
4
4
  from collections.abc import Callable
5
5
  from dataclasses import field
6
- from typing import (
7
- Any,
8
- Optional,
9
- )
6
+ from typing import Any
10
7
  from urllib.parse import urlparse
11
8
 
12
9
  from pydantic.dataclasses import dataclass
@@ -49,14 +46,14 @@ class EndpointMonitoringProvider:
49
46
  name: str
50
47
  provider: str
51
48
  description: str
52
- timeout: Optional[str] = None
53
- checkInterval: Optional[str] = None
54
- blackboxExporter: Optional[BlackboxMonitoringProvider] = None
55
- signalFx: Optional[SignalfxMonitoringProvier] = None
56
- metricLabels: Optional[str] = None
49
+ timeout: str | None = None
50
+ checkInterval: str | None = None
51
+ blackboxExporter: BlackboxMonitoringProvider | None = None
52
+ signalFx: SignalfxMonitoringProvier | None = None
53
+ metricLabels: str | None = None
57
54
 
58
55
  @property
59
- def namespace(self) -> Optional[dict[str, Any]]:
56
+ def namespace(self) -> dict[str, Any] | None:
60
57
  if self.blackboxExporter:
61
58
  return self.blackboxExporter.namespace
62
59
 
@@ -131,7 +128,7 @@ def fill_desired_state(
131
128
  def run_for_provider(
132
129
  provider: str,
133
130
  probe_builder: Callable[
134
- [EndpointMonitoringProvider, list[Endpoint]], Optional[OpenshiftResource]
131
+ [EndpointMonitoringProvider, list[Endpoint]], OpenshiftResource | None
135
132
  ],
136
133
  integration: str,
137
134
  integration_version: str,
@@ -1,9 +1,6 @@
1
1
  import logging
2
2
  import sys
3
- from typing import (
4
- Any,
5
- Optional,
6
- )
3
+ from typing import Any
7
4
 
8
5
  from reconcile.status import ExitCodes
9
6
  from reconcile.typed_queries.app_interface_vault_settings import (
@@ -18,7 +15,7 @@ from reconcile.utils.vault import VaultClient
18
15
  QONTRACT_INTEGRATION = "cluster-deployment-mapper"
19
16
 
20
17
 
21
- def run(dry_run: bool, vault_output_path: Optional[str]) -> None:
18
+ def run(dry_run: bool, vault_output_path: str | None) -> None:
22
19
  """Get Hive ClusterDeployments from clusters and save mapping to Vault"""
23
20
  if not vault_output_path:
24
21
  logging.error("must supply vault output path")
@@ -9,10 +9,7 @@ from dataclasses import (
9
9
  field,
10
10
  )
11
11
  from enum import Enum
12
- from typing import (
13
- Any,
14
- Optional,
15
- )
12
+ from typing import Any
16
13
 
17
14
 
18
15
  class AssetError(Exception):
@@ -31,9 +28,9 @@ class AssetStatus(Enum):
31
28
 
32
29
  @dataclass(frozen=True)
33
30
  class Asset(ABC):
34
- uuid: Optional[str] = field(compare=False, hash=True)
35
- href: Optional[str] = field(compare=False, hash=True)
36
- status: Optional[AssetStatus] = field(compare=False, hash=True)
31
+ uuid: str | None = field(compare=False, hash=True)
32
+ href: str | None = field(compare=False, hash=True)
33
+ status: AssetStatus | None = field(compare=False, hash=True)
37
34
  name: str
38
35
  kind: AssetType
39
36
 
@@ -2,10 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Mapping
4
4
  from dataclasses import dataclass
5
- from typing import (
6
- Any,
7
- Optional,
8
- )
5
+ from typing import Any
9
6
 
10
7
  from reconcile.cna.assets.asset import (
11
8
  Asset,
@@ -18,7 +15,7 @@ from reconcile.gql_definitions.cna.queries.cna_resources import CNANullAssetV1
18
15
 
19
16
  @dataclass(frozen=True)
20
17
  class NullAsset(Asset):
21
- addr_block: Optional[str]
18
+ addr_block: str | None
22
19
 
23
20
  def api_payload(self) -> dict[str, Any]:
24
21
  return {
@@ -3,7 +3,6 @@ from collections.abc import (
3
3
  Iterable,
4
4
  Mapping,
5
5
  )
6
- from typing import Optional
7
6
 
8
7
  from reconcile.cna.assets.asset_factory import asset_factory_from_schema
9
8
  from reconcile.cna.client import CNAClient
@@ -45,8 +44,8 @@ class CNAIntegration:
45
44
  self,
46
45
  cna_clients: Mapping[str, CNAClient],
47
46
  namespaces: Iterable[NamespaceV1],
48
- desired_states: Optional[Mapping[str, State]] = None,
49
- current_states: Optional[Mapping[str, State]] = None,
47
+ desired_states: Mapping[str, State] | None = None,
48
+ current_states: Mapping[str, State] | None = None,
50
49
  ):
51
50
  self._cna_clients = cna_clients
52
51
  self._namespaces = namespaces
reconcile/cna/state.py CHANGED
@@ -4,10 +4,7 @@ from collections.abc import (
4
4
  Iterable,
5
5
  Mapping,
6
6
  )
7
- from typing import (
8
- Any,
9
- Optional,
10
- )
7
+ from typing import Any
11
8
 
12
9
  from reconcile.cna.assets.asset import (
13
10
  Asset,
@@ -29,7 +26,7 @@ class State:
29
26
  deletions and updates to reach another state.
30
27
  """
31
28
 
32
- def __init__(self, assets: Optional[dict[AssetType, dict[str, Asset]]] = None):
29
+ def __init__(self, assets: dict[AssetType, dict[str, Asset]] | None = None):
33
30
  self._assets: dict[AssetType, dict[str, Asset]] = {}
34
31
  for kind in AssetType:
35
32
  self._assets[kind] = {}
@@ -3,10 +3,7 @@ import os
3
3
  from base64 import b64encode
4
4
  from collections.abc import Mapping
5
5
  from dataclasses import dataclass
6
- from typing import (
7
- Any,
8
- Optional,
9
- )
6
+ from typing import Any
10
7
  from urllib.parse import urljoin
11
8
 
12
9
  import requests
@@ -23,8 +20,8 @@ LOG = logging.getLogger(__name__)
23
20
  class DashdotDBSecret:
24
21
  path: str
25
22
  field: str
26
- q_format: Optional[str]
27
- version: Optional[int]
23
+ q_format: str | None
24
+ version: int | None
28
25
 
29
26
 
30
27
  DASHDOTDB_SECRET = DashdotDBSecret(
@@ -53,7 +50,7 @@ class DashdotdbBase:
53
50
  self.dashdotdb_pass = self.secret_content["password"]
54
51
  self.logmarker = marker
55
52
  self.scope = scope
56
- self.dashdotdb_token = Optional[str]
53
+ self.dashdotdb_token: str | None
57
54
 
58
55
  def _get_token(self) -> None:
59
56
  if self.dry_run:
@@ -134,10 +131,10 @@ class DashdotdbBase:
134
131
  def _promget(
135
132
  self,
136
133
  url: str,
137
- params: Optional[Mapping[Any, Any]],
138
- token: Optional[str] = None,
139
- username: Optional[str] = None,
140
- password: Optional[str] = None,
134
+ params: Mapping[Any, Any] | None,
135
+ token: str | None = None,
136
+ username: str | None = None,
137
+ password: str | None = None,
141
138
  ssl_verify: bool = True,
142
139
  uri: str = "api/v1/query",
143
140
  ) -> dict[Any, Any]:
@@ -1,7 +1,4 @@
1
- from typing import (
2
- Any,
3
- Optional,
4
- )
1
+ from typing import Any
5
2
 
6
3
  import requests
7
4
  from sretoolbox.utils import threaded
@@ -44,7 +41,7 @@ class DashdotdbCSO(DashdotdbBase):
44
41
  secret_reader=secret_reader,
45
42
  )
46
43
 
47
- def _post(self, manifest: dict[Any, Any]) -> Optional[requests.Response]:
44
+ def _post(self, manifest: dict[Any, Any]) -> requests.Response | None:
48
45
  if manifest is None:
49
46
  return None
50
47
 
@@ -70,7 +67,7 @@ class DashdotdbCSO(DashdotdbBase):
70
67
  return response
71
68
 
72
69
  @staticmethod
73
- def _get_imagemanifestvuln(cluster: str, oc_map: OCMap) -> Optional[dict[str, Any]]:
70
+ def _get_imagemanifestvuln(cluster: str, oc_map: OCMap) -> dict[str, Any] | None:
74
71
  LOG.info("%s processing %s", LOGMARKER, cluster)
75
72
  oc = oc_map.get(cluster)
76
73
  if isinstance(oc, OCLogMsg):
@@ -1,17 +1,15 @@
1
1
  import functools
2
2
  import os
3
3
  from collections import defaultdict
4
+ from collections.abc import Iterable, Mapping
4
5
  from dataclasses import dataclass
5
6
  from datetime import (
7
+ UTC,
6
8
  datetime,
7
9
  timedelta,
8
- timezone,
9
10
  )
10
11
  from typing import (
11
12
  Any,
12
- Iterable,
13
- Mapping,
14
- Optional,
15
13
  Self,
16
14
  )
17
15
 
@@ -44,8 +42,8 @@ QONTRACT_INTEGRATION = "dashdotdb-dora"
44
42
  class DeploymentDBSecret:
45
43
  path: str
46
44
  field: str
47
- q_format: Optional[str]
48
- version: Optional[int]
45
+ q_format: str | None
46
+ version: int | None
49
47
 
50
48
 
51
49
  @dataclass(eq=True, frozen=True)
@@ -76,9 +74,9 @@ class SaasTarget:
76
74
 
77
75
  @dataclass(eq=True, frozen=True)
78
76
  class RepoChanges:
79
- repo_url: Optional[str]
80
- ref_from: Optional[str]
81
- ref_to: Optional[str]
77
+ repo_url: str | None
78
+ ref_from: str | None
79
+ ref_to: str | None
82
80
 
83
81
 
84
82
  @dataclass(eq=True, frozen=True)
@@ -162,12 +160,10 @@ class Commit:
162
160
  finish_timestamp_tzaware = finish_timestamp
163
161
 
164
162
  if commit_date_tzaware.tzinfo is None:
165
- commit_date_tzaware = commit_date_tzaware.replace(tzinfo=timezone.utc)
163
+ commit_date_tzaware = commit_date_tzaware.replace(tzinfo=UTC)
166
164
 
167
165
  if finish_timestamp_tzaware.tzinfo is None:
168
- finish_timestamp_tzaware = finish_timestamp_tzaware.replace(
169
- tzinfo=timezone.utc
170
- )
166
+ finish_timestamp_tzaware = finish_timestamp_tzaware.replace(tzinfo=UTC)
171
167
 
172
168
  return int((finish_timestamp_tzaware - commit_date_tzaware).total_seconds())
173
169
 
@@ -397,7 +393,7 @@ class DashdotdbDORA(DashdotdbBase):
397
393
 
398
394
  def get_repo_ref_for_sha(
399
395
  self, saastarget: SaasTarget, sha: str
400
- ) -> tuple[Optional[str], Optional[str]]:
396
+ ) -> tuple[str | None, str | None]:
401
397
  try:
402
398
  saas_file_yaml = self.gl_app_interface_get_file(
403
399
  saastarget.path, ref=sha
@@ -4,10 +4,7 @@ from collections.abc import (
4
4
  Sequence,
5
5
  )
6
6
  from dataclasses import dataclass
7
- from typing import (
8
- Any,
9
- Optional,
10
- )
7
+ from typing import Any
11
8
 
12
9
  import requests
13
10
  from requests import Response
@@ -67,7 +64,7 @@ class DashdotdbDVO(DashdotdbBase):
67
64
  for i in range(0, len(data), int(size)):
68
65
  yield data[i : i + int(size)]
69
66
 
70
- def _post(self, deploymentvalidation: DVOPayload) -> Optional[Response]:
67
+ def _post(self, deploymentvalidation: DVOPayload) -> Response | None:
71
68
  if deploymentvalidation is None:
72
69
  return
73
70
  cluster_name = deploymentvalidation.cluster_name
@@ -130,7 +127,7 @@ class DashdotdbDVO(DashdotdbBase):
130
127
 
131
128
  def _get_deploymentvalidation(
132
129
  self, metrics: list[str], cluster: ClusterV1
133
- ) -> Optional[DVOPayload]:
130
+ ) -> DVOPayload | None:
134
131
  prom_info = self._get_prometheus_info(cluster)
135
132
  if not prom_info:
136
133
  return None
@@ -162,8 +159,8 @@ class DashdotdbDVO(DashdotdbBase):
162
159
  # via startswith and return only those that match.
163
160
  # Returns a map of {cluster: cluster_name, data: [metric_names]}
164
161
  def _get_validation_names(
165
- self, cluster: ClusterV1, filter: Optional[str] = None
166
- ) -> Optional[ClusterValidationMetrics]:
162
+ self, cluster: ClusterV1, filter: str | None = None
163
+ ) -> ClusterValidationMetrics | None:
167
164
  prom_info = self._get_prometheus_info(cluster)
168
165
  if not prom_info:
169
166
  return None
@@ -202,7 +199,7 @@ class DashdotdbDVO(DashdotdbBase):
202
199
  metrics=deploymentvalidation["data"],
203
200
  )
204
201
 
205
- def _get_prometheus_info(self, cluster: ClusterV1) -> Optional[PrometheusInfo]:
202
+ def _get_prometheus_info(self, cluster: ClusterV1) -> PrometheusInfo | None:
206
203
  if not cluster.automation_token:
207
204
  LOG.error(
208
205
  "%s cluster %s does not have an automation token",
@@ -217,14 +214,14 @@ class DashdotdbDVO(DashdotdbBase):
217
214
  )
218
215
 
219
216
  @staticmethod
220
- def _get_clusters(name: Optional[str] = None) -> list[ClusterV1]:
217
+ def _get_clusters(name: str | None = None) -> list[ClusterV1]:
221
218
  return [
222
219
  c for c in get_clusters_minimal(name=name) if c.ocm and c.prometheus_url
223
220
  ]
224
221
 
225
- def run(self, cname: Optional[str] = None) -> None:
222
+ def run(self, cname: str | None = None) -> None:
226
223
  clusters = self._get_clusters(name=cname)
227
- validation_list: list[Optional[ClusterValidationMetrics]] = threaded.run(
224
+ validation_list: list[ClusterValidationMetrics | None] = threaded.run(
228
225
  func=self._get_validation_names,
229
226
  iterable=clusters,
230
227
  thread_pool_size=self.thread_pool_size,
@@ -258,7 +255,7 @@ class DashdotdbDVO(DashdotdbBase):
258
255
  def run(
259
256
  dry_run: bool = False,
260
257
  thread_pool_size: int = 10,
261
- cluster_name: Optional[str] = None,
258
+ cluster_name: str | None = None,
262
259
  ) -> None:
263
260
  vault_settings = get_app_interface_vault_settings()
264
261
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
@@ -1,9 +1,6 @@
1
1
  from collections.abc import Iterable
2
2
  from dataclasses import dataclass
3
- from typing import (
4
- Any,
5
- Optional,
6
- )
3
+ from typing import Any
7
4
 
8
5
  import jinja2
9
6
  import requests
@@ -72,7 +69,7 @@ class DashdotdbSLO(DashdotdbBase):
72
69
  secret_reader=secret_reader,
73
70
  )
74
71
 
75
- def _post(self, service_slos: Iterable[ServiceSLO]) -> Optional[Response]:
72
+ def _post(self, service_slos: Iterable[ServiceSLO]) -> Response | None:
76
73
  for item in service_slos:
77
74
  LOG.debug(f"About to POST SLO JSON item to dashdotDB:\n{item}\n")
78
75
 
@@ -106,9 +103,9 @@ class DashdotdbSLO(DashdotdbBase):
106
103
  continue
107
104
 
108
105
  ns = namespace_access.namespace
109
- promtoken: Optional[str] = None
110
- username: Optional[str] = None
111
- password: Optional[str] = None
106
+ promtoken: str | None = None
107
+ username: str | None = None
108
+ password: str | None = None
112
109
  if namespace_access.prometheus_access:
113
110
  promurl = namespace_access.prometheus_access.url
114
111
  username = self.secret_reader.read_secret(
@@ -1,5 +1,6 @@
1
1
  import base64
2
2
  import logging
3
+ from collections.abc import Callable
3
4
  from random import choices
4
5
  from string import (
5
6
  ascii_letters,
@@ -7,8 +8,6 @@ from string import (
7
8
  )
8
9
  from typing import (
9
10
  Any,
10
- Callable,
11
- Optional,
12
11
  TypedDict,
13
12
  cast,
14
13
  )
@@ -57,7 +56,7 @@ JOB_PSQL_ENGINE_VERSION = "15.4-alpine"
57
56
 
58
57
 
59
58
  def get_database_access_namespaces(
60
- query_func: Optional[Callable] = None,
59
+ query_func: Callable | None = None,
61
60
  ) -> list[NamespaceV1]:
62
61
  if not query_func:
63
62
  query_func = gql.get_api().query
@@ -74,7 +73,7 @@ class DatabaseConnectionParameters(BaseModel):
74
73
 
75
74
  class PSQLScriptGenerator(BaseModel):
76
75
  db_access: DatabaseAccessV1
77
- current_db_access: Optional[DatabaseAccessV1]
76
+ current_db_access: DatabaseAccessV1 | None
78
77
  connection_parameter: DatabaseConnectionParameters
79
78
  admin_connection_parameter: DatabaseConnectionParameters
80
79
  engine: str
@@ -426,7 +425,7 @@ def _populate_resources(
426
425
  settings: dict[Any, Any],
427
426
  user_connection: DatabaseConnectionParameters,
428
427
  admin_connection: DatabaseConnectionParameters,
429
- current_db_access: Optional[DatabaseAccessV1] = None,
428
+ current_db_access: DatabaseAccessV1 | None = None,
430
429
  ) -> list[DBAMResource]:
431
430
  if user_connection.database == admin_connection.database:
432
431
  raise ValueError(f"Can not use default database {admin_connection.database}")
@@ -594,7 +593,7 @@ def _process_db_access(
594
593
  if not _db_access_acccess_is_valid(db_access):
595
594
  raise ValueError("Duplicate schema in access list.")
596
595
 
597
- current_db_access: Optional[DatabaseAccessV1] = None
596
+ current_db_access: DatabaseAccessV1 | None = None
598
597
  if state.exists(db_access.name):
599
598
  current_state = state.get(db_access.name)
600
599
  if current_state == db_access.dict(by_alias=True):
@@ -1,16 +1,14 @@
1
1
  import base64
2
2
  import logging
3
3
  import sys
4
- from collections.abc import Iterable
4
+ from collections.abc import Iterable, Mapping
5
5
  from datetime import timedelta
6
- from typing import (
7
- Any,
8
- Mapping,
9
- )
6
+ from typing import Any
10
7
 
11
8
  from dynatrace import Dynatrace
12
9
  from dynatrace.environment_v2.tokens_api import ApiTokenCreated
13
10
 
11
+ from reconcile.dynatrace_token_provider.meta import QONTRACT_INTEGRATION
14
12
  from reconcile.dynatrace_token_provider.metrics import (
15
13
  DTPClustersManagedGauge,
16
14
  DTPOrganizationErrorRate,
@@ -55,7 +53,6 @@ from reconcile.utils.runtime.integration import (
55
53
  )
56
54
  from reconcile.utils.secret_reader import SecretReaderBase
57
55
 
58
- QONTRACT_INTEGRATION = "dynatrace-token-provider"
59
56
  SYNCSET_ID = "ext-dynatrace-tokens-dtp"
60
57
  SECRET_NAME = "dynatrace-token-dtp"
61
58
  SECRET_NAMESPACE = "dynatrace"
@@ -0,0 +1,20 @@
1
+ from reconcile.dynatrace_token_provider.meta import QONTRACT_INTEGRATION
2
+ from reconcile.utils.runtime.integration import (
3
+ PydanticRunParams,
4
+ QontractReconcileIntegration,
5
+ )
6
+
7
+
8
+ class DynatraceTokenProviderIntegrationParamsV2(PydanticRunParams):
9
+ ocm_organization_ids: set[str] | None = None
10
+
11
+
12
+ class DynatraceTokenProviderIntegrationV2(
13
+ QontractReconcileIntegration[DynatraceTokenProviderIntegrationParamsV2]
14
+ ):
15
+ @property
16
+ def name(self) -> str:
17
+ return QONTRACT_INTEGRATION
18
+
19
+ def run(self, dry_run: bool) -> None:
20
+ pass
@@ -0,0 +1 @@
1
+ QONTRACT_INTEGRATION = "dynatrace-token-provider"
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from typing import Callable
2
+ from collections.abc import Callable
3
3
 
4
4
  from reconcile.external_resources.manager import (
5
5
  ExternalResourcesInventory,
@@ -1,8 +1,8 @@
1
1
  import json
2
2
  import logging
3
3
  from collections.abc import Iterable
4
- from datetime import datetime, timezone
5
- from enum import Enum
4
+ from datetime import UTC, datetime
5
+ from enum import StrEnum
6
6
 
7
7
  from sretoolbox.utils import threaded
8
8
 
@@ -73,7 +73,7 @@ def setup_factories(
73
73
  return of
74
74
 
75
75
 
76
- class ReconcileAction(str, Enum):
76
+ class ReconcileAction(StrEnum):
77
77
  NOOP = "NOOP"
78
78
  APPLY_NOT_EXISTS = "Resource does not exist"
79
79
  APPLY_ERROR = "Resource status in ERROR state"
@@ -260,7 +260,7 @@ class ExternalResourcesManager:
260
260
  return need_secret_sync
261
261
 
262
262
  def _update_state(self, r: Reconciliation, state: ExternalResourceState) -> None:
263
- state.ts = datetime.now(timezone.utc)
263
+ state.ts = datetime.now(UTC)
264
264
  if r.action == Action.APPLY:
265
265
  state.resource_status = ResourceStatus.IN_PROGRESS
266
266
  elif r.action == Action.DESTROY:
@@ -9,7 +9,7 @@ from collections.abc import (
9
9
  Iterator,
10
10
  MutableMapping,
11
11
  )
12
- from enum import Enum
12
+ from enum import StrEnum
13
13
  from typing import Any
14
14
 
15
15
  from pydantic import BaseModel
@@ -82,7 +82,7 @@ class ExternalResourcesInventory(MutableMapping):
82
82
  for (p, ns) in desired_providers
83
83
  for r in p.resources
84
84
  if isinstance(
85
- r, (NamespaceTerraformResourceRDSV1, NamespaceTerraformResourceRoleV1)
85
+ r, NamespaceTerraformResourceRDSV1 | NamespaceTerraformResourceRoleV1
86
86
  )
87
87
  and r.managed_by_erv2
88
88
  ]
@@ -123,7 +123,7 @@ class ExternalResourcesInventory(MutableMapping):
123
123
  raise FetchResourceError(msg)
124
124
 
125
125
 
126
- class Action(str, Enum):
126
+ class Action(StrEnum):
127
127
  DESTROY: str = "Destroy"
128
128
  APPLY: str = "Apply"
129
129
 
@@ -3,9 +3,9 @@ import json
3
3
  import logging
4
4
  from abc import abstractmethod
5
5
  from collections.abc import Iterable, Mapping
6
- from datetime import datetime, timezone
6
+ from datetime import UTC, datetime
7
7
  from hashlib import shake_128
8
- from typing import Any, Optional
8
+ from typing import Any
9
9
 
10
10
  from pydantic import BaseModel
11
11
  from sretoolbox.utils import threaded
@@ -45,8 +45,8 @@ class VaultSecret(BaseModel):
45
45
 
46
46
  path: str
47
47
  field: str
48
- version: Optional[int]
49
- q_format: Optional[str]
48
+ version: int | None
49
+ q_format: str | None
50
50
 
51
51
 
52
52
  class SecretHelper:
@@ -324,7 +324,7 @@ class InClusterSecretsReconciler(SecretsReconciler):
324
324
  else:
325
325
  data[k] = decoded
326
326
 
327
- spec.metadata[SECRET_UPDATED_AT] = datetime.now(timezone.utc).strftime(
327
+ spec.metadata[SECRET_UPDATED_AT] = datetime.now(UTC).strftime(
328
328
  SECRET_UPDATED_AT_TIMEFORMAT
329
329
  )
330
330
  spec.secret = data
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
  from collections.abc import Mapping
3
- from datetime import datetime, timezone
4
- from enum import Enum
3
+ from datetime import UTC, datetime
4
+ from enum import StrEnum
5
5
  from typing import Any
6
6
 
7
7
  from pydantic import BaseModel
@@ -20,14 +20,14 @@ class StateNotFoundError(Exception):
20
20
  pass
21
21
 
22
22
 
23
- class ReconcileStatus(str, Enum):
23
+ class ReconcileStatus(StrEnum):
24
24
  SUCCESS: str = "SUCCESS"
25
25
  ERROR: str = "ERROR"
26
26
  IN_PROGRESS: str = "IN_PROGRESS"
27
27
  NOT_EXISTS: str = "NOT_EXISTS"
28
28
 
29
29
 
30
- class ResourceStatus(str, Enum):
30
+ class ResourceStatus(StrEnum):
31
31
  CREATED: str = "CREATED"
32
32
  DELETED: str = "DELETED"
33
33
  ABANDONED: str = "ABANDONED"
@@ -198,7 +198,7 @@ class ExternalResourcesStateDynamoDB:
198
198
  else:
199
199
  return ExternalResourceState(
200
200
  key=key,
201
- ts=datetime.now(timezone.utc),
201
+ ts=datetime.now(UTC),
202
202
  resource_status=ResourceStatus.NOT_EXISTS,
203
203
  reconciliation=Reconciliation(key=key),
204
204
  reconciliation_errors=0,
@@ -10,10 +10,7 @@ from datetime import (
10
10
  date,
11
11
  datetime,
12
12
  )
13
- from typing import (
14
- Any,
15
- Optional,
16
- )
13
+ from typing import Any
17
14
 
18
15
  import reconcile.openshift_base as ob
19
16
  from reconcile import queries
@@ -114,9 +111,9 @@ def fetch_desired_state(
114
111
  def run(
115
112
  dry_run: bool,
116
113
  thread_pool_size: int = 10,
117
- internal: Optional[bool] = None,
114
+ internal: bool | None = None,
118
115
  use_jump_host: bool = True,
119
- defer: Optional[Callable] = None,
116
+ defer: Callable | None = None,
120
117
  ) -> None:
121
118
  gabi_instances = queries.get_gabi_instances()
122
119
  if not gabi_instances:
reconcile/gcr_mirror.py CHANGED
@@ -241,7 +241,7 @@ class QuayMirror:
241
241
  control_file_name = "qontract-reconcile-gcr-mirror.timestamp"
242
242
  control_file_path = os.path.join(tempfile.gettempdir(), control_file_name)
243
243
  try:
244
- with open(control_file_path, "r", encoding="locale") as file_obj:
244
+ with open(control_file_path, encoding="locale") as file_obj:
245
245
  last_deep_sync = float(file_obj.read())
246
246
  except FileNotFoundError:
247
247
  self._record_timestamp(control_file_path)