qontract-reconcile 0.10.1rc884__py3-none-any.whl → 0.10.1rc886__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.
- {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/RECORD +279 -276
- reconcile/acs_rbac.py +1 -2
- reconcile/aus/advanced_upgrade_service.py +14 -14
- reconcile/aus/aus_label_source.py +1 -2
- reconcile/aus/base.py +23 -26
- reconcile/aus/cluster_version_data.py +4 -4
- reconcile/aus/models.py +2 -3
- reconcile/aus/version_gate_approver.py +2 -6
- reconcile/aus/version_gates/__init__.py +1 -3
- reconcile/aus/version_gates/sts_version_gate_handler.py +2 -3
- reconcile/aws_account_manager/integration.py +2 -2
- reconcile/aws_ami_cleanup/integration.py +3 -4
- reconcile/aws_iam_password_reset.py +2 -5
- reconcile/aws_version_sync/integration.py +2 -2
- reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
- reconcile/change_owners/approver.py +4 -5
- reconcile/change_owners/bundle.py +20 -22
- reconcile/change_owners/change_types.py +23 -24
- reconcile/change_owners/changes.py +13 -16
- reconcile/change_owners/decision.py +2 -5
- reconcile/change_owners/diff.py +11 -15
- reconcile/change_owners/self_service_roles.py +1 -2
- reconcile/change_owners/tester.py +7 -10
- reconcile/checkpoint.py +2 -5
- reconcile/cli.py +9 -12
- reconcile/closedbox_endpoint_monitoring_base.py +8 -11
- reconcile/cluster_deployment_mapper.py +2 -5
- reconcile/cna/assets/asset.py +4 -7
- reconcile/cna/assets/null.py +2 -5
- reconcile/cna/integration.py +2 -3
- reconcile/cna/state.py +2 -5
- reconcile/dashdotdb_base.py +8 -11
- reconcile/dashdotdb_cso.py +3 -6
- reconcile/dashdotdb_dora.py +10 -14
- reconcile/dashdotdb_dvo.py +10 -13
- reconcile/dashdotdb_slo.py +5 -8
- reconcile/database_access_manager.py +5 -6
- reconcile/dynatrace_token_provider/integration.py +2 -5
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +4 -4
- reconcile/external_resources/model.py +3 -3
- reconcile/external_resources/secrets_sync.py +5 -5
- reconcile/external_resources/state.py +5 -5
- reconcile/gabi_authorized_users.py +3 -6
- reconcile/gcr_mirror.py +1 -1
- reconcile/github_org.py +1 -3
- reconcile/github_repo_invites.py +2 -5
- reconcile/gitlab_housekeeping.py +7 -11
- reconcile/gitlab_labeler.py +1 -2
- reconcile/gitlab_members.py +2 -5
- reconcile/gitlab_permissions.py +1 -3
- reconcile/glitchtip/integration.py +2 -5
- reconcile/glitchtip_project_alerts/integration.py +3 -6
- reconcile/glitchtip_project_dsn/integration.py +4 -7
- reconcile/integrations_manager.py +5 -8
- reconcile/jenkins/types.py +5 -6
- reconcile/jenkins_job_builder.py +9 -12
- reconcile/jenkins_roles.py +1 -1
- reconcile/jira_watcher.py +2 -2
- reconcile/ldap_groups/integration.py +2 -5
- reconcile/ocm/types.py +21 -26
- reconcile/ocm_addons_upgrade_tests_trigger.py +3 -6
- reconcile/ocm_clusters.py +8 -8
- reconcile/ocm_internal_notifications/integration.py +1 -2
- reconcile/ocm_labels/integration.py +2 -5
- reconcile/ocm_machine_pools.py +11 -15
- reconcile/ocm_upgrade_scheduler_org_updater.py +2 -5
- reconcile/openshift_base.py +27 -29
- reconcile/openshift_groups.py +15 -20
- reconcile/openshift_namespace_labels.py +8 -14
- reconcile/openshift_namespaces.py +5 -8
- reconcile/openshift_network_policies.py +2 -4
- reconcile/openshift_resources_base.py +19 -29
- reconcile/openshift_saas_deploy.py +9 -10
- reconcile/openshift_saas_deploy_change_tester.py +7 -10
- reconcile/openshift_saas_deploy_trigger_base.py +4 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +5 -8
- reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
- reconcile/openshift_saas_deploy_trigger_images.py +1 -2
- reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
- reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
- reconcile/openshift_tekton_resources.py +7 -11
- reconcile/openshift_upgrade_watcher.py +10 -13
- reconcile/openshift_users.py +8 -11
- reconcile/oum/base.py +3 -4
- reconcile/oum/labelset.py +1 -2
- reconcile/oum/metrics.py +2 -2
- reconcile/oum/models.py +1 -2
- reconcile/oum/standalone.py +2 -3
- reconcile/prometheus_rules_tester/integration.py +6 -9
- reconcile/quay_membership.py +1 -2
- reconcile/quay_mirror.py +12 -13
- reconcile/quay_mirror_org.py +10 -10
- reconcile/queries.py +4 -7
- reconcile/resource_scraper.py +3 -4
- reconcile/rhidp/common.py +2 -2
- reconcile/saas_auto_promotions_manager/integration.py +5 -6
- reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +1 -2
- reconcile/saas_auto_promotions_manager/publisher.py +5 -6
- reconcile/saas_auto_promotions_manager/subscriber.py +3 -4
- reconcile/saas_file_validator.py +2 -5
- reconcile/signalfx_endpoint_monitoring.py +2 -5
- reconcile/skupper_network/integration.py +3 -6
- reconcile/skupper_network/models.py +3 -5
- reconcile/slack_base.py +4 -7
- reconcile/slack_usergroups.py +15 -17
- reconcile/sql_query.py +5 -9
- reconcile/status_board.py +4 -5
- reconcile/statuspage/atlassian.py +14 -15
- reconcile/statuspage/integrations/maintenances.py +3 -3
- reconcile/statuspage/page.py +8 -8
- reconcile/statuspage/state.py +4 -5
- reconcile/statuspage/status.py +7 -8
- reconcile/templating/lib/rendering.py +8 -8
- reconcile/templating/renderer.py +10 -11
- reconcile/templating/validator.py +4 -4
- reconcile/terraform_aws_route53.py +3 -6
- reconcile/terraform_cloudflare_dns.py +9 -12
- reconcile/terraform_cloudflare_resources.py +9 -11
- reconcile/terraform_cloudflare_users.py +8 -11
- reconcile/terraform_init/integration.py +2 -2
- reconcile/terraform_repo.py +11 -14
- reconcile/terraform_resources.py +20 -21
- reconcile/terraform_tgw_attachments.py +32 -36
- reconcile/terraform_users.py +6 -7
- reconcile/terraform_vpc_resources/integration.py +5 -5
- reconcile/test/conftest.py +7 -10
- reconcile/test/fixtures.py +1 -1
- reconcile/test/saas_auto_promotions_manager/conftest.py +2 -2
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +2 -2
- reconcile/test/test_database_access_manager.py +3 -6
- reconcile/test/test_gitlab_labeler.py +2 -5
- reconcile/test/test_jump_host.py +5 -8
- reconcile/test/test_ocm_machine_pools.py +1 -4
- reconcile/test/test_openshift_base.py +3 -6
- reconcile/test/test_openshift_cluster_bots.py +5 -5
- reconcile/test/test_openshift_namespace_labels.py +2 -3
- reconcile/test/test_openshift_saas_deploy_trigger_cleaner.py +2 -2
- reconcile/test/test_saasherder.py +9 -12
- reconcile/test/test_slack_base.py +4 -6
- reconcile/test/test_status_board.py +4 -7
- reconcile/test/test_terraform_tgw_attachments.py +14 -20
- reconcile/typed_queries/alerting_services_settings.py +1 -2
- reconcile/typed_queries/app_interface_custom_messages.py +2 -3
- reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +1 -3
- reconcile/typed_queries/app_interface_repo_url.py +1 -2
- reconcile/typed_queries/app_interface_state_settings.py +1 -3
- reconcile/typed_queries/app_interface_vault_settings.py +1 -2
- reconcile/typed_queries/aws_vpc_requests.py +1 -3
- reconcile/typed_queries/aws_vpcs.py +1 -3
- reconcile/typed_queries/clusters.py +2 -4
- reconcile/typed_queries/clusters_minimal.py +1 -3
- reconcile/typed_queries/clusters_with_dms.py +1 -3
- reconcile/typed_queries/external_resources.py +3 -4
- reconcile/typed_queries/pagerduty_instances.py +1 -2
- reconcile/typed_queries/repos.py +2 -3
- reconcile/typed_queries/reserved_networks.py +1 -3
- reconcile/typed_queries/saas_files.py +49 -59
- reconcile/typed_queries/slo_documents.py +1 -3
- reconcile/typed_queries/status_board.py +3 -7
- reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
- reconcile/typed_queries/terraform_namespaces.py +1 -2
- reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +1 -3
- reconcile/utils/acs/base.py +2 -3
- reconcile/utils/acs/notifiers.py +3 -3
- reconcile/utils/acs/policies.py +3 -3
- reconcile/utils/aggregated_list.py +1 -1
- reconcile/utils/amtool.py +1 -2
- reconcile/utils/aws_api.py +28 -31
- reconcile/utils/binary.py +1 -3
- reconcile/utils/clusterhealth/providerbase.py +1 -2
- reconcile/utils/clusterhealth/telemeter.py +2 -2
- reconcile/utils/deadmanssnitch_api.py +1 -2
- reconcile/utils/disabled_integrations.py +4 -6
- reconcile/utils/environ.py +1 -1
- reconcile/utils/expiration.py +3 -7
- reconcile/utils/external_resource_spec.py +3 -4
- reconcile/utils/external_resources.py +4 -7
- reconcile/utils/filtering.py +1 -2
- reconcile/utils/git.py +3 -9
- reconcile/utils/git_secrets.py +5 -5
- reconcile/utils/github_api.py +5 -9
- reconcile/utils/gitlab_api.py +2 -3
- reconcile/utils/glitchtip/client.py +2 -4
- reconcile/utils/glitchtip/models.py +8 -11
- reconcile/utils/gql.py +26 -35
- reconcile/utils/grouping.py +1 -3
- reconcile/utils/imap_client.py +2 -5
- reconcile/utils/internal_groups/client.py +1 -2
- reconcile/utils/internal_groups/models.py +8 -9
- reconcile/utils/jenkins_api.py +4 -4
- reconcile/utils/jinja2/extensions.py +1 -1
- reconcile/utils/jinja2/filters.py +4 -4
- reconcile/utils/jinja2/utils.py +16 -16
- reconcile/utils/jira_client.py +10 -11
- reconcile/utils/jjb_client.py +14 -17
- reconcile/utils/jobcontroller/controller.py +5 -5
- reconcile/utils/jobcontroller/models.py +2 -2
- reconcile/utils/jsonpath.py +4 -5
- reconcile/utils/jump_host.py +7 -8
- reconcile/utils/keycloak.py +3 -7
- reconcile/utils/ldap_client.py +2 -3
- reconcile/utils/lean_terraform_client.py +13 -17
- reconcile/utils/membershipsources/app_interface_resolver.py +1 -1
- reconcile/utils/membershipsources/models.py +19 -22
- reconcile/utils/metrics.py +13 -15
- reconcile/utils/mr/base.py +7 -11
- reconcile/utils/mr/glitchtip_access_reporter.py +2 -2
- reconcile/utils/mr/notificator.py +1 -2
- reconcile/utils/oc.py +32 -38
- reconcile/utils/oc_connection_parameters.py +24 -25
- reconcile/utils/oc_filters.py +2 -3
- reconcile/utils/oc_map.py +9 -15
- reconcile/utils/ocm/addons.py +7 -10
- reconcile/utils/ocm/base.py +38 -39
- reconcile/utils/ocm/clusters.py +6 -9
- reconcile/utils/ocm/label_sources.py +1 -2
- reconcile/utils/ocm/labels.py +3 -6
- reconcile/utils/ocm/ocm.py +11 -14
- reconcile/utils/ocm/products.py +1 -3
- reconcile/utils/ocm/search_filters.py +16 -17
- reconcile/utils/ocm/service_log.py +2 -3
- reconcile/utils/ocm/sre_capability_labels.py +4 -8
- reconcile/utils/ocm/subscriptions.py +1 -3
- reconcile/utils/ocm/syncsets.py +2 -4
- reconcile/utils/ocm/upgrades.py +5 -9
- reconcile/utils/ocm_base_client.py +13 -16
- reconcile/utils/openshift_resource.py +5 -11
- reconcile/utils/output.py +2 -3
- reconcile/utils/pagerduty_api.py +4 -5
- reconcile/utils/prometheus.py +2 -2
- reconcile/utils/promotion_state.py +4 -5
- reconcile/utils/promtool.py +2 -8
- reconcile/utils/quay_api.py +12 -22
- reconcile/utils/raw_github_api.py +3 -5
- reconcile/utils/rosa/rosa_cli.py +6 -6
- reconcile/utils/rosa/session.py +6 -7
- reconcile/utils/runtime/desired_state_diff.py +3 -8
- reconcile/utils/runtime/environment.py +4 -7
- reconcile/utils/runtime/integration.py +4 -4
- reconcile/utils/runtime/meta.py +1 -2
- reconcile/utils/runtime/runner.py +7 -10
- reconcile/utils/runtime/sharding.py +22 -27
- reconcile/utils/saasherder/interfaces.py +63 -69
- reconcile/utils/saasherder/models.py +30 -35
- reconcile/utils/saasherder/saasherder.py +37 -53
- reconcile/utils/secret_reader.py +17 -19
- reconcile/utils/slack_api.py +15 -17
- reconcile/utils/smtp_client.py +1 -2
- reconcile/utils/sqs_gateway.py +1 -3
- reconcile/utils/state.py +1 -2
- reconcile/utils/terraform/config_client.py +4 -5
- reconcile/utils/terraform_client.py +3 -8
- reconcile/utils/terrascript/cloudflare_client.py +4 -10
- reconcile/utils/terrascript/cloudflare_resources.py +10 -13
- reconcile/utils/terrascript/models.py +2 -3
- reconcile/utils/terrascript/resources.py +1 -2
- reconcile/utils/terrascript_aws_client.py +30 -38
- reconcile/utils/unleash/client.py +4 -7
- reconcile/utils/unleash/server.py +2 -2
- reconcile/utils/vault.py +8 -11
- reconcile/utils/vaultsecretref.py +2 -3
- reconcile/utils/vcs.py +7 -8
- reconcile/vault_replication.py +4 -8
- reconcile/vpc_peerings_validator.py +4 -9
- release/version.py +6 -7
- tools/app_interface_reporter.py +2 -2
- tools/cli_commands/gpg_encrypt.py +3 -6
- tools/cli_commands/systems_and_tools.py +4 -7
- tools/qontract_cli.py +31 -17
- tools/saas_promotion_state/__init__.py +0 -0
- tools/saas_promotion_state/saas_promotion_state.py +72 -0
- tools/template_validation.py +1 -1
- tools/test/conftest.py +45 -6
- tools/test/test_saas_promotion_state.py +86 -0
- {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.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:
|
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:
|
82
|
-
rules:
|
83
|
-
hostedzones:
|
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:
|
92
|
-
route_table_ids:
|
93
|
-
subnets_id_az:
|
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:
|
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:
|
123
|
+
ocm_map: OCMMap | None,
|
126
124
|
awsapi: AWSApi,
|
127
|
-
account_name:
|
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:
|
144
|
+
ocm_map: OCMMap | None,
|
147
145
|
awsapi: AWSApi,
|
148
|
-
account_name:
|
149
|
-
) -> Generator[
|
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:
|
163
|
+
ocm: OCM | None,
|
166
164
|
awsapi: AWSApi,
|
167
|
-
) -> Generator[
|
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:
|
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
|
-
) ->
|
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:
|
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:
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
497
|
+
print_to_file: str | None = None,
|
502
498
|
enable_deletion: bool = False,
|
503
499
|
thread_pool_size: int = 10,
|
504
|
-
account_name:
|
505
|
-
defer:
|
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,
|
reconcile/terraform_users.py
CHANGED
@@ -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:
|
113
|
-
account_name:
|
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"
|
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:
|
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:
|
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:
|
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
|
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:
|
45
|
-
print_to_file:
|
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:
|
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."""
|
reconcile/test/conftest.py
CHANGED
@@ -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],
|
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:
|
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],
|
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:
|
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[[
|
141
|
-
def builder(data:
|
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
|
reconcile/test/fixtures.py
CHANGED
@@ -5,7 +5,7 @@ from collections.abc import (
|
|
5
5
|
Mapping,
|
6
6
|
MutableMapping,
|
7
7
|
)
|
8
|
-
from datetime import
|
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(
|
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",
|
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",
|
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
|
3
|
-
|
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:
|
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) ->
|
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}
|
reconcile/test/test_jump_host.py
CHANGED
@@ -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,
|
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:
|
103
|
-
remote_port:
|
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,
|
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) ->
|
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
|
3
|
-
|
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:
|
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 = "{}"
|
134
|
+
ret_mock.stdout = b"{}"
|
135
135
|
assert ocb.oc(*args) == {}
|
136
136
|
|
137
|
-
ret_mock.stdout = ""
|
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!"
|
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"
|
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"
|
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:
|
41
|
-
managed:
|
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
|
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=
|
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
|
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:
|
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:
|
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:
|
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(
|
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(
|
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(
|
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(
|
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:
|
161
|
-
timeout:
|
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:
|
171
|
-
methods:
|
168
|
+
q_global: ClientGlobalConfig | None
|
169
|
+
methods: list[ClientMethodConfig] | None
|
172
170
|
|
173
171
|
|
174
172
|
def test_get_slackapi():
|