qontract-reconcile 0.10.2.dev349__py3-none-any.whl → 0.10.2.dev414__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.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/METADATA +12 -11
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/RECORD +356 -350
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +15 -12
- reconcile/aus/base.py +26 -27
- reconcile/aus/cluster_version_data.py +15 -5
- reconcile/aus/models.py +1 -1
- reconcile/automated_actions/config/integration.py +15 -3
- reconcile/aws_account_manager/integration.py +8 -8
- reconcile/aws_account_manager/reconciler.py +3 -3
- reconcile/aws_ami_cleanup/integration.py +8 -12
- reconcile/aws_ami_share.py +69 -62
- reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
- reconcile/aws_ecr_image_pull_secrets.py +2 -2
- reconcile/aws_iam_keys.py +7 -41
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +32 -25
- reconcile/aws_version_sync/integration.py +6 -12
- reconcile/change_owners/bundle.py +3 -3
- reconcile/change_owners/change_log_tracking.py +3 -2
- reconcile/change_owners/change_owners.py +1 -1
- reconcile/change_owners/diff.py +2 -4
- reconcile/checkpoint.py +11 -3
- reconcile/cli.py +33 -8
- reconcile/dashdotdb_dora.py +5 -12
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +123 -117
- reconcile/dynatrace_token_provider/integration.py +1 -1
- reconcile/endpoints_discovery/integration.py +4 -1
- reconcile/endpoints_discovery/merge_request.py +1 -1
- reconcile/endpoints_discovery/merge_request_manager.py +9 -11
- reconcile/external_resources/factories.py +5 -12
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +24 -10
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +13 -13
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +6 -8
- reconcile/external_resources/state.py +60 -17
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gabi_authorized_users.py +8 -5
- reconcile/gcp_image_mirror.py +2 -2
- reconcile/github_org.py +1 -1
- reconcile/github_owners.py +4 -0
- reconcile/gitlab_housekeeping.py +13 -15
- reconcile/gitlab_members.py +6 -12
- reconcile/gitlab_mr_sqs_consumer.py +2 -2
- reconcile/gitlab_owners.py +15 -11
- reconcile/gitlab_permissions.py +8 -12
- reconcile/glitchtip_project_alerts/integration.py +3 -1
- reconcile/gql_definitions/acs/acs_instances.py +5 -5
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
- reconcile/gql_definitions/automated_actions/instance.py +46 -7
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
- reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
- reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
- reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
- reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
- reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
- reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_roles.py +5 -5
- reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
- reconcile/gql_definitions/common/apps.py +5 -5
- reconcile/gql_definitions/common/aws_vpc_requests.py +15 -5
- reconcile/gql_definitions/common/aws_vpcs.py +5 -5
- reconcile/gql_definitions/common/clusters.py +7 -5
- reconcile/gql_definitions/common/clusters_minimal.py +5 -5
- reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
- reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
- reconcile/gql_definitions/common/github_orgs.py +5 -5
- reconcile/gql_definitions/common/jira_settings.py +5 -5
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +5 -5
- reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
- reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
- reconcile/gql_definitions/common/ocm_environments.py +5 -5
- reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
- reconcile/gql_definitions/common/pipeline_providers.py +5 -5
- reconcile/gql_definitions/common/quay_instances.py +5 -5
- reconcile/gql_definitions/common/quay_orgs.py +5 -5
- reconcile/gql_definitions/common/reserved_networks.py +5 -5
- reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
- reconcile/gql_definitions/common/saas_files.py +5 -5
- reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
- reconcile/gql_definitions/common/saasherder_settings.py +5 -5
- reconcile/gql_definitions/common/slack_workspaces.py +5 -5
- reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
- reconcile/gql_definitions/common/state_aws_account.py +5 -5
- reconcile/gql_definitions/common/users.py +5 -5
- reconcile/gql_definitions/common/users_with_paths.py +5 -5
- reconcile/gql_definitions/cost_report/app_names.py +5 -5
- reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
- reconcile/gql_definitions/cost_report/settings.py +5 -5
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
- reconcile/gql_definitions/email_sender/apps.py +5 -5
- reconcile/gql_definitions/email_sender/emails.py +5 -5
- reconcile/gql_definitions/email_sender/users.py +5 -5
- reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
- reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +89 -6
- reconcile/gql_definitions/external_resources/external_resources_settings.py +7 -5
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
- reconcile/gql_definitions/fragments/aus_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
- reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
- reconcile/gql_definitions/fragments/aws_organization.py +33 -0
- reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc_request.py +7 -5
- reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
- reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
- reconcile/gql_definitions/fragments/disable.py +5 -5
- reconcile/gql_definitions/fragments/email_service.py +5 -5
- reconcile/gql_definitions/fragments/email_user.py +5 -5
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
- reconcile/gql_definitions/fragments/membership_source.py +5 -5
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
- reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_values.py +5 -5
- reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
- reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
- reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
- reconcile/gql_definitions/fragments/terraform_state.py +5 -5
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
- reconcile/gql_definitions/fragments/user.py +5 -5
- reconcile/gql_definitions/fragments/vault_secret.py +5 -5
- reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
- reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
- reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
- reconcile/gql_definitions/integrations/integrations.py +5 -5
- reconcile/gql_definitions/introspection.json +2137 -1053
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
- reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +5 -5
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
- reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
- reconcile/gql_definitions/rhcs/certs.py +5 -5
- reconcile/gql_definitions/rhidp/organizations.py +5 -5
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
- reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
- reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
- reconcile/gql_definitions/slack_usergroups/users.py +5 -5
- reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
- reconcile/gql_definitions/status_board/status_board.py +5 -5
- reconcile/gql_definitions/statuspage/statuspages.py +5 -5
- reconcile/gql_definitions/templating/template_collection.py +5 -5
- reconcile/gql_definitions/templating/templates.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
- reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +38 -6
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
- reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
- reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_worker_fleets.py +10 -8
- reconcile/jira_permissions_validator.py +237 -122
- reconcile/ldap_groups/integration.py +1 -1
- reconcile/ocm/types.py +35 -56
- reconcile/ocm_aws_infrastructure_access.py +1 -1
- reconcile/ocm_clusters.py +4 -4
- reconcile/ocm_labels/integration.py +3 -2
- reconcile/ocm_machine_pools.py +23 -23
- reconcile/openshift_base.py +53 -2
- reconcile/openshift_cluster_bots.py +3 -2
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +6 -2
- reconcile/openshift_rhcs_certs.py +5 -5
- reconcile/openshift_rolebindings.py +7 -11
- reconcile/openshift_saas_deploy.py +6 -7
- reconcile/openshift_saas_deploy_change_tester.py +9 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
- reconcile/openshift_serviceaccount_tokens.py +2 -2
- reconcile/openshift_upgrade_watcher.py +4 -4
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/prometheus_rules_tester/integration.py +3 -3
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +131 -1
- reconcile/rhidp/common.py +3 -5
- reconcile/rhidp/sso_client/base.py +1 -1
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +35 -14
- reconcile/sql_query.py +1 -0
- reconcile/status_board.py +6 -6
- reconcile/statuspage/atlassian.py +7 -7
- reconcile/statuspage/integrations/maintenances.py +4 -3
- reconcile/statuspage/page.py +4 -9
- reconcile/statuspage/status.py +5 -8
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +4 -0
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +4 -3
- reconcile/terraform_aws_route53.py +7 -1
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +5 -5
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +187 -23
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +17 -7
- reconcile/terraform_tgw_attachments.py +27 -19
- reconcile/terraform_users.py +7 -0
- reconcile/terraform_vpc_peerings.py +14 -3
- reconcile/terraform_vpc_resources/integration.py +10 -1
- reconcile/typed_queries/aws_account_tags.py +41 -0
- reconcile/typed_queries/cost_report/app_names.py +1 -1
- reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
- reconcile/typed_queries/saas_files.py +13 -13
- reconcile/typed_queries/status_board.py +2 -2
- reconcile/unleash_feature_toggles/integration.py +4 -2
- reconcile/utils/acs/base.py +6 -3
- reconcile/utils/acs/policies.py +2 -2
- reconcile/utils/aggregated_list.py +4 -3
- reconcile/utils/aws_api.py +51 -54
- reconcile/utils/aws_api_typed/api.py +38 -9
- reconcile/utils/aws_api_typed/cloudformation.py +149 -0
- reconcile/utils/aws_api_typed/logs.py +73 -0
- reconcile/utils/aws_api_typed/organization.py +4 -2
- reconcile/utils/datetime_util.py +67 -0
- reconcile/utils/deadmanssnitch_api.py +1 -1
- reconcile/utils/differ.py +2 -3
- reconcile/utils/early_exit_cache.py +11 -12
- reconcile/utils/expiration.py +7 -3
- reconcile/utils/external_resource_spec.py +24 -1
- reconcile/utils/filtering.py +1 -1
- reconcile/utils/gitlab_api.py +7 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gql.py +4 -7
- reconcile/utils/helm.py +2 -1
- reconcile/utils/helpers.py +1 -1
- reconcile/utils/instrumented_wrappers.py +1 -1
- reconcile/utils/internal_groups/client.py +2 -2
- reconcile/utils/internal_groups/models.py +8 -17
- reconcile/utils/jinja2/utils.py +6 -101
- reconcile/utils/jira_client.py +82 -63
- reconcile/utils/jjb_client.py +9 -12
- reconcile/utils/jobcontroller/controller.py +1 -1
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +70 -0
- reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
- reconcile/utils/membershipsources/models.py +16 -23
- reconcile/utils/membershipsources/resolver.py +4 -2
- reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
- reconcile/utils/merge_request_manager/parser.py +6 -6
- reconcile/utils/metrics.py +5 -5
- reconcile/utils/models.py +304 -82
- reconcile/utils/mr/app_interface_reporter.py +2 -2
- reconcile/utils/mr/base.py +2 -2
- reconcile/utils/mr/notificator.py +3 -3
- reconcile/utils/mr/update_access_report_base.py +3 -4
- reconcile/utils/mr/user_maintenance.py +3 -2
- reconcile/utils/oc.py +118 -97
- reconcile/utils/oc_filters.py +3 -3
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +17 -20
- reconcile/utils/ocm/cluster_groups.py +1 -1
- reconcile/utils/ocm/identity_providers.py +2 -2
- reconcile/utils/ocm/labels.py +1 -1
- reconcile/utils/ocm/products.py +9 -3
- reconcile/utils/ocm/search_filters.py +3 -6
- reconcile/utils/ocm/service_log.py +4 -6
- reconcile/utils/ocm/sre_capability_labels.py +20 -13
- reconcile/utils/openshift_resource.py +10 -5
- reconcile/utils/output.py +3 -2
- reconcile/utils/pagerduty_api.py +10 -7
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/raw_github_api.py +1 -1
- reconcile/utils/rhcsv2_certs.py +1 -4
- reconcile/utils/runtime/integration.py +2 -3
- reconcile/utils/runtime/runner.py +2 -2
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +25 -21
- reconcile/utils/saasherder/saasherder.py +35 -24
- reconcile/utils/slack_api.py +26 -4
- reconcile/utils/sloth.py +171 -2
- reconcile/utils/sqs_gateway.py +2 -1
- reconcile/utils/state.py +2 -1
- reconcile/utils/structs.py +1 -1
- reconcile/utils/terraform_client.py +5 -4
- reconcile/utils/terrascript_aws_client.py +171 -114
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +5 -12
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +107 -42
- tools/app_interface_reporter.py +4 -4
- tools/cli_commands/cost_report/cost_management_api.py +3 -3
- tools/cli_commands/cost_report/view.py +7 -6
- tools/cli_commands/erv2.py +3 -1
- tools/cli_commands/systems_and_tools.py +5 -1
- tools/qontract_cli.py +31 -18
- tools/template_validation.py +3 -1
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/entry_points.txt +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from pydantic import
|
|
4
|
-
from pydantic.fields import
|
|
3
|
+
from pydantic import WithJsonSchema
|
|
4
|
+
from pydantic.fields import FieldInfo
|
|
5
5
|
|
|
6
6
|
from reconcile.utils.ocm.base import (
|
|
7
7
|
LabelContainer,
|
|
@@ -22,11 +22,11 @@ def sre_capability_label_key(
|
|
|
22
22
|
return f"sre-capabilities.{sre_capability}.{config_atom}"
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def labelset_groupfield(group_prefix: str) ->
|
|
25
|
+
def labelset_groupfield(group_prefix: str) -> WithJsonSchema:
|
|
26
26
|
"""
|
|
27
27
|
Helper function to build the FieldMeta for a labelset field that groups labels.
|
|
28
28
|
"""
|
|
29
|
-
return
|
|
29
|
+
return WithJsonSchema({"group_by_prefix": group_prefix})
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def build_labelset(
|
|
@@ -36,16 +36,23 @@ def build_labelset(
|
|
|
36
36
|
Instantiates a dataclass from a set of labels.
|
|
37
37
|
"""
|
|
38
38
|
raw_data = {
|
|
39
|
-
field.alias: _labelset_field_value(labels, field)
|
|
40
|
-
for field in dataclass.
|
|
39
|
+
field.alias or name: _labelset_field_value(labels, name, field)
|
|
40
|
+
for name, field in dataclass.model_fields.items()
|
|
41
41
|
}
|
|
42
42
|
return dataclass(**raw_data)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def _labelset_field_value(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
def _labelset_field_value(
|
|
46
|
+
labels: LabelContainer, name: str, field: FieldInfo
|
|
47
|
+
) -> Any | None:
|
|
48
|
+
schema = next((m for m in field.metadata if isinstance(m, WithJsonSchema)), None)
|
|
49
|
+
if (
|
|
50
|
+
schema is None
|
|
51
|
+
or not schema.json_schema
|
|
52
|
+
or "group_by_prefix" not in schema.json_schema
|
|
53
|
+
):
|
|
54
|
+
return labels.get_label_value(field.alias or name)
|
|
55
|
+
|
|
56
|
+
return build_container_for_prefix(
|
|
57
|
+
labels, schema.json_schema["group_by_prefix"], strip_key_prefix=True
|
|
58
|
+
).get_values_dict()
|
|
@@ -4,9 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
import base64
|
|
5
5
|
import contextlib
|
|
6
6
|
import copy
|
|
7
|
-
import datetime
|
|
8
7
|
import hashlib
|
|
9
|
-
import
|
|
8
|
+
import logging
|
|
10
9
|
import re
|
|
11
10
|
from threading import Lock
|
|
12
11
|
from typing import TYPE_CHECKING, Any
|
|
@@ -15,6 +14,8 @@ import semver
|
|
|
15
14
|
from pydantic import BaseModel
|
|
16
15
|
|
|
17
16
|
from reconcile.external_resources.meta import SECRET_UPDATED_AT
|
|
17
|
+
from reconcile.utils.datetime_util import to_utc_seconds_iso_format, utc_now
|
|
18
|
+
from reconcile.utils.json import json_dumps
|
|
18
19
|
from reconcile.utils.metrics import GaugeMetric
|
|
19
20
|
|
|
20
21
|
if TYPE_CHECKING:
|
|
@@ -368,8 +369,8 @@ class OpenshiftResource:
|
|
|
368
369
|
annotations[QONTRACT_ANNOTATION_INTEGRATION] = self.integration
|
|
369
370
|
annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION] = self.integration_version
|
|
370
371
|
annotations[QONTRACT_ANNOTATION_SHA256SUM] = sha256sum
|
|
371
|
-
now =
|
|
372
|
-
annotations[QONTRACT_ANNOTATION_UPDATE] = now
|
|
372
|
+
now = utc_now()
|
|
373
|
+
annotations[QONTRACT_ANNOTATION_UPDATE] = to_utc_seconds_iso_format(now)
|
|
373
374
|
if self.caller_name:
|
|
374
375
|
annotations[QONTRACT_ANNOTATION_CALLER_NAME] = self.caller_name
|
|
375
376
|
|
|
@@ -530,7 +531,7 @@ class OpenshiftResource:
|
|
|
530
531
|
|
|
531
532
|
@staticmethod
|
|
532
533
|
def serialize(body: dict[str, Any]) -> str:
|
|
533
|
-
return
|
|
534
|
+
return json_dumps(body)
|
|
534
535
|
|
|
535
536
|
@staticmethod
|
|
536
537
|
def calculate_sha256sum(body: str) -> str:
|
|
@@ -601,6 +602,10 @@ class ResourceInventory:
|
|
|
601
602
|
resource: OpenshiftResource,
|
|
602
603
|
privileged: bool = False,
|
|
603
604
|
) -> None:
|
|
605
|
+
if cluster not in self._clusters:
|
|
606
|
+
logging.error(f"Cluster {cluster} not initialized in ResourceInventory")
|
|
607
|
+
return
|
|
608
|
+
|
|
604
609
|
if resource.kind_and_group in self._clusters[cluster][namespace]:
|
|
605
610
|
kind = resource.kind_and_group
|
|
606
611
|
else:
|
reconcile/utils/output.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import re
|
|
3
2
|
from collections.abc import Iterable, Mapping
|
|
4
3
|
|
|
5
4
|
import yaml
|
|
6
5
|
from tabulate import tabulate
|
|
7
6
|
|
|
7
|
+
from reconcile.utils.json import json_dumps
|
|
8
|
+
|
|
8
9
|
|
|
9
10
|
def print_output(
|
|
10
11
|
options: Mapping[str, str | bool],
|
|
@@ -30,7 +31,7 @@ def print_output(
|
|
|
30
31
|
)
|
|
31
32
|
print(formatted_content)
|
|
32
33
|
elif output == "json":
|
|
33
|
-
formatted_content =
|
|
34
|
+
formatted_content = json_dumps(content)
|
|
34
35
|
print(formatted_content)
|
|
35
36
|
elif output == "yaml":
|
|
36
37
|
formatted_content = yaml.dump(content)
|
reconcile/utils/pagerduty_api.py
CHANGED
|
@@ -3,8 +3,7 @@ from collections.abc import (
|
|
|
3
3
|
Callable,
|
|
4
4
|
Iterable,
|
|
5
5
|
)
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from datetime import timedelta
|
|
6
|
+
from datetime import datetime, timedelta
|
|
8
7
|
from typing import (
|
|
9
8
|
Protocol,
|
|
10
9
|
)
|
|
@@ -14,6 +13,7 @@ import requests
|
|
|
14
13
|
from pydantic import BaseModel
|
|
15
14
|
from sretoolbox.utils import retry
|
|
16
15
|
|
|
16
|
+
from reconcile.utils.datetime_util import utc_now
|
|
17
17
|
from reconcile.utils.secret_reader import (
|
|
18
18
|
HasSecret,
|
|
19
19
|
SecretReader,
|
|
@@ -52,10 +52,13 @@ class PagerDutyTarget(Protocol):
|
|
|
52
52
|
which must be implemented by a class to be compatible."""
|
|
53
53
|
|
|
54
54
|
name: str
|
|
55
|
-
instance: PagerDutyInstance
|
|
56
55
|
escalation_policy_id: str | None
|
|
57
56
|
schedule_id: str | None
|
|
58
57
|
|
|
58
|
+
@property
|
|
59
|
+
def instance(self) -> PagerDutyInstance:
|
|
60
|
+
pass
|
|
61
|
+
|
|
59
62
|
|
|
60
63
|
class PagerDutyConfig(BaseModel):
|
|
61
64
|
"""PagerDuty Config."""
|
|
@@ -80,7 +83,7 @@ class PagerDutyApi:
|
|
|
80
83
|
def get_pagerduty_users(
|
|
81
84
|
self, resource_type: str, resource_id: str
|
|
82
85
|
) -> list[pypd.User]:
|
|
83
|
-
now =
|
|
86
|
+
now = utc_now()
|
|
84
87
|
|
|
85
88
|
try:
|
|
86
89
|
if resource_type == "schedule":
|
|
@@ -103,7 +106,7 @@ class PagerDutyApi:
|
|
|
103
106
|
self.users.append(user)
|
|
104
107
|
return user.email.split("@")[0]
|
|
105
108
|
|
|
106
|
-
def get_schedule_users(self, schedule_id: str, now:
|
|
109
|
+
def get_schedule_users(self, schedule_id: str, now: datetime) -> list[pypd.User]:
|
|
107
110
|
until = now + timedelta(seconds=60)
|
|
108
111
|
s = pypd.Schedule.fetch(id=schedule_id, since=now, until=until, time_zone="UTC")
|
|
109
112
|
entries = s["final_schedule"]["rendered_schedule_entries"]
|
|
@@ -115,7 +118,7 @@ class PagerDutyApi:
|
|
|
115
118
|
]
|
|
116
119
|
|
|
117
120
|
def get_escalation_policy_users(
|
|
118
|
-
self, escalation_policy_id: str, now:
|
|
121
|
+
self, escalation_policy_id: str, now: datetime
|
|
119
122
|
) -> list[pypd.User]:
|
|
120
123
|
ep = pypd.EscalationPolicy.fetch(
|
|
121
124
|
id=escalation_policy_id, since=now, until=now, time_zone="UTC"
|
|
@@ -189,7 +192,7 @@ def get_pagerduty_name(user: PagerDutyUser) -> str:
|
|
|
189
192
|
return user.pagerduty_username or user.org_username
|
|
190
193
|
|
|
191
194
|
|
|
192
|
-
@retry(no_retry_exceptions=PagerDutyTargetError)
|
|
195
|
+
@retry(no_retry_exceptions=(PagerDutyTargetError,))
|
|
193
196
|
def get_usernames_from_pagerduty(
|
|
194
197
|
pagerduties: Iterable[PagerDutyTarget],
|
|
195
198
|
users: Iterable[PagerDutyUser],
|
|
@@ -3,13 +3,12 @@ from collections import defaultdict
|
|
|
3
3
|
|
|
4
4
|
from pydantic import (
|
|
5
5
|
BaseModel,
|
|
6
|
-
Extra,
|
|
7
6
|
)
|
|
8
7
|
|
|
9
8
|
from reconcile.utils.state import State
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class PromotionData(BaseModel):
|
|
11
|
+
class PromotionData(BaseModel, extra="forbid"):
|
|
13
12
|
"""
|
|
14
13
|
A class that strictly corresponds to the json stored in S3.
|
|
15
14
|
|
|
@@ -20,17 +19,13 @@ class PromotionData(BaseModel):
|
|
|
20
19
|
|
|
21
20
|
# The success is primarily used for SAPM auto-promotions
|
|
22
21
|
success: bool
|
|
23
|
-
target_config_hash: str | None
|
|
24
|
-
saas_file: str | None
|
|
25
|
-
check_in: str | None
|
|
22
|
+
target_config_hash: str | None = None
|
|
23
|
+
saas_file: str | None = None
|
|
24
|
+
check_in: str | None = None
|
|
26
25
|
# Whether this promotion has ever succeeded
|
|
27
26
|
# Note, this shouldnt be overridden on subsequent promotions of same ref
|
|
28
27
|
# This attribute is primarily used by saasherder validations
|
|
29
|
-
has_succeeded_once: bool | None
|
|
30
|
-
|
|
31
|
-
class Config:
|
|
32
|
-
smart_union = True
|
|
33
|
-
extra = Extra.forbid
|
|
28
|
+
has_succeeded_once: bool | None = None
|
|
34
29
|
|
|
35
30
|
|
|
36
31
|
class PromotionState:
|
|
@@ -107,5 +102,5 @@ class PromotionState:
|
|
|
107
102
|
self, sha: str, channel: str, target_uid: str, data: PromotionData
|
|
108
103
|
) -> None:
|
|
109
104
|
state_key_v2 = f"promotions_v2/{channel}/{target_uid}/{sha}"
|
|
110
|
-
self._state.add(state_key_v2, data.
|
|
105
|
+
self._state.add(state_key_v2, data.model_dump(), force=True)
|
|
111
106
|
logging.info("Uploaded %s to %s", data, state_key_v2)
|
|
@@ -76,7 +76,7 @@ class RawGithubApi:
|
|
|
76
76
|
if login is not None
|
|
77
77
|
]
|
|
78
78
|
|
|
79
|
-
def team_invitations(self, org_id: str, team_id: str) -> list[str]:
|
|
79
|
+
def team_invitations(self, org_id: str | int, team_id: str | int) -> list[str]:
|
|
80
80
|
invitations = self.query(f"/organizations/{org_id}/team/{team_id}/invitations")
|
|
81
81
|
|
|
82
82
|
return [
|
reconcile/utils/rhcsv2_certs.py
CHANGED
|
@@ -9,15 +9,12 @@ from cryptography.x509.oid import NameOID
|
|
|
9
9
|
from pydantic import BaseModel, Field
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
class RhcsV2Cert(BaseModel):
|
|
12
|
+
class RhcsV2Cert(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
13
13
|
certificate: str = Field(alias="tls.crt")
|
|
14
14
|
private_key: str = Field(alias="tls.key")
|
|
15
15
|
ca_cert: str = Field(alias="ca.crt")
|
|
16
16
|
expiration_timestamp: int
|
|
17
17
|
|
|
18
|
-
class Config:
|
|
19
|
-
allow_population_by_field_name = True
|
|
20
|
-
|
|
21
18
|
|
|
22
19
|
def extract_cert(text: str) -> re.Match:
|
|
23
20
|
# The CA webform returns an HTML page with inline JS that builds an array of “outputList”
|
|
@@ -7,7 +7,6 @@ from dataclasses import dataclass
|
|
|
7
7
|
from types import ModuleType
|
|
8
8
|
from typing import (
|
|
9
9
|
Any,
|
|
10
|
-
Generic,
|
|
11
10
|
Optional,
|
|
12
11
|
TypeVar,
|
|
13
12
|
)
|
|
@@ -120,7 +119,7 @@ class PydanticRunParams(RunParams, BaseModel):
|
|
|
120
119
|
def copy_and_update(
|
|
121
120
|
self: PydanticRunParamsSelfTypeVar, update: dict[str, Any]
|
|
122
121
|
) -> PydanticRunParamsSelfTypeVar:
|
|
123
|
-
return self.
|
|
122
|
+
return self.model_copy(update=update)
|
|
124
123
|
|
|
125
124
|
def get(self, field: str) -> Any:
|
|
126
125
|
return getattr(self, field)
|
|
@@ -144,7 +143,7 @@ IntegrationClassTypeVar = TypeVar(
|
|
|
144
143
|
)
|
|
145
144
|
|
|
146
145
|
|
|
147
|
-
class QontractReconcileIntegration
|
|
146
|
+
class QontractReconcileIntegration[RunParamsTypeVar: RunParams](ABC):
|
|
148
147
|
"""
|
|
149
148
|
The base class for all integrations. It defines the basic interface to interact
|
|
150
149
|
with an integration and offers hook methods that allow the integration to opt
|
|
@@ -156,7 +156,7 @@ def run_integration_cfg(run_cfg: IntegrationRunConfiguration) -> None:
|
|
|
156
156
|
_integration_wet_run(run_cfg.integration)
|
|
157
157
|
|
|
158
158
|
|
|
159
|
-
def _integration_wet_run(
|
|
159
|
+
def _integration_wet_run[RunParamsTypeVar: RunParams](
|
|
160
160
|
integration: QontractReconcileIntegration[RunParamsTypeVar],
|
|
161
161
|
) -> None:
|
|
162
162
|
"""
|
|
@@ -165,7 +165,7 @@ def _integration_wet_run(
|
|
|
165
165
|
integration.run(False)
|
|
166
166
|
|
|
167
167
|
|
|
168
|
-
def _integration_dry_run(
|
|
168
|
+
def _integration_dry_run[RunParamsTypeVar: RunParams](
|
|
169
169
|
integration: QontractReconcileIntegration[RunParamsTypeVar],
|
|
170
170
|
desired_state_diff: DesiredStateDiff | None,
|
|
171
171
|
) -> None:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# ruff: noqa: N801
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from collections.abc import
|
|
4
|
+
from collections.abc import Sequence
|
|
5
5
|
from typing import (
|
|
6
6
|
TYPE_CHECKING,
|
|
7
7
|
Any,
|
|
@@ -12,6 +12,8 @@ from typing import (
|
|
|
12
12
|
from reconcile.utils import oc_connection_parameters
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
|
+
from pydantic.main import IncEx
|
|
16
|
+
|
|
15
17
|
from reconcile.gql_definitions.fragments.saas_slo_document import SLODocument
|
|
16
18
|
from reconcile.utils.secret_reader import HasSecret
|
|
17
19
|
|
|
@@ -27,18 +29,12 @@ class SaasFileSecretParameters(Protocol):
|
|
|
27
29
|
@property
|
|
28
30
|
def secret(self) -> HasSecret: ...
|
|
29
31
|
|
|
30
|
-
def
|
|
31
|
-
self,
|
|
32
|
-
*,
|
|
33
|
-
by_alias: bool = False,
|
|
34
|
-
include: AbstractSetIntStr | MappingIntStrAny | None = None,
|
|
32
|
+
def model_dump(
|
|
33
|
+
self, *, by_alias: bool = False, include: IncEx | None = None
|
|
35
34
|
) -> dict[str, Any]: ...
|
|
36
35
|
|
|
37
36
|
|
|
38
37
|
SaasSecretParameters = Sequence[SaasFileSecretParameters] | None
|
|
39
|
-
# Taken from pydantic.typing
|
|
40
|
-
AbstractSetIntStr = Set[int | str]
|
|
41
|
-
MappingIntStrAny = Mapping[int | str, Any]
|
|
42
38
|
|
|
43
39
|
|
|
44
40
|
@runtime_checkable
|
|
@@ -212,11 +208,8 @@ class SaasResourceTemplateTargetNamespace(Protocol):
|
|
|
212
208
|
@property
|
|
213
209
|
def cluster(self) -> oc_connection_parameters.Cluster: ...
|
|
214
210
|
|
|
215
|
-
def
|
|
216
|
-
self,
|
|
217
|
-
*,
|
|
218
|
-
by_alias: bool = False,
|
|
219
|
-
include: AbstractSetIntStr | MappingIntStrAny | None = None,
|
|
211
|
+
def model_dump(
|
|
212
|
+
self, *, by_alias: bool = False, include: IncEx | None = None
|
|
220
213
|
) -> dict[str, Any]: ...
|
|
221
214
|
|
|
222
215
|
|
|
@@ -249,7 +242,7 @@ class SaasResourceTemplateTargetPromotion(Protocol):
|
|
|
249
242
|
@property
|
|
250
243
|
def promotion_data(self) -> Sequence[SaasPromotionData] | None: ...
|
|
251
244
|
|
|
252
|
-
def
|
|
245
|
+
def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
|
|
253
246
|
|
|
254
247
|
|
|
255
248
|
class Channel(Protocol):
|
|
@@ -274,7 +267,7 @@ class SaasPromotion(Protocol):
|
|
|
274
267
|
@property
|
|
275
268
|
def subscribe(self) -> list[Channel] | None: ...
|
|
276
269
|
|
|
277
|
-
def
|
|
270
|
+
def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
|
|
278
271
|
|
|
279
272
|
|
|
280
273
|
class SaasResourceTemplateTarget_SaasSecretParameters(Protocol):
|
|
@@ -295,7 +288,7 @@ class SaasResourceTemplateTargetUpstream(Protocol):
|
|
|
295
288
|
@property
|
|
296
289
|
def instance(self) -> SaasJenkinsInstance: ...
|
|
297
290
|
|
|
298
|
-
def
|
|
291
|
+
def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
|
|
299
292
|
|
|
300
293
|
|
|
301
294
|
class SaasQuayInstance(Protocol):
|
|
@@ -315,7 +308,7 @@ class SaasResourceTemplateTargetImage(Protocol):
|
|
|
315
308
|
@property
|
|
316
309
|
def org(self) -> SaasQuayOrg: ...
|
|
317
310
|
|
|
318
|
-
def
|
|
311
|
+
def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
|
|
319
312
|
|
|
320
313
|
|
|
321
314
|
class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
|
|
@@ -344,7 +337,7 @@ class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
|
|
|
344
337
|
self, parent_saas_file_name: str, parent_resource_template_name: str
|
|
345
338
|
) -> str: ...
|
|
346
339
|
|
|
347
|
-
def
|
|
340
|
+
def model_dump(self, *, by_alias: bool = False) -> dict[str, Any]: ...
|
|
348
341
|
|
|
349
342
|
|
|
350
343
|
class SaasResourceTemplate(HasParameters, HasSecretParameters, Protocol):
|
|
@@ -381,7 +374,7 @@ class ManagedResourceName(Protocol):
|
|
|
381
374
|
resource: str
|
|
382
375
|
resource_names: list[str]
|
|
383
376
|
|
|
384
|
-
def
|
|
377
|
+
def model_dump(self) -> dict[str, str]: ...
|
|
385
378
|
|
|
386
379
|
|
|
387
380
|
class SaasFile(HasParameters, HasSecretParameters, Protocol):
|
|
@@ -7,15 +7,13 @@ from enum import Enum
|
|
|
7
7
|
from typing import Any, NotRequired, TypedDict
|
|
8
8
|
|
|
9
9
|
from github import Github
|
|
10
|
-
from pydantic import
|
|
11
|
-
BaseModel,
|
|
12
|
-
Field,
|
|
13
|
-
)
|
|
10
|
+
from pydantic import BaseModel, Field, model_validator
|
|
14
11
|
|
|
15
12
|
from reconcile.gql_definitions.fragments.saas_slo_document import (
|
|
16
13
|
SLODocument,
|
|
17
14
|
)
|
|
18
15
|
from reconcile.utils.jenkins_api import JobBuildState
|
|
16
|
+
from reconcile.utils.json import json_dumps
|
|
19
17
|
from reconcile.utils.oc_connection_parameters import Cluster
|
|
20
18
|
from reconcile.utils.saasherder.interfaces import (
|
|
21
19
|
HasParameters,
|
|
@@ -206,7 +204,12 @@ TriggerSpecUnion = (
|
|
|
206
204
|
)
|
|
207
205
|
|
|
208
206
|
|
|
209
|
-
class Namespace(
|
|
207
|
+
class Namespace(
|
|
208
|
+
BaseModel,
|
|
209
|
+
validate_by_name=True,
|
|
210
|
+
validate_by_alias=True,
|
|
211
|
+
arbitrary_types_allowed=True,
|
|
212
|
+
):
|
|
210
213
|
name: str
|
|
211
214
|
environment: SaasEnvironment
|
|
212
215
|
app: SaasApp
|
|
@@ -216,29 +219,19 @@ class Namespace(BaseModel):
|
|
|
216
219
|
..., alias="managedResourceNames"
|
|
217
220
|
)
|
|
218
221
|
|
|
219
|
-
class Config:
|
|
220
|
-
arbitrary_types_allowed = True
|
|
221
|
-
allow_population_by_field_name = True
|
|
222
|
-
|
|
223
222
|
|
|
224
|
-
class PromotionChannelData(BaseModel):
|
|
223
|
+
class PromotionChannelData(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
225
224
|
q_type: str = Field(..., alias="type")
|
|
226
225
|
|
|
227
|
-
class Config:
|
|
228
|
-
allow_population_by_field_name = True
|
|
229
226
|
|
|
230
|
-
|
|
231
|
-
class ParentSaasPromotion(BaseModel):
|
|
227
|
+
class ParentSaasPromotion(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
232
228
|
q_type: str = Field(..., alias="type")
|
|
233
|
-
parent_saas: str | None
|
|
234
|
-
target_config_hash: str | None
|
|
235
|
-
|
|
236
|
-
class Config:
|
|
237
|
-
allow_population_by_field_name = True
|
|
229
|
+
parent_saas: str | None = None
|
|
230
|
+
target_config_hash: str | None = None
|
|
238
231
|
|
|
239
232
|
|
|
240
233
|
class PromotionData(BaseModel):
|
|
241
|
-
channel: str | None
|
|
234
|
+
channel: str | None = None
|
|
242
235
|
data: list[ParentSaasPromotion | PromotionChannelData] | None = None
|
|
243
236
|
|
|
244
237
|
|
|
@@ -263,6 +256,17 @@ class Promotion(BaseModel):
|
|
|
263
256
|
saas_file_paths: list[str] | None = None
|
|
264
257
|
target_paths: list[str] | None = None
|
|
265
258
|
|
|
259
|
+
@model_validator(mode="before")
|
|
260
|
+
@classmethod
|
|
261
|
+
def handle_gql_classes(cls, data: Any) -> Any:
|
|
262
|
+
if data.get("promotion_data"):
|
|
263
|
+
data["promotion_data"] = [
|
|
264
|
+
# convert a GQL class to a dict
|
|
265
|
+
item.model_dump() if hasattr(item, "model_dump") else item
|
|
266
|
+
for item in data["promotion_data"]
|
|
267
|
+
]
|
|
268
|
+
return data
|
|
269
|
+
|
|
266
270
|
|
|
267
271
|
@dataclass
|
|
268
272
|
class ImageAuth:
|
|
@@ -422,7 +426,7 @@ class TargetSpec:
|
|
|
422
426
|
elif v is False:
|
|
423
427
|
parameters[k] = "false"
|
|
424
428
|
elif any(isinstance(v, t) for t in [dict, list, tuple]):
|
|
425
|
-
parameters[k] =
|
|
429
|
+
parameters[k] = json_dumps(v)
|
|
426
430
|
return parameters
|
|
427
431
|
|
|
428
432
|
def _collect_secret_parameters(
|