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
tools/qontract_cli.py
CHANGED
@@ -9,16 +9,13 @@ import re
|
|
9
9
|
import sys
|
10
10
|
from collections import defaultdict
|
11
11
|
from datetime import (
|
12
|
+
UTC,
|
12
13
|
datetime,
|
13
14
|
timedelta,
|
14
|
-
timezone,
|
15
15
|
)
|
16
16
|
from operator import itemgetter
|
17
17
|
from statistics import median
|
18
|
-
from typing import
|
19
|
-
Any,
|
20
|
-
Optional,
|
21
|
-
)
|
18
|
+
from typing import Any
|
22
19
|
|
23
20
|
import boto3
|
24
21
|
import click
|
@@ -352,8 +349,8 @@ def get_upgrade_policies_data(
|
|
352
349
|
|
353
350
|
def soaking_str(
|
354
351
|
soaking: dict[str, Any],
|
355
|
-
upgrade_policy:
|
356
|
-
upgradeable_version:
|
352
|
+
upgrade_policy: AbstractUpgradePolicy | None,
|
353
|
+
upgradeable_version: str | None,
|
357
354
|
) -> str:
|
358
355
|
if upgrade_policy:
|
359
356
|
upgrade_version = upgrade_policy.version
|
@@ -764,9 +761,9 @@ def ocm_addon_upgrade_policies(ctx: click.core.Context) -> None:
|
|
764
761
|
@click.pass_context
|
765
762
|
def sd_app_sre_alert_report(
|
766
763
|
ctx: click.core.Context,
|
767
|
-
days:
|
768
|
-
from_timestamp:
|
769
|
-
to_timestamp:
|
764
|
+
days: int | None,
|
765
|
+
from_timestamp: int | None,
|
766
|
+
to_timestamp: int | None,
|
770
767
|
) -> None:
|
771
768
|
import tools.sd_app_sre_alert_report as report
|
772
769
|
|
@@ -1407,9 +1404,7 @@ def rosa_create_cluster_command(ctx, cluster_name):
|
|
1407
1404
|
@click.argument("jumphost_hostname", required=False)
|
1408
1405
|
@click.argument("cluster_name", required=False)
|
1409
1406
|
@click.pass_context
|
1410
|
-
def sshuttle_command(
|
1411
|
-
ctx, jumphost_hostname: Optional[str], cluster_name: Optional[str]
|
1412
|
-
):
|
1407
|
+
def sshuttle_command(ctx, jumphost_hostname: str | None, cluster_name: str | None):
|
1413
1408
|
jumphosts_query_data = queries.get_jumphosts(hostname=jumphost_hostname)
|
1414
1409
|
jumphosts = jumphosts_query_data.jumphosts or []
|
1415
1410
|
for jh in jumphosts:
|
@@ -2358,7 +2353,7 @@ def ec2_jenkins_workers(ctx, aws_access_key_id, aws_secret_access_key, aws_regio
|
|
2358
2353
|
client = boto3.client("autoscaling")
|
2359
2354
|
ec2 = boto3.resource("ec2")
|
2360
2355
|
results = []
|
2361
|
-
now = datetime.now(
|
2356
|
+
now = datetime.now(UTC)
|
2362
2357
|
DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
|
2363
2358
|
columns = [
|
2364
2359
|
"type",
|
@@ -2511,7 +2506,7 @@ def alerts(ctx, file_path):
|
|
2511
2506
|
case _:
|
2512
2507
|
return BIG_NUMBER
|
2513
2508
|
|
2514
|
-
with open(file_path,
|
2509
|
+
with open(file_path, encoding="locale") as f:
|
2515
2510
|
content = json.loads(f.read())
|
2516
2511
|
|
2517
2512
|
columns = [
|
@@ -2605,7 +2600,7 @@ def osd_component_versions(ctx):
|
|
2605
2600
|
@get.command()
|
2606
2601
|
@click.pass_context
|
2607
2602
|
def maintenances(ctx):
|
2608
|
-
now = datetime.now(
|
2603
|
+
now = datetime.now(UTC)
|
2609
2604
|
maintenances = maintenances_gql.query(gql.get_api().query).maintenances or []
|
2610
2605
|
data = [
|
2611
2606
|
{
|
@@ -3474,7 +3469,7 @@ def saas_dev(ctx, app_name=None, saas_file_name=None, env_name=None) -> None:
|
|
3474
3469
|
@click.option("--app-name", default=None, help="app to act on.")
|
3475
3470
|
@click.pass_context
|
3476
3471
|
def saas_targets(
|
3477
|
-
ctx, saas_file_name:
|
3472
|
+
ctx, saas_file_name: str | None = None, app_name: str | None = None
|
3478
3473
|
) -> None:
|
3479
3474
|
"""Resolve namespaceSelectors and print all resulting targets of a saas file."""
|
3480
3475
|
console = Console()
|
@@ -3663,6 +3658,25 @@ def gpg_encrypt(
|
|
3663
3658
|
).execute()
|
3664
3659
|
|
3665
3660
|
|
3661
|
+
@root.command()
|
3662
|
+
@click.option("--channel", help="the channel that state is part of")
|
3663
|
+
@click.option("--sha", help="the commit sha we want state for")
|
3664
|
+
@environ(["APP_INTERFACE_STATE_BUCKET"])
|
3665
|
+
def get_promotion_state(channel: str, sha: str):
|
3666
|
+
from tools.saas_promotion_state.saas_promotion_state import (
|
3667
|
+
SaasPromotionState,
|
3668
|
+
)
|
3669
|
+
|
3670
|
+
promotion_state = SaasPromotionState.create(promotion_state=None, saas_files=None)
|
3671
|
+
for publisher_id, state in promotion_state.get(channel=channel, sha=sha).items():
|
3672
|
+
print()
|
3673
|
+
if not state:
|
3674
|
+
print(f"No state found for {publisher_id=}")
|
3675
|
+
else:
|
3676
|
+
print(f"State for {publisher_id=}:")
|
3677
|
+
print(state)
|
3678
|
+
|
3679
|
+
|
3666
3680
|
@root.command()
|
3667
3681
|
@click.option("--change-type-name")
|
3668
3682
|
@click.option("--role-name")
|
File without changes
|
@@ -0,0 +1,72 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from collections.abc import Iterable
|
4
|
+
|
5
|
+
from reconcile.openshift_saas_deploy import (
|
6
|
+
QONTRACT_INTEGRATION as OPENSHIFT_SAAS_DEPLOY,
|
7
|
+
)
|
8
|
+
from reconcile.typed_queries.app_interface_vault_settings import (
|
9
|
+
get_app_interface_vault_settings,
|
10
|
+
)
|
11
|
+
from reconcile.typed_queries.saas_files import SaasFile, get_saas_files
|
12
|
+
from reconcile.utils.promotion_state import PromotionData, PromotionState
|
13
|
+
from reconcile.utils.secret_reader import create_secret_reader
|
14
|
+
from reconcile.utils.state import init_state
|
15
|
+
|
16
|
+
|
17
|
+
class SaasPromotionState:
|
18
|
+
def __init__(
|
19
|
+
self, promotion_state: PromotionState, saas_files: Iterable[SaasFile]
|
20
|
+
) -> None:
|
21
|
+
self._promotion_state = promotion_state
|
22
|
+
self._saas_files = saas_files
|
23
|
+
|
24
|
+
def _publisher_ids_for_channel(
|
25
|
+
self, channel: str, saas_files: Iterable[SaasFile]
|
26
|
+
) -> list[str]:
|
27
|
+
publisher_uids: list[str] = []
|
28
|
+
for saas_file in saas_files:
|
29
|
+
for resource_template in saas_file.resource_templates:
|
30
|
+
for target in resource_template.targets:
|
31
|
+
if not target.promotion:
|
32
|
+
continue
|
33
|
+
for publish_channel in target.promotion.publish or []:
|
34
|
+
if publish_channel == channel:
|
35
|
+
publisher_uids.append(
|
36
|
+
target.uid(
|
37
|
+
parent_saas_file_name=saas_file.name,
|
38
|
+
parent_resource_template_name=resource_template.name,
|
39
|
+
)
|
40
|
+
)
|
41
|
+
return publisher_uids
|
42
|
+
|
43
|
+
def get(self, channel: str, sha: str) -> dict[str, PromotionData | None]:
|
44
|
+
return {
|
45
|
+
publisher_id: self._promotion_state.get_promotion_data(
|
46
|
+
sha=sha,
|
47
|
+
channel=channel,
|
48
|
+
use_cache=False,
|
49
|
+
target_uid=publisher_id,
|
50
|
+
pre_check_sha_exists=False,
|
51
|
+
)
|
52
|
+
for publisher_id in self._publisher_ids_for_channel(
|
53
|
+
channel=channel, saas_files=self._saas_files
|
54
|
+
)
|
55
|
+
}
|
56
|
+
|
57
|
+
@staticmethod
|
58
|
+
def create(
|
59
|
+
promotion_state: PromotionState | None, saas_files: Iterable[SaasFile] | None
|
60
|
+
) -> SaasPromotionState:
|
61
|
+
if not promotion_state:
|
62
|
+
vault_settings = get_app_interface_vault_settings()
|
63
|
+
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
64
|
+
saas_deploy_state = init_state(
|
65
|
+
integration=OPENSHIFT_SAAS_DEPLOY, secret_reader=secret_reader
|
66
|
+
)
|
67
|
+
promotion_state = PromotionState(state=saas_deploy_state)
|
68
|
+
if not saas_files:
|
69
|
+
saas_files = get_saas_files()
|
70
|
+
return SaasPromotionState(
|
71
|
+
promotion_state=promotion_state, saas_files=saas_files
|
72
|
+
)
|
tools/template_validation.py
CHANGED
@@ -27,7 +27,7 @@ def load_clean_yaml(path: str) -> dict:
|
|
27
27
|
|
28
28
|
def load_yaml(to_load: str) -> dict:
|
29
29
|
ruamel_instance = create_ruamel_instance()
|
30
|
-
with open(to_load,
|
30
|
+
with open(to_load, encoding="utf-8") as file:
|
31
31
|
return ruamel_instance.load(file)
|
32
32
|
|
33
33
|
|
tools/test/conftest.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
from collections.abc import (
|
2
2
|
Callable,
|
3
|
+
Iterable,
|
4
|
+
Mapping,
|
3
5
|
MutableMapping,
|
4
6
|
)
|
5
|
-
from
|
6
|
-
|
7
|
-
Optional,
|
8
|
-
)
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import Any
|
9
9
|
|
10
10
|
import pytest
|
11
11
|
from pydantic import BaseModel
|
12
12
|
from pydantic.error_wrappers import ValidationError
|
13
13
|
|
14
|
+
from reconcile.typed_queries.saas_files import SaasFile
|
14
15
|
from reconcile.utils.models import data_default_none
|
15
16
|
|
16
17
|
|
@@ -18,17 +19,55 @@ class GQLClassFactoryError(Exception):
|
|
18
19
|
pass
|
19
20
|
|
20
21
|
|
22
|
+
@pytest.fixture
|
23
|
+
def saas_files_builder(
|
24
|
+
gql_class_factory: Callable[[type[SaasFile], Mapping], SaasFile],
|
25
|
+
) -> Callable[[Iterable[MutableMapping]], list[SaasFile]]:
|
26
|
+
def builder(data: Iterable[MutableMapping]) -> list[SaasFile]:
|
27
|
+
for d in data:
|
28
|
+
if "app" not in d:
|
29
|
+
d["app"] = {}
|
30
|
+
if "pipelinesProvider" not in d:
|
31
|
+
d["pipelinesProvider"] = {}
|
32
|
+
if "managedResourceTypes" not in d:
|
33
|
+
d["managedResourceTypes"] = []
|
34
|
+
if "imagePatterns" not in d:
|
35
|
+
d["imagePatterns"] = []
|
36
|
+
for rt in d.get("resourceTemplates", []):
|
37
|
+
for t in rt.get("targets", []):
|
38
|
+
ns = t["namespace"]
|
39
|
+
if "name" not in ns:
|
40
|
+
ns["name"] = "some_name"
|
41
|
+
if "environment" not in ns:
|
42
|
+
ns["environment"] = {}
|
43
|
+
if "app" not in ns:
|
44
|
+
ns["app"] = {}
|
45
|
+
if "cluster" not in ns:
|
46
|
+
ns["cluster"] = {}
|
47
|
+
return [gql_class_factory(SaasFile, d) for d in data]
|
48
|
+
|
49
|
+
return builder
|
50
|
+
|
51
|
+
|
52
|
+
@pytest.fixture
|
53
|
+
def fx() -> Callable:
|
54
|
+
def _fx(name: str) -> str:
|
55
|
+
return (Path(__file__).parent / "fixtures" / name).read_text()
|
56
|
+
|
57
|
+
return _fx
|
58
|
+
|
59
|
+
|
21
60
|
@pytest.fixture
|
22
61
|
def gql_class_factory() -> (
|
23
62
|
Callable[
|
24
|
-
[type[BaseModel],
|
63
|
+
[type[BaseModel], MutableMapping[str, Any] | None],
|
25
64
|
BaseModel,
|
26
65
|
]
|
27
66
|
):
|
28
67
|
"""Create a GQL class from a fixture and set default values to None."""
|
29
68
|
|
30
69
|
def _gql_class_factory(
|
31
|
-
klass: type[BaseModel], data:
|
70
|
+
klass: type[BaseModel], data: MutableMapping[str, Any] | None = None
|
32
71
|
) -> BaseModel:
|
33
72
|
try:
|
34
73
|
return klass(**data_default_none(klass, data or {}))
|
@@ -0,0 +1,86 @@
|
|
1
|
+
from collections.abc import (
|
2
|
+
Callable,
|
3
|
+
Iterable,
|
4
|
+
Mapping,
|
5
|
+
)
|
6
|
+
from unittest.mock import (
|
7
|
+
create_autospec,
|
8
|
+
)
|
9
|
+
|
10
|
+
from reconcile.typed_queries.saas_files import SaasFile
|
11
|
+
from reconcile.utils.promotion_state import PromotionData, PromotionState
|
12
|
+
from tools.saas_promotion_state.saas_promotion_state import (
|
13
|
+
SaasPromotionState,
|
14
|
+
)
|
15
|
+
|
16
|
+
|
17
|
+
def test_saas_promotion_state(
|
18
|
+
saas_files_builder: Callable[[Iterable[Mapping]], list[SaasFile]],
|
19
|
+
) -> None:
|
20
|
+
saas_files = saas_files_builder([
|
21
|
+
{
|
22
|
+
"path": "/saas1.yml",
|
23
|
+
"name": "saas_1",
|
24
|
+
"resourceTemplates": [
|
25
|
+
{
|
26
|
+
"name": "template_1",
|
27
|
+
"url": "repo1/url",
|
28
|
+
"targets": [
|
29
|
+
{
|
30
|
+
"ref": "main",
|
31
|
+
"namespace": {"path": "/namespace1.yml"},
|
32
|
+
"promotion": {
|
33
|
+
"publish": ["channel-a"],
|
34
|
+
},
|
35
|
+
}
|
36
|
+
],
|
37
|
+
}
|
38
|
+
],
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"path": "/saas2.yml",
|
42
|
+
"name": "saas_2",
|
43
|
+
"resourceTemplates": [
|
44
|
+
{
|
45
|
+
"name": "template_2",
|
46
|
+
"url": "repo2/url",
|
47
|
+
"targets": [
|
48
|
+
{
|
49
|
+
"ref": "main",
|
50
|
+
"namespace": {"path": "/namespace2.yml"},
|
51
|
+
"promotion": {
|
52
|
+
"publish": ["channel-b"],
|
53
|
+
"subscribe": ["channel-a"],
|
54
|
+
},
|
55
|
+
},
|
56
|
+
{
|
57
|
+
"ref": "main",
|
58
|
+
"namespace": {"path": "/namespace3.yml"},
|
59
|
+
},
|
60
|
+
],
|
61
|
+
}
|
62
|
+
],
|
63
|
+
},
|
64
|
+
])
|
65
|
+
|
66
|
+
expected = PromotionData(
|
67
|
+
check_in="test1",
|
68
|
+
saas_file="test2",
|
69
|
+
success=True,
|
70
|
+
target_config_hash="test3",
|
71
|
+
)
|
72
|
+
promotion_state = create_autospec(spec=PromotionState)
|
73
|
+
promotion_state.get_promotion_data.return_value = expected
|
74
|
+
saas_promotion_state = SaasPromotionState.create(
|
75
|
+
promotion_state=promotion_state, saas_files=saas_files
|
76
|
+
)
|
77
|
+
result = saas_promotion_state.get(channel="channel-a", sha="main")
|
78
|
+
|
79
|
+
assert result == {"616af45d7fad7f4eea8d52b8b5e8a058cef82ab0": expected}
|
80
|
+
promotion_state.get_promotion_data.assert_called_once_with(
|
81
|
+
sha="main",
|
82
|
+
channel="channel-a",
|
83
|
+
use_cache=False,
|
84
|
+
target_uid="616af45d7fad7f4eea8d52b8b5e8a058cef82ab0",
|
85
|
+
pre_check_sha_exists=False,
|
86
|
+
)
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc884.dist-info → qontract_reconcile-0.10.1rc886.dist-info}/top_level.txt
RENAMED
File without changes
|