qontract-reconcile 0.10.2.dev361__py3-none-any.whl → 0.10.2.dev474__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.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/METADATA +14 -13
- {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/RECORD +371 -364
- {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/WHEEL +1 -1
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +18 -12
- reconcile/aus/aus_sts_gate_handler.py +59 -0
- reconcile/aus/base.py +137 -34
- reconcile/aus/cluster_version_data.py +15 -5
- reconcile/aus/models.py +3 -1
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
- reconcile/aus/ocm_upgrade_scheduler.py +8 -1
- reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
- reconcile/aus/version_gate_approver.py +1 -16
- reconcile/aus/version_gates/sts_version_gate_handler.py +5 -72
- reconcile/automated_actions/config/integration.py +16 -4
- reconcile/aws_account_manager/integration.py +21 -9
- reconcile/aws_account_manager/reconciler.py +3 -3
- reconcile/aws_account_manager/utils.py +1 -1
- 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 +1 -1
- reconcile/aws_iam_keys.py +1 -0
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +30 -23
- reconcile/aws_version_sync/integration.py +6 -12
- reconcile/change_owners/README.md +1 -1
- reconcile/change_owners/bundle.py +3 -3
- reconcile/change_owners/change_log_tracking.py +3 -2
- reconcile/change_owners/change_owners.py +108 -42
- reconcile/change_owners/decision.py +1 -1
- reconcile/change_owners/diff.py +0 -2
- reconcile/checkpoint.py +11 -3
- reconcile/cli.py +94 -11
- 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 +8 -8
- reconcile/external_resources/factories.py +4 -6
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +8 -6
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +19 -15
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +6 -10
- reconcile/external_resources/state.py +26 -16
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gabi_authorized_users.py +5 -2
- 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_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 +14 -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 +18 -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 +38 -7
- reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -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 +12 -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 +775 -136
- 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 +25 -79
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
- 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 +37 -7
- 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 +8 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +6 -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 -57
- 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 +33 -27
- reconcile/openshift_base.py +113 -4
- reconcile/openshift_cluster_bots.py +1 -1
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +96 -101
- reconcile/openshift_resources_base.py +6 -2
- reconcile/openshift_rhcs_certs.py +74 -37
- reconcile/openshift_rolebindings.py +7 -11
- reconcile/openshift_saas_deploy.py +4 -5
- 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_base.py +25 -6
- reconcile/quay_membership.py +55 -29
- reconcile/quay_mirror.py +1 -1
- reconcile/quay_mirror_org.py +6 -4
- reconcile/quay_permissions.py +81 -75
- reconcile/quay_repos.py +35 -37
- reconcile/queries.py +132 -1
- reconcile/rhidp/common.py +3 -5
- reconcile/rhidp/sso_client/base.py +16 -5
- 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 +1 -1
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +1 -1
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +2 -2
- reconcile/templating/validator.py +4 -4
- 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 +6 -6
- 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 +20 -8
- reconcile/terraform_vpc_resources/merge_request.py +12 -2
- reconcile/terraform_vpc_resources/merge_request_manager.py +43 -19
- 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 +20 -15
- 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/aws_api.py +51 -20
- 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/binary.py +7 -12
- 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/environ.py +5 -0
- reconcile/utils/expiration.py +7 -3
- reconcile/utils/external_resource_spec.py +2 -0
- reconcile/utils/filtering.py +1 -1
- reconcile/utils/gitlab_api.py +19 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gql.py +4 -7
- 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 +26 -13
- reconcile/utils/jobcontroller/controller.py +2 -2
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +43 -1
- 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/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 +252 -201
- 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 +8 -8
- 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 +8 -3
- reconcile/utils/pagerduty_api.py +10 -7
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/quay_api.py +74 -87
- reconcile/utils/raw_github_api.py +1 -1
- reconcile/utils/rhcsv2_certs.py +86 -23
- reconcile/utils/rosa/session.py +16 -0
- 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 +23 -20
- reconcile/utils/saasherder/saasherder.py +50 -27
- reconcile/utils/slack_api.py +2 -2
- reconcile/utils/sloth.py +171 -2
- reconcile/utils/structs.py +1 -1
- reconcile/utils/terraform_client.py +5 -4
- reconcile/utils/terrascript_aws_client.py +274 -124
- 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
- reconcile/vpc_peerings_validator.py +13 -0
- 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 +1 -1
- tools/qontract_cli.py +28 -17
- tools/template_validation.py +3 -1
- {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev474.dist-info}/entry_points.txt +0 -0
reconcile/utils/quay_api.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
from typing import Any
|
|
2
3
|
|
|
3
4
|
import requests
|
|
4
5
|
|
|
6
|
+
from reconcile.utils.rest_api_base import ApiBase, BearerTokenAuth
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
class QuayTeamNotFoundError(Exception):
|
|
7
10
|
pass
|
|
8
11
|
|
|
9
12
|
|
|
10
|
-
class QuayApi:
|
|
13
|
+
class QuayApi(ApiBase):
|
|
11
14
|
LIMIT_FOLLOWS = 15
|
|
12
15
|
|
|
13
16
|
def __init__(
|
|
@@ -17,14 +20,18 @@ class QuayApi:
|
|
|
17
20
|
base_url: str = "quay.io",
|
|
18
21
|
timeout: int = 60,
|
|
19
22
|
) -> None:
|
|
20
|
-
|
|
23
|
+
# Support both hostname (e.g., "quay.io") and full URLs (e.g., "http://localhost:12345")
|
|
24
|
+
if base_url.startswith(("http://", "https://")):
|
|
25
|
+
host = base_url
|
|
26
|
+
else:
|
|
27
|
+
host = f"https://{base_url}"
|
|
28
|
+
super().__init__(
|
|
29
|
+
host=host,
|
|
30
|
+
auth=BearerTokenAuth(token),
|
|
31
|
+
read_timeout=timeout,
|
|
32
|
+
)
|
|
21
33
|
self.organization = organization
|
|
22
|
-
self.auth_header = {"Authorization": "Bearer %s" % (token,)}
|
|
23
34
|
self.team_members: dict[str, Any] = {}
|
|
24
|
-
self.api_url = f"https://{base_url}/api/v1"
|
|
25
|
-
|
|
26
|
-
self._timeout = timeout
|
|
27
|
-
"""Timeout to use for HTTP calls to Quay (seconds)."""
|
|
28
35
|
|
|
29
36
|
def list_team_members(self, team: str, **kwargs: Any) -> list[dict]:
|
|
30
37
|
"""
|
|
@@ -38,19 +45,20 @@ class QuayApi:
|
|
|
38
45
|
if cache_members:
|
|
39
46
|
return cache_members
|
|
40
47
|
|
|
41
|
-
url = f"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
url = f"/api/v1/organization/{self.organization}/team/{team}/members"
|
|
49
|
+
params = {"includePending": "true"}
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
body = self._get(url, params=params)
|
|
53
|
+
except requests.exceptions.HTTPError as e:
|
|
54
|
+
if e.response.status_code == 404:
|
|
55
|
+
raise QuayTeamNotFoundError(
|
|
56
|
+
f"team {team} is not found in "
|
|
57
|
+
f"org {self.organization}. "
|
|
58
|
+
f"contact org owner to create the "
|
|
59
|
+
f"team manually."
|
|
60
|
+
) from e
|
|
61
|
+
raise
|
|
54
62
|
|
|
55
63
|
# Using a set because members may be repeated
|
|
56
64
|
members = {member["name"] for member in body["members"]}
|
|
@@ -61,30 +69,37 @@ class QuayApi:
|
|
|
61
69
|
return members_list
|
|
62
70
|
|
|
63
71
|
def user_exists(self, user: str) -> bool:
|
|
64
|
-
url = f"
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
url = f"/api/v1/users/{user}"
|
|
73
|
+
try:
|
|
74
|
+
self._get(url)
|
|
75
|
+
return True
|
|
76
|
+
except requests.exceptions.HTTPError:
|
|
77
|
+
return False
|
|
67
78
|
|
|
68
79
|
def remove_user_from_team(self, user: str, team: str) -> bool:
|
|
69
80
|
"""Deletes an user from a team.
|
|
70
81
|
|
|
71
82
|
:raises HTTPError if there are any problems with the request
|
|
72
83
|
"""
|
|
73
|
-
url_team =
|
|
84
|
+
url_team = (
|
|
85
|
+
f"/api/v1/organization/{self.organization}/team/{team}/members/{user}"
|
|
86
|
+
)
|
|
74
87
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
try:
|
|
89
|
+
self._delete(url_team)
|
|
90
|
+
except requests.exceptions.HTTPError as e:
|
|
91
|
+
message = ""
|
|
92
|
+
if e.response is not None:
|
|
93
|
+
with contextlib.suppress(ValueError, AttributeError):
|
|
94
|
+
message = e.response.json().get("message", "")
|
|
78
95
|
|
|
79
96
|
expected_message = f"User {user} does not belong to team {team}"
|
|
80
97
|
|
|
81
98
|
if message != expected_message:
|
|
82
|
-
|
|
99
|
+
raise
|
|
83
100
|
|
|
84
|
-
url_org = f"
|
|
85
|
-
|
|
86
|
-
r = requests.delete(url_org, headers=self.auth_header, timeout=self._timeout)
|
|
87
|
-
r.raise_for_status()
|
|
101
|
+
url_org = f"/api/v1/organization/{self.organization}/members/{user}"
|
|
102
|
+
self._delete(url_org)
|
|
88
103
|
|
|
89
104
|
return True
|
|
90
105
|
|
|
@@ -96,9 +111,8 @@ class QuayApi:
|
|
|
96
111
|
if user in self.list_team_members(team, cache=True):
|
|
97
112
|
return True
|
|
98
113
|
|
|
99
|
-
url = f"
|
|
100
|
-
|
|
101
|
-
r.raise_for_status()
|
|
114
|
+
url = f"/api/v1/organization/{self.organization}/team/{team}/members/{user}"
|
|
115
|
+
self._put(url)
|
|
102
116
|
return True
|
|
103
117
|
|
|
104
118
|
def create_or_update_team(
|
|
@@ -115,17 +129,14 @@ class QuayApi:
|
|
|
115
129
|
:raises HTTPError: unsuccessful attempt to create the team
|
|
116
130
|
"""
|
|
117
131
|
|
|
118
|
-
url = f"
|
|
132
|
+
url = f"/api/v1/organization/{self.organization}/team/{team}"
|
|
119
133
|
|
|
120
134
|
payload = {"role": role}
|
|
121
135
|
|
|
122
136
|
if description:
|
|
123
137
|
payload.update({"description": description})
|
|
124
138
|
|
|
125
|
-
|
|
126
|
-
url, headers=self.auth_header, json=payload, timeout=self._timeout
|
|
127
|
-
)
|
|
128
|
-
r.raise_for_status()
|
|
139
|
+
self._put(url, data=payload)
|
|
129
140
|
|
|
130
141
|
def list_images(
|
|
131
142
|
self, images: list | None = None, page: str | None = None, count: int = 0
|
|
@@ -140,7 +151,7 @@ class QuayApi:
|
|
|
140
151
|
if count > self.LIMIT_FOLLOWS:
|
|
141
152
|
raise ValueError("Too many page follows")
|
|
142
153
|
|
|
143
|
-
url =
|
|
154
|
+
url = "/api/v1/repository"
|
|
144
155
|
|
|
145
156
|
# params
|
|
146
157
|
params = {"namespace": self.organization}
|
|
@@ -148,13 +159,7 @@ class QuayApi:
|
|
|
148
159
|
params["next_page"] = page
|
|
149
160
|
|
|
150
161
|
# perform request
|
|
151
|
-
|
|
152
|
-
url, params=params, headers=self.auth_header, timeout=self._timeout
|
|
153
|
-
)
|
|
154
|
-
r.raise_for_status()
|
|
155
|
-
|
|
156
|
-
# read body
|
|
157
|
-
body = r.json()
|
|
162
|
+
body = self._get(url, params=params)
|
|
158
163
|
repositories = body.get("repositories", [])
|
|
159
164
|
next_page = body.get("next_page")
|
|
160
165
|
|
|
@@ -176,7 +181,7 @@ class QuayApi:
|
|
|
176
181
|
"""
|
|
177
182
|
visibility = "public" if public else "private"
|
|
178
183
|
|
|
179
|
-
url =
|
|
184
|
+
url = "/repository"
|
|
180
185
|
|
|
181
186
|
params = {
|
|
182
187
|
"repo_kind": "image",
|
|
@@ -186,29 +191,16 @@ class QuayApi:
|
|
|
186
191
|
"description": description,
|
|
187
192
|
}
|
|
188
193
|
|
|
189
|
-
|
|
190
|
-
r = requests.post(
|
|
191
|
-
url, json=params, headers=self.auth_header, timeout=self._timeout
|
|
192
|
-
)
|
|
193
|
-
r.raise_for_status()
|
|
194
|
+
self._post(url, data=params)
|
|
194
195
|
|
|
195
196
|
def repo_delete(self, repo_name: str) -> None:
|
|
196
|
-
url = f"
|
|
197
|
-
|
|
198
|
-
# perform request
|
|
199
|
-
r = requests.delete(url, headers=self.auth_header, timeout=self._timeout)
|
|
200
|
-
r.raise_for_status()
|
|
197
|
+
url = f"/api/v1/repository/{self.organization}/{repo_name}"
|
|
198
|
+
self._delete(url)
|
|
201
199
|
|
|
202
200
|
def repo_update_description(self, repo_name: str, description: str) -> None:
|
|
203
|
-
url = f"
|
|
204
|
-
|
|
201
|
+
url = f"/api/v1/repository/{self.organization}/{repo_name}"
|
|
205
202
|
params = {"description": description}
|
|
206
|
-
|
|
207
|
-
# perform request
|
|
208
|
-
r = requests.put(
|
|
209
|
-
url, json=params, headers=self.auth_header, timeout=self._timeout
|
|
210
|
-
)
|
|
211
|
-
r.raise_for_status()
|
|
203
|
+
self._put(url, data=params)
|
|
212
204
|
|
|
213
205
|
def repo_make_public(self, repo_name: str) -> None:
|
|
214
206
|
self._repo_change_visibility(repo_name, "public")
|
|
@@ -217,39 +209,34 @@ class QuayApi:
|
|
|
217
209
|
self._repo_change_visibility(repo_name, "private")
|
|
218
210
|
|
|
219
211
|
def _repo_change_visibility(self, repo_name: str, visibility: str) -> None:
|
|
220
|
-
url = f"
|
|
221
|
-
|
|
212
|
+
url = f"/api/v1/repository/{self.organization}/{repo_name}/changevisibility"
|
|
222
213
|
params = {"visibility": visibility}
|
|
223
|
-
|
|
224
|
-
# perform request
|
|
225
|
-
r = requests.post(
|
|
226
|
-
url, json=params, headers=self.auth_header, timeout=self._timeout
|
|
227
|
-
)
|
|
228
|
-
r.raise_for_status()
|
|
214
|
+
self._post(url, data=params)
|
|
229
215
|
|
|
230
216
|
def get_repo_team_permissions(self, repo_name: str, team: str) -> str | None:
|
|
231
217
|
url = (
|
|
232
|
-
f"
|
|
218
|
+
f"/api/v1/repository/{self.organization}/"
|
|
233
219
|
+ f"{repo_name}/permissions/team/{team}"
|
|
234
220
|
)
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
221
|
+
try:
|
|
222
|
+
body = self._get(url)
|
|
223
|
+
return body.get("role") or None
|
|
224
|
+
except requests.exceptions.HTTPError as e:
|
|
225
|
+
message = ""
|
|
226
|
+
if e.response is not None:
|
|
227
|
+
with contextlib.suppress(ValueError, AttributeError):
|
|
228
|
+
message = e.response.json().get("message", "")
|
|
229
|
+
|
|
238
230
|
expected_message = "Team does not have permission for repo."
|
|
239
231
|
if message == expected_message:
|
|
240
232
|
return None
|
|
241
233
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return r.json().get("role") or None
|
|
234
|
+
raise
|
|
245
235
|
|
|
246
236
|
def set_repo_team_permissions(self, repo_name: str, team: str, role: str) -> None:
|
|
247
237
|
url = (
|
|
248
|
-
f"
|
|
238
|
+
f"/api/v1/repository/{self.organization}/"
|
|
249
239
|
+ f"{repo_name}/permissions/team/{team}"
|
|
250
240
|
)
|
|
251
241
|
body = {"role": role}
|
|
252
|
-
|
|
253
|
-
url, json=body, headers=self.auth_header, timeout=self._timeout
|
|
254
|
-
)
|
|
255
|
-
r.raise_for_status()
|
|
242
|
+
self._put(url, data=body)
|
|
@@ -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
|
@@ -1,22 +1,33 @@
|
|
|
1
|
+
import base64
|
|
1
2
|
import re
|
|
2
3
|
from datetime import UTC
|
|
4
|
+
from enum import StrEnum
|
|
3
5
|
|
|
4
6
|
import requests
|
|
5
7
|
from cryptography import x509
|
|
6
8
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
7
9
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
10
|
+
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
8
11
|
from cryptography.x509.oid import NameOID
|
|
9
12
|
from pydantic import BaseModel, Field
|
|
10
13
|
|
|
11
14
|
|
|
12
|
-
class
|
|
15
|
+
class CertificateFormat(StrEnum):
|
|
16
|
+
PEM = "PEM"
|
|
17
|
+
PKCS12 = "PKCS12"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RhcsV2CertPem(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
13
21
|
certificate: str = Field(alias="tls.crt")
|
|
14
22
|
private_key: str = Field(alias="tls.key")
|
|
15
23
|
ca_cert: str = Field(alias="ca.crt")
|
|
16
24
|
expiration_timestamp: int
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
class RhcsV2CertPkcs12(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
28
|
+
pkcs12_keystore: str = Field(alias="keystore.pkcs12.b64")
|
|
29
|
+
pkcs12_truststore: str = Field(alias="truststore.pkcs12.b64")
|
|
30
|
+
expiration_timestamp: int
|
|
20
31
|
|
|
21
32
|
|
|
22
33
|
def extract_cert(text: str) -> re.Match:
|
|
@@ -70,7 +81,66 @@ def get_cert_expiry_timestamp(js_escaped_pem: str) -> int:
|
|
|
70
81
|
return int(dt_expiry.timestamp())
|
|
71
82
|
|
|
72
83
|
|
|
73
|
-
def
|
|
84
|
+
def _format_pem(
|
|
85
|
+
private_key: rsa.RSAPrivateKey,
|
|
86
|
+
cert_pem: str,
|
|
87
|
+
ca_pem: str,
|
|
88
|
+
cert_expiry_timestamp: int,
|
|
89
|
+
) -> RhcsV2CertPem:
|
|
90
|
+
"""Generate RhcsV2Cert with PEM components."""
|
|
91
|
+
private_key_pem = private_key.private_bytes(
|
|
92
|
+
encoding=serialization.Encoding.PEM,
|
|
93
|
+
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
94
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
95
|
+
).decode()
|
|
96
|
+
return RhcsV2CertPem(
|
|
97
|
+
private_key=private_key_pem,
|
|
98
|
+
certificate=cert_pem.encode().decode("unicode_escape").replace("\\/", "/"),
|
|
99
|
+
ca_cert=ca_pem,
|
|
100
|
+
expiration_timestamp=cert_expiry_timestamp,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _format_pkcs12(
|
|
105
|
+
private_key: rsa.RSAPrivateKey,
|
|
106
|
+
cert_pem: str,
|
|
107
|
+
ca_pem: str,
|
|
108
|
+
uid: str,
|
|
109
|
+
pwd: str,
|
|
110
|
+
cert_expiry_timestamp: int,
|
|
111
|
+
) -> RhcsV2CertPkcs12:
|
|
112
|
+
"""Generate PKCS#12 keystore and truststore components, returns base64-encoded strings."""
|
|
113
|
+
clean_cert_pem = cert_pem.encode().decode("unicode_escape").replace("\\/", "/")
|
|
114
|
+
cert_obj = x509.load_pem_x509_certificate(clean_cert_pem.encode())
|
|
115
|
+
ca_obj = x509.load_pem_x509_certificate(ca_pem.encode())
|
|
116
|
+
keystore_p12 = pkcs12.serialize_key_and_certificates(
|
|
117
|
+
name=uid.encode("utf-8"),
|
|
118
|
+
key=private_key,
|
|
119
|
+
cert=cert_obj,
|
|
120
|
+
cas=[ca_obj],
|
|
121
|
+
encryption_algorithm=serialization.BestAvailableEncryption(pwd.encode("utf-8")),
|
|
122
|
+
)
|
|
123
|
+
truststore_p12 = pkcs12.serialize_key_and_certificates(
|
|
124
|
+
name=b"ca-trust",
|
|
125
|
+
key=None,
|
|
126
|
+
cert=None,
|
|
127
|
+
cas=[ca_obj],
|
|
128
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
129
|
+
)
|
|
130
|
+
return RhcsV2CertPkcs12(
|
|
131
|
+
pkcs12_keystore=base64.b64encode(keystore_p12).decode("utf-8"),
|
|
132
|
+
pkcs12_truststore=base64.b64encode(truststore_p12).decode("utf-8"),
|
|
133
|
+
expiration_timestamp=cert_expiry_timestamp,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def generate_cert(
|
|
138
|
+
issuer_url: str,
|
|
139
|
+
uid: str,
|
|
140
|
+
pwd: str,
|
|
141
|
+
ca_url: str,
|
|
142
|
+
cert_format: CertificateFormat = CertificateFormat.PEM,
|
|
143
|
+
) -> RhcsV2CertPem | RhcsV2CertPkcs12:
|
|
74
144
|
private_key = rsa.generate_private_key(65537, 4096)
|
|
75
145
|
csr = (
|
|
76
146
|
x509.CertificateSigningRequestBuilder()
|
|
@@ -81,6 +151,7 @@ def generate_cert(issuer_url: str, uid: str, pwd: str, ca_url: str) -> RhcsV2Cer
|
|
|
81
151
|
)
|
|
82
152
|
.sign(private_key, hashes.SHA256())
|
|
83
153
|
)
|
|
154
|
+
|
|
84
155
|
data = {
|
|
85
156
|
"uid": uid,
|
|
86
157
|
"pwd": pwd,
|
|
@@ -90,27 +161,19 @@ def generate_cert(issuer_url: str, uid: str, pwd: str, ca_url: str) -> RhcsV2Cer
|
|
|
90
161
|
"renewal": "false",
|
|
91
162
|
"xmlOutput": "false",
|
|
92
163
|
}
|
|
93
|
-
response = requests.post(issuer_url, data=data)
|
|
164
|
+
response = requests.post(issuer_url, data=data, timeout=30)
|
|
94
165
|
response.raise_for_status()
|
|
166
|
+
cert_pem = extract_cert(response.text).group(1)
|
|
167
|
+
cert_expiry_timestamp = get_cert_expiry_timestamp(cert_pem)
|
|
95
168
|
|
|
96
|
-
|
|
97
|
-
cert_expiry_timestamp = get_cert_expiry_timestamp(cert_pem.group(1))
|
|
98
|
-
private_key_pem = private_key.private_bytes(
|
|
99
|
-
encoding=serialization.Encoding.PEM,
|
|
100
|
-
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
101
|
-
encryption_algorithm=serialization.NoEncryption(),
|
|
102
|
-
).decode()
|
|
103
|
-
|
|
104
|
-
response = requests.get(ca_url)
|
|
169
|
+
response = requests.get(ca_url, timeout=30)
|
|
105
170
|
response.raise_for_status()
|
|
106
171
|
ca_pem = response.text
|
|
107
172
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
expiration_timestamp=cert_expiry_timestamp,
|
|
116
|
-
)
|
|
173
|
+
match cert_format:
|
|
174
|
+
case CertificateFormat.PKCS12:
|
|
175
|
+
return _format_pkcs12(
|
|
176
|
+
private_key, cert_pem, ca_pem, uid, pwd, cert_expiry_timestamp
|
|
177
|
+
)
|
|
178
|
+
case CertificateFormat.PEM:
|
|
179
|
+
return _format_pem(private_key, cert_pem, ca_pem, cert_expiry_timestamp)
|
reconcile/utils/rosa/session.py
CHANGED
|
@@ -178,6 +178,22 @@ class RosaSession:
|
|
|
178
178
|
)
|
|
179
179
|
result.write_logs_to_logger(logging.info)
|
|
180
180
|
|
|
181
|
+
def upgrade_rosa_roles(
|
|
182
|
+
self,
|
|
183
|
+
cluster_name: str,
|
|
184
|
+
upgrade_version: str,
|
|
185
|
+
policy_version: str,
|
|
186
|
+
dry_run: bool,
|
|
187
|
+
) -> None:
|
|
188
|
+
logging.info(
|
|
189
|
+
f"Upgrade roles in AWS account {self.aws_account_id} to {upgrade_version}"
|
|
190
|
+
)
|
|
191
|
+
if not dry_run:
|
|
192
|
+
result = self.cli_execute(
|
|
193
|
+
f"rosa upgrade roles -c {cluster_name} --cluster-version {upgrade_version} --policy-version {policy_version} -y -m=auto"
|
|
194
|
+
)
|
|
195
|
+
result.write_logs_to_logger(logging.info)
|
|
196
|
+
|
|
181
197
|
|
|
182
198
|
def generate_rosa_creation_script(
|
|
183
199
|
cluster_name: str, cluster: OCMSpec, dry_run: bool
|
|
@@ -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):
|