qontract-reconcile 0.10.2.dev310__py3-none-any.whl → 0.10.2.dev439__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.
Potentially problematic release.
This version of qontract-reconcile might be problematic. Click here for more details.
- {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/METADATA +13 -12
- {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/RECORD +396 -391
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +18 -12
- reconcile/aus/base.py +134 -32
- 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_gates/sts_version_gate_handler.py +54 -1
- reconcile/automated_actions/config/integration.py +16 -4
- 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 +5 -5
- reconcile/aws_iam_keys.py +1 -0
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +32 -25
- reconcile/aws_version_sync/integration.py +125 -84
- 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 +12 -4
- reconcile/cli.py +111 -18
- reconcile/cluster_deployment_mapper.py +2 -3
- reconcile/dashdotdb_dora.py +5 -12
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +125 -121
- reconcile/deadmanssnitch.py +1 -5
- 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 +8 -5
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +20 -20
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +10 -14
- reconcile/external_resources/state.py +26 -16
- 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 +10 -10
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +6 -6
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +32 -32
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +26 -26
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +6 -7
- 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 +51 -12
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +11 -11
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +28 -68
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +10 -10
- 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 +9 -9
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +18 -18
- reconcile/gql_definitions/common/alerting_services_settings.py +9 -9
- 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 +120 -0
- reconcile/gql_definitions/common/app_interface_state_settings.py +10 -10
- 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 +22 -9
- reconcile/gql_definitions/common/aws_vpcs.py +11 -11
- reconcile/gql_definitions/common/clusters.py +37 -35
- reconcile/gql_definitions/common/clusters_minimal.py +14 -14
- reconcile/gql_definitions/common/clusters_with_dms.py +6 -6
- reconcile/gql_definitions/common/clusters_with_peering.py +29 -30
- reconcile/gql_definitions/common/github_orgs.py +10 -10
- reconcile/gql_definitions/common/jira_settings.py +10 -10
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +42 -44
- reconcile/gql_definitions/common/namespaces_minimal.py +15 -13
- reconcile/gql_definitions/common/ocm_env_telemeter.py +12 -12
- reconcile/gql_definitions/common/ocm_environments.py +19 -19
- reconcile/gql_definitions/common/pagerduty_instances.py +9 -9
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +6 -6
- reconcile/gql_definitions/common/pipeline_providers.py +29 -29
- 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 +44 -44
- reconcile/gql_definitions/common/saas_target_namespaces.py +10 -10
- 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 +19 -19
- reconcile/gql_definitions/common/state_aws_account.py +7 -8
- 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 +9 -9
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +43 -43
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +10 -10
- 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 +8 -8
- reconcile/gql_definitions/email_sender/users.py +6 -6
- reconcile/gql_definitions/endpoints_discovery/apps.py +10 -10
- reconcile/gql_definitions/external_resources/aws_accounts.py +9 -9
- reconcile/gql_definitions/external_resources/external_resources_modules.py +23 -23
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +494 -410
- reconcile/gql_definitions/external_resources/external_resources_settings.py +28 -26
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +40 -40
- 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_vpc_request_subnet.py → aws_organization.py} +12 -8
- 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 +9 -9
- reconcile/gql_definitions/gcp/gcp_projects.py +9 -9
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +9 -9
- reconcile/gql_definitions/gitlab_members/permissions.py +9 -9
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +9 -9
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +11 -11
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +9 -9
- reconcile/gql_definitions/integrations/integrations.py +48 -51
- reconcile/gql_definitions/introspection.json +3510 -1865
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +11 -11
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +10 -10
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +14 -10
- reconcile/gql_definitions/jumphosts/jumphosts.py +13 -13
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +9 -9
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +18 -19
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +22 -22
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +6 -6
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +10 -10
- reconcile/gql_definitions/quay_membership/quay_membership.py +6 -6
- reconcile/gql_definitions/rhcs/certs.py +33 -87
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
- reconcile/gql_definitions/rhidp/organizations.py +18 -18
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +8 -8
- reconcile/gql_definitions/sharding/aws_accounts.py +10 -10
- reconcile/gql_definitions/sharding/ocm_organization.py +8 -8
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +10 -10
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +9 -9
- 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 +6 -7
- reconcile/gql_definitions/statuspage/statuspages.py +9 -9
- 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 +6 -6
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +11 -11
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +11 -11
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +20 -25
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +6 -6
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +12 -12
- reconcile/gql_definitions/terraform_init/aws_accounts.py +23 -9
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +9 -9
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +450 -402
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +23 -17
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +9 -9
- reconcile/gql_definitions/vault_instances/vault_instances.py +61 -61
- reconcile/gql_definitions/vault_policies/vault_policies.py +11 -11
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +8 -8
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_job_builder.py +1 -1
- reconcile/jenkins_worker_fleets.py +80 -11
- 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 +33 -27
- reconcile/openshift_base.py +122 -10
- reconcile/openshift_cluster_bots.py +5 -5
- reconcile/openshift_groups.py +5 -0
- reconcile/openshift_limitranges.py +1 -1
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +10 -5
- reconcile/openshift_rhcs_certs.py +77 -40
- reconcile/openshift_rolebindings.py +230 -130
- 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 +8 -7
- reconcile/openshift_tekton_resources.py +1 -1
- reconcile/openshift_upgrade_watcher.py +4 -4
- reconcile/openshift_users.py +5 -3
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/oum/providers.py +1 -1
- reconcile/prometheus_rules_tester/integration.py +4 -4
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +131 -0
- reconcile/requests_sender.py +8 -3
- reconcile/resource_scraper.py +1 -5
- reconcile/rhidp/common.py +3 -5
- reconcile/rhidp/sso_client/base.py +19 -10
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
- reconcile/sendgrid_teammates.py +20 -9
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +35 -14
- reconcile/sql_query.py +1 -0
- reconcile/status.py +2 -2
- 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 +5 -1
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +4 -1
- reconcile/templating/lib/merge_request_manager.py +2 -2
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +12 -13
- reconcile/terraform_aws_route53.py +18 -8
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +12 -13
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +187 -23
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +18 -10
- reconcile/terraform_tgw_attachments.py +28 -20
- reconcile/terraform_users.py +27 -22
- reconcile/terraform_vpc_peerings.py +15 -3
- reconcile/terraform_vpc_resources/integration.py +23 -8
- reconcile/typed_queries/app_interface_roles.py +10 -0
- 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 -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/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/gpg.py +5 -3
- reconcile/utils/gql.py +4 -7
- reconcile/utils/helm.py +2 -1
- reconcile/utils/helpers.py +1 -1
- reconcile/utils/imap_client.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/jenkins_api.py +24 -1
- reconcile/utils/jinja2/utils.py +6 -8
- reconcile/utils/jira_client.py +82 -63
- reconcile/utils/jjb_client.py +78 -46
- reconcile/utils/jobcontroller/controller.py +2 -2
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +74 -0
- reconcile/utils/ldap_client.py +4 -3
- reconcile/utils/lean_terraform_client.py +3 -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/__init__.py +3 -1
- reconcile/utils/mr/app_interface_reporter.py +6 -3
- reconcile/utils/mr/aws_access.py +1 -1
- reconcile/utils/mr/base.py +7 -13
- reconcile/utils/mr/clusters_updates.py +4 -2
- reconcile/utils/mr/notificator.py +3 -3
- reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +4 -1
- reconcile/utils/mr/promote_qontract.py +28 -12
- reconcile/utils/mr/update_access_report_base.py +3 -4
- reconcile/utils/mr/user_maintenance.py +7 -6
- reconcile/utils/oc.py +445 -336
- reconcile/utils/oc_filters.py +3 -3
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +18 -21
- 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/ocm.py +81 -71
- 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/ocm_base_client.py +4 -4
- reconcile/utils/openshift_resource.py +83 -52
- reconcile/utils/openssl.py +2 -2
- 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 +11 -8
- reconcile/utils/repo_owners.py +21 -29
- reconcile/utils/rhcsv2_certs.py +138 -35
- reconcile/utils/rosa/session.py +16 -0
- reconcile/utils/runtime/integration.py +2 -3
- reconcile/utils/runtime/meta.py +2 -1
- 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 +60 -32
- reconcile/utils/secret_reader.py +6 -6
- reconcile/utils/sharding.py +1 -1
- reconcile/utils/slack_api.py +26 -4
- reconcile/utils/sloth.py +224 -0
- reconcile/utils/sqs_gateway.py +16 -11
- reconcile/utils/state.py +2 -1
- reconcile/utils/structs.py +1 -1
- reconcile/utils/terraform_client.py +29 -26
- reconcile/utils/terrascript_aws_client.py +200 -116
- reconcile/utils/three_way_diff_strategy.py +1 -1
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +44 -41
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +119 -58
- 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/cli_commands/gpg_encrypt.py +4 -1
- tools/cli_commands/systems_and_tools.py +5 -1
- tools/qontract_cli.py +36 -21
- tools/template_validation.py +3 -1
- reconcile/gql_definitions/ocm_oidc_idp/__init__.py +0 -0
- reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
- reconcile/jenkins/__init__.py +0 -0
- reconcile/jenkins/types.py +0 -77
- {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev310.dist-info → qontract_reconcile-0.10.2.dev439.dist-info}/entry_points.txt +0 -0
|
@@ -9,10 +9,9 @@ from string import (
|
|
|
9
9
|
from typing import (
|
|
10
10
|
Any,
|
|
11
11
|
TypedDict,
|
|
12
|
-
cast,
|
|
13
12
|
)
|
|
14
13
|
|
|
15
|
-
from pydantic import BaseModel
|
|
14
|
+
from pydantic import BaseModel, Field
|
|
16
15
|
from sretoolbox.container.image import Image
|
|
17
16
|
|
|
18
17
|
from reconcile import openshift_base, queries
|
|
@@ -44,7 +43,6 @@ from reconcile.utils.state import (
|
|
|
44
43
|
)
|
|
45
44
|
from reconcile.utils.vault import (
|
|
46
45
|
VaultClient,
|
|
47
|
-
_VaultClient,
|
|
48
46
|
)
|
|
49
47
|
|
|
50
48
|
QONTRACT_INTEGRATION = "database-access-manager"
|
|
@@ -63,17 +61,19 @@ def get_database_access_namespaces(
|
|
|
63
61
|
return query(query_func).namespaces_v1 or []
|
|
64
62
|
|
|
65
63
|
|
|
66
|
-
class DatabaseConnectionParameters(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
class DatabaseConnectionParameters(
|
|
65
|
+
BaseModel, validate_by_name=True, validate_by_alias=True
|
|
66
|
+
):
|
|
67
|
+
host: str = Field(..., alias="db.host")
|
|
68
|
+
port: str = Field(..., alias="db.port")
|
|
69
|
+
user: str = Field(..., alias="db.user")
|
|
70
|
+
password: str = Field(..., alias="db.password")
|
|
71
|
+
database: str = Field(..., alias="db.name")
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
class PSQLScriptGenerator(BaseModel):
|
|
75
75
|
db_access: DatabaseAccessV1
|
|
76
|
-
current_db_access: DatabaseAccessV1 | None
|
|
76
|
+
current_db_access: DatabaseAccessV1 | None = None
|
|
77
77
|
connection_parameter: DatabaseConnectionParameters
|
|
78
78
|
admin_connection_parameter: DatabaseConnectionParameters
|
|
79
79
|
engine: str
|
|
@@ -227,7 +227,7 @@ def get_db_engine(resource: NamespaceTerraformResourceRDSV1) -> str:
|
|
|
227
227
|
|
|
228
228
|
class JobData(BaseModel):
|
|
229
229
|
engine: str
|
|
230
|
-
|
|
230
|
+
name: str
|
|
231
231
|
image: str
|
|
232
232
|
service_account_name: str
|
|
233
233
|
rds_admin_secret_name: str
|
|
@@ -236,7 +236,7 @@ class JobData(BaseModel):
|
|
|
236
236
|
|
|
237
237
|
|
|
238
238
|
def get_job_spec(job_data: JobData) -> OpenshiftResource:
|
|
239
|
-
job_name =
|
|
239
|
+
job_name = job_data.name
|
|
240
240
|
|
|
241
241
|
image_tag = Image(job_data.image).tag
|
|
242
242
|
image_pull_policy = "Always" if image_tag == "latest" else "IfNotPresent"
|
|
@@ -393,14 +393,6 @@ def get_service_account_spec(name: str) -> OpenshiftResource:
|
|
|
393
393
|
)
|
|
394
394
|
|
|
395
395
|
|
|
396
|
-
class DBAMResource(BaseModel):
|
|
397
|
-
resource: OpenshiftResource
|
|
398
|
-
clean_up: bool
|
|
399
|
-
|
|
400
|
-
class Config:
|
|
401
|
-
arbitrary_types_allowed = True
|
|
402
|
-
|
|
403
|
-
|
|
404
396
|
class JobStatusCondition(BaseModel):
|
|
405
397
|
type: str
|
|
406
398
|
|
|
@@ -426,18 +418,12 @@ def _populate_resources(
|
|
|
426
418
|
user_connection: DatabaseConnectionParameters,
|
|
427
419
|
admin_connection: DatabaseConnectionParameters,
|
|
428
420
|
current_db_access: DatabaseAccessV1 | None = None,
|
|
429
|
-
) -> list[
|
|
421
|
+
) -> list[OpenshiftResource]:
|
|
430
422
|
if user_connection.database == admin_connection.database:
|
|
431
423
|
raise ValueError(f"Can not use default database {admin_connection.database}")
|
|
432
424
|
|
|
433
|
-
managed_resources: list[DBAMResource] = []
|
|
434
425
|
# create service account
|
|
435
|
-
|
|
436
|
-
DBAMResource(
|
|
437
|
-
resource=get_service_account_spec(resource_prefix),
|
|
438
|
-
clean_up=True,
|
|
439
|
-
)
|
|
440
|
-
)
|
|
426
|
+
service_account_resource = get_service_account_spec(resource_prefix)
|
|
441
427
|
|
|
442
428
|
# create script secret
|
|
443
429
|
generator = PSQLScriptGenerator(
|
|
@@ -448,74 +434,107 @@ def _populate_resources(
|
|
|
448
434
|
engine=engine,
|
|
449
435
|
)
|
|
450
436
|
script_secret_name = f"{resource_prefix}-script"
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
clean_up=False,
|
|
463
|
-
),
|
|
464
|
-
])
|
|
437
|
+
secret_script_resource = generate_script_secret_spec(
|
|
438
|
+
script_secret_name,
|
|
439
|
+
generator.generate_script(),
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
# create user secret
|
|
443
|
+
user_secret_resource = generate_user_secret_spec(
|
|
444
|
+
resource_prefix,
|
|
445
|
+
user_connection,
|
|
446
|
+
)
|
|
447
|
+
|
|
465
448
|
# create pull secret
|
|
466
|
-
|
|
467
|
-
pull_secret_resources = orb.fetch_provider_vault_secret(
|
|
449
|
+
pull_secret_resource = orb.fetch_provider_vault_secret(
|
|
468
450
|
path=pull_secret["path"],
|
|
469
451
|
version=pull_secret["version"],
|
|
470
452
|
name=f"{resource_prefix}-pull-secret",
|
|
471
|
-
labels=labels,
|
|
453
|
+
labels=pull_secret["labels"] or {},
|
|
472
454
|
annotations=pull_secret["annotations"] or {},
|
|
473
455
|
type=pull_secret["type"],
|
|
474
456
|
integration=QONTRACT_INTEGRATION,
|
|
475
457
|
integration_version=QONTRACT_INTEGRATION_VERSION,
|
|
476
458
|
settings=settings,
|
|
477
459
|
)
|
|
478
|
-
managed_resources.extend([
|
|
479
|
-
DBAMResource(resource=pull_secret_resources, clean_up=True),
|
|
480
|
-
# create job
|
|
481
|
-
DBAMResource(
|
|
482
|
-
resource=get_job_spec(
|
|
483
|
-
JobData(
|
|
484
|
-
engine=engine,
|
|
485
|
-
name_suffix=db_access.name,
|
|
486
|
-
image=job_image,
|
|
487
|
-
service_account_name=resource_prefix,
|
|
488
|
-
rds_admin_secret_name=admin_secret_name,
|
|
489
|
-
script_secret_name=script_secret_name,
|
|
490
|
-
pull_secret=f"{resource_prefix}-pull-secret",
|
|
491
|
-
)
|
|
492
|
-
),
|
|
493
|
-
clean_up=True,
|
|
494
|
-
),
|
|
495
|
-
])
|
|
496
460
|
|
|
497
|
-
|
|
461
|
+
job_resource = get_job_spec(
|
|
462
|
+
JobData(
|
|
463
|
+
engine=engine,
|
|
464
|
+
name=resource_prefix,
|
|
465
|
+
image=job_image,
|
|
466
|
+
service_account_name=resource_prefix,
|
|
467
|
+
rds_admin_secret_name=admin_secret_name,
|
|
468
|
+
script_secret_name=script_secret_name,
|
|
469
|
+
pull_secret=f"{resource_prefix}-pull-secret",
|
|
470
|
+
)
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
return [
|
|
474
|
+
service_account_resource,
|
|
475
|
+
secret_script_resource,
|
|
476
|
+
user_secret_resource,
|
|
477
|
+
pull_secret_resource,
|
|
478
|
+
job_resource,
|
|
479
|
+
]
|
|
498
480
|
|
|
499
481
|
|
|
500
482
|
def _generate_password() -> str:
|
|
501
483
|
return "".join(choices(ascii_letters + digits, k=32))
|
|
502
484
|
|
|
503
485
|
|
|
504
|
-
class
|
|
486
|
+
class DBConnections(TypedDict):
|
|
505
487
|
user: DatabaseConnectionParameters
|
|
506
488
|
admin: DatabaseConnectionParameters
|
|
507
489
|
|
|
508
490
|
|
|
491
|
+
def _decode_secret_value(value: str) -> str:
|
|
492
|
+
return base64.b64decode(value).decode("utf-8")
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
def _build_user_connection(
|
|
496
|
+
db_access: DatabaseAccessV1,
|
|
497
|
+
admin_secret: dict[str, Any],
|
|
498
|
+
user_secret: dict[str, Any],
|
|
499
|
+
) -> DatabaseConnectionParameters:
|
|
500
|
+
"""
|
|
501
|
+
Build user connection parameters.
|
|
502
|
+
|
|
503
|
+
If user secret exists, use values from it as that's the one used to provision new database user.
|
|
504
|
+
Otherwise, generate a new password, this info will be saved as cluster secret.
|
|
505
|
+
After job completes, the secret will be saved to vault then deleted from the cluster.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
db_access (DatabaseAccessV1): Database access definition from app-interface.
|
|
509
|
+
admin_secret (dict[str, Any]): Admin secret fetched from the cluster.
|
|
510
|
+
user_secret (dict[str, Any]): User secret fetched from the cluster, may be empty if not exists.
|
|
511
|
+
Returns:
|
|
512
|
+
DatabaseConnectionParameters: Connection parameters for the database user.
|
|
513
|
+
"""
|
|
514
|
+
if user_secret:
|
|
515
|
+
return DatabaseConnectionParameters(
|
|
516
|
+
host=_decode_secret_value(user_secret["data"]["db.host"]),
|
|
517
|
+
port=_decode_secret_value(user_secret["data"]["db.port"]),
|
|
518
|
+
user=_decode_secret_value(user_secret["data"]["db.user"]),
|
|
519
|
+
password=_decode_secret_value(user_secret["data"]["db.password"]),
|
|
520
|
+
database=_decode_secret_value(user_secret["data"]["db.name"]),
|
|
521
|
+
)
|
|
522
|
+
return DatabaseConnectionParameters(
|
|
523
|
+
host=_decode_secret_value(admin_secret["data"]["db.host"]),
|
|
524
|
+
port=_decode_secret_value(admin_secret["data"]["db.port"]),
|
|
525
|
+
user=db_access.username,
|
|
526
|
+
password=_generate_password(),
|
|
527
|
+
database=db_access.database,
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
|
|
509
531
|
def _create_database_connection_parameter(
|
|
510
532
|
db_access: DatabaseAccessV1,
|
|
511
533
|
namespace_name: str,
|
|
512
534
|
oc: OCClient,
|
|
513
535
|
admin_secret_name: str,
|
|
514
536
|
user_secret_name: str,
|
|
515
|
-
) ->
|
|
516
|
-
def _decode_secret_value(value: str) -> str:
|
|
517
|
-
return base64.b64decode(value).decode("utf-8")
|
|
518
|
-
|
|
537
|
+
) -> DBConnections:
|
|
519
538
|
user_secret = oc.get(
|
|
520
539
|
namespace_name,
|
|
521
540
|
"Secret",
|
|
@@ -528,26 +547,11 @@ def _create_database_connection_parameter(
|
|
|
528
547
|
admin_secret_name,
|
|
529
548
|
allow_not_found=False,
|
|
530
549
|
)
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
port = _decode_secret_value(user_secret["data"]["db.port"])
|
|
537
|
-
database = _decode_secret_value(user_secret["data"]["db.name"])
|
|
538
|
-
else:
|
|
539
|
-
host = _decode_secret_value(admin_secret["data"]["db.host"])
|
|
540
|
-
port = _decode_secret_value(admin_secret["data"]["db.port"])
|
|
541
|
-
user = db_access.username
|
|
542
|
-
password = _generate_password()
|
|
543
|
-
database = db_access.database
|
|
544
|
-
return _DBDonnections(
|
|
545
|
-
user=DatabaseConnectionParameters(
|
|
546
|
-
host=host,
|
|
547
|
-
port=port,
|
|
548
|
-
user=user,
|
|
549
|
-
password=password,
|
|
550
|
-
database=database,
|
|
550
|
+
return DBConnections(
|
|
551
|
+
user=_build_user_connection(
|
|
552
|
+
db_access=db_access,
|
|
553
|
+
admin_secret=admin_secret,
|
|
554
|
+
user_secret=user_secret,
|
|
551
555
|
),
|
|
552
556
|
admin=DatabaseConnectionParameters(
|
|
553
557
|
host=_decode_secret_value(admin_secret["data"]["db.host"]),
|
|
@@ -559,10 +563,10 @@ def _create_database_connection_parameter(
|
|
|
559
563
|
)
|
|
560
564
|
|
|
561
565
|
|
|
562
|
-
def
|
|
566
|
+
def _db_access_access_is_valid(db_access: DatabaseAccessV1) -> bool:
|
|
563
567
|
found_schema: set[str] = set()
|
|
564
568
|
|
|
565
|
-
for schema in
|
|
569
|
+
for schema in db_access.access or []:
|
|
566
570
|
if schema.target.dbschema in found_schema:
|
|
567
571
|
return False
|
|
568
572
|
found_schema.add(schema.target.dbschema)
|
|
@@ -577,21 +581,22 @@ class JobFailedError(Exception):
|
|
|
577
581
|
def _process_db_access(
|
|
578
582
|
dry_run: bool,
|
|
579
583
|
state: State,
|
|
584
|
+
state_key: str,
|
|
580
585
|
db_access: DatabaseAccessV1,
|
|
581
586
|
namespace: NamespaceV1,
|
|
582
587
|
admin_secret_name: str,
|
|
583
588
|
engine: str,
|
|
584
589
|
settings: dict[Any, Any],
|
|
585
590
|
vault_output_path: str,
|
|
586
|
-
vault_client:
|
|
591
|
+
vault_client: VaultClient,
|
|
587
592
|
) -> None:
|
|
588
|
-
if not
|
|
593
|
+
if not _db_access_access_is_valid(db_access):
|
|
589
594
|
raise ValueError("Duplicate schema in access list.")
|
|
590
595
|
|
|
591
596
|
current_db_access: DatabaseAccessV1 | None = None
|
|
592
|
-
if state.exists(
|
|
593
|
-
current_state = state.get(
|
|
594
|
-
if current_state == db_access.
|
|
597
|
+
if state.exists(state_key):
|
|
598
|
+
current_state = state.get(state_key)
|
|
599
|
+
if current_state == db_access.model_dump(by_alias=True):
|
|
595
600
|
return
|
|
596
601
|
current_db_access = DatabaseAccessV1(**current_state)
|
|
597
602
|
if current_db_access.database != db_access.database:
|
|
@@ -602,9 +607,9 @@ def _process_db_access(
|
|
|
602
607
|
cluster_name = namespace.cluster.name
|
|
603
608
|
namespace_name = namespace.name
|
|
604
609
|
|
|
605
|
-
resource_prefix = f"dbam-{
|
|
610
|
+
resource_prefix = f"dbam-{state_key.replace('/', '-')}"
|
|
606
611
|
with OC_Map(
|
|
607
|
-
clusters=[namespace.cluster.
|
|
612
|
+
clusters=[namespace.cluster.model_dump(by_alias=True)],
|
|
608
613
|
integration=QONTRACT_INTEGRATION,
|
|
609
614
|
settings=settings,
|
|
610
615
|
) as oc_map:
|
|
@@ -615,7 +620,7 @@ def _process_db_access(
|
|
|
615
620
|
namespace_name,
|
|
616
621
|
oc,
|
|
617
622
|
admin_secret_name,
|
|
618
|
-
resource_prefix,
|
|
623
|
+
user_secret_name=resource_prefix,
|
|
619
624
|
)
|
|
620
625
|
|
|
621
626
|
sql_query_settings = settings.get("sqlQuery")
|
|
@@ -644,7 +649,7 @@ def _process_db_access(
|
|
|
644
649
|
job = oc.get(
|
|
645
650
|
namespace_name,
|
|
646
651
|
"Job",
|
|
647
|
-
|
|
652
|
+
resource_prefix,
|
|
648
653
|
allow_not_found=True,
|
|
649
654
|
)
|
|
650
655
|
if not job:
|
|
@@ -654,8 +659,8 @@ def _process_db_access(
|
|
|
654
659
|
oc_map=oc_map,
|
|
655
660
|
cluster=cluster_name,
|
|
656
661
|
namespace=namespace_name,
|
|
657
|
-
resource_type=r.
|
|
658
|
-
resource=r
|
|
662
|
+
resource_type=r.kind,
|
|
663
|
+
resource=r,
|
|
659
664
|
wait_for_namespace=False,
|
|
660
665
|
)
|
|
661
666
|
return
|
|
@@ -667,34 +672,31 @@ def _process_db_access(
|
|
|
667
672
|
)
|
|
668
673
|
if job_status.is_complete():
|
|
669
674
|
if job_status.has_errors():
|
|
670
|
-
raise JobFailedError(
|
|
671
|
-
f"Job dbam-{db_access.name} failed, please check logs"
|
|
672
|
-
)
|
|
675
|
+
raise JobFailedError(f"Job {resource_prefix} failed, please check logs")
|
|
673
676
|
if not dry_run and not db_access.delete:
|
|
674
677
|
secret = {
|
|
675
|
-
"path": f"{vault_output_path}/{QONTRACT_INTEGRATION}/{
|
|
676
|
-
"data": connections["user"].
|
|
678
|
+
"path": f"{vault_output_path}/{QONTRACT_INTEGRATION}/{state_key}",
|
|
679
|
+
"data": connections["user"].model_dump(by_alias=True),
|
|
677
680
|
}
|
|
678
681
|
vault_client.write(secret, decode_base64=False)
|
|
679
682
|
logging.debug("job completed, cleaning up")
|
|
680
683
|
for r in managed_resources:
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
)
|
|
684
|
+
openshift_base.delete(
|
|
685
|
+
dry_run=dry_run,
|
|
686
|
+
oc_map=oc_map,
|
|
687
|
+
cluster=cluster_name,
|
|
688
|
+
namespace=namespace_name,
|
|
689
|
+
resource_type=r.kind,
|
|
690
|
+
name=r.name,
|
|
691
|
+
enable_deletion=True,
|
|
692
|
+
)
|
|
691
693
|
state.add(
|
|
692
|
-
|
|
693
|
-
value=db_access.
|
|
694
|
+
state_key,
|
|
695
|
+
value=db_access.model_dump(by_alias=True),
|
|
694
696
|
force=True,
|
|
695
697
|
)
|
|
696
698
|
else:
|
|
697
|
-
logging.info(f"Job
|
|
699
|
+
logging.info(f"Job {resource_prefix} appears to be still running")
|
|
698
700
|
|
|
699
701
|
|
|
700
702
|
class DBAMIntegrationParams(PydanticRunParams):
|
|
@@ -708,7 +710,7 @@ class DatabaseAccessManagerIntegration(QontractReconcileIntegration):
|
|
|
708
710
|
|
|
709
711
|
def run(self, dry_run: bool) -> None:
|
|
710
712
|
settings = queries.get_app_interface_settings()
|
|
711
|
-
vault_client =
|
|
713
|
+
vault_client = VaultClient.get_instance()
|
|
712
714
|
|
|
713
715
|
state = init_state(
|
|
714
716
|
integration=QONTRACT_INTEGRATION, secret_reader=self.secret_reader
|
|
@@ -736,9 +738,11 @@ class DatabaseAccessManagerIntegration(QontractReconcileIntegration):
|
|
|
736
738
|
|
|
737
739
|
for db_access in resource.database_access or []:
|
|
738
740
|
try:
|
|
741
|
+
state_key = f"{external_resource.provisioner.name}/{resource.identifier}/{db_access.name}"
|
|
739
742
|
_process_db_access(
|
|
740
743
|
dry_run,
|
|
741
744
|
state,
|
|
745
|
+
state_key,
|
|
742
746
|
db_access,
|
|
743
747
|
namespace,
|
|
744
748
|
admin_secret_name,
|
reconcile/deadmanssnitch.py
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import (
|
|
3
|
-
cast,
|
|
4
|
-
)
|
|
5
2
|
|
|
6
3
|
from pydantic import BaseModel
|
|
7
4
|
|
|
@@ -22,7 +19,6 @@ from reconcile.utils.runtime.integration import (
|
|
|
22
19
|
from reconcile.utils.semver_helper import make_semver
|
|
23
20
|
from reconcile.utils.vault import (
|
|
24
21
|
VaultClient,
|
|
25
|
-
_VaultClient,
|
|
26
22
|
)
|
|
27
23
|
|
|
28
24
|
QONTRACT_INTEGRATION = "deadmanssnitch"
|
|
@@ -51,7 +47,7 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
|
|
|
51
47
|
super().__init__(NoParams())
|
|
52
48
|
self.qontract_integration_version = make_semver(0, 1, 0)
|
|
53
49
|
self.settings = get_deadmanssnitch_settings()
|
|
54
|
-
self.vault_client =
|
|
50
|
+
self.vault_client = VaultClient.get_instance()
|
|
55
51
|
|
|
56
52
|
@staticmethod
|
|
57
53
|
def get_snitch_name(cluster: ClusterV1) -> str:
|
|
@@ -82,7 +82,7 @@ class DynatraceTokenProviderIntegration(QontractReconcileIntegration[NoParams]):
|
|
|
82
82
|
return {
|
|
83
83
|
"version": QONTRACT_INTEGRATION_VERSION,
|
|
84
84
|
"specs": {
|
|
85
|
-
spec.name: spec.
|
|
85
|
+
spec.name: spec.model_dump()
|
|
86
86
|
for spec in get_dynatrace_token_provider_token_specs()
|
|
87
87
|
},
|
|
88
88
|
}
|
|
@@ -150,7 +150,10 @@ class EndpointsDiscoveryIntegration(
|
|
|
150
150
|
return []
|
|
151
151
|
|
|
152
152
|
routes = defaultdict(list)
|
|
153
|
-
for item in oc.get_items(
|
|
153
|
+
for item in oc.get_items(
|
|
154
|
+
kind="Route.route.openshift.io",
|
|
155
|
+
namespace=namespace.name,
|
|
156
|
+
):
|
|
154
157
|
tls = bool(item["spec"].get("tls"))
|
|
155
158
|
host = item["spec"]["host"]
|
|
156
159
|
# group all routes with the same hostname/tls
|
|
@@ -89,7 +89,7 @@ class Renderer:
|
|
|
89
89
|
|
|
90
90
|
def render_description(self, hash: str) -> str:
|
|
91
91
|
"""Render the description for a merge request."""
|
|
92
|
-
return DESC.safe_substitute(EPDInfo(hash=hash).
|
|
92
|
+
return DESC.safe_substitute(EPDInfo(hash=hash).model_dump())
|
|
93
93
|
|
|
94
94
|
def render_title(self) -> str:
|
|
95
95
|
"""Render the title for a merge request."""
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
-
import json
|
|
3
2
|
import logging
|
|
4
3
|
from collections.abc import Sequence
|
|
5
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
6
5
|
|
|
7
6
|
from gitlab.exceptions import GitlabGetError
|
|
8
7
|
from pydantic import BaseModel
|
|
@@ -16,6 +15,7 @@ from reconcile.endpoints_discovery.merge_request import (
|
|
|
16
15
|
Renderer,
|
|
17
16
|
)
|
|
18
17
|
from reconcile.utils.gitlab_api import GitLabApi
|
|
18
|
+
from reconcile.utils.json import json_dumps
|
|
19
19
|
from reconcile.utils.merge_request_manager.merge_request_manager import (
|
|
20
20
|
MergeRequestManagerBase,
|
|
21
21
|
)
|
|
@@ -64,22 +64,20 @@ class Endpoint(BaseModel):
|
|
|
64
64
|
|
|
65
65
|
@property
|
|
66
66
|
def hash(self) -> str:
|
|
67
|
-
return hashlib.sha256(
|
|
68
|
-
json.dumps(self.dict(), sort_keys=True).encode()
|
|
69
|
-
).hexdigest()
|
|
67
|
+
return hashlib.sha256(json_dumps(self.model_dump()).encode()).hexdigest()
|
|
70
68
|
|
|
71
69
|
|
|
72
|
-
EndpointsToAdd
|
|
73
|
-
EndpointsToChange
|
|
74
|
-
EndpointsToDelete
|
|
70
|
+
EndpointsToAdd = list[Endpoint]
|
|
71
|
+
EndpointsToChange = list[Endpoint]
|
|
72
|
+
EndpointsToDelete = list[Endpoint]
|
|
75
73
|
|
|
76
74
|
|
|
77
75
|
class App(BaseModel):
|
|
78
76
|
name: str
|
|
79
77
|
path: str
|
|
80
|
-
endpoints_to_add: EndpointsToAdd =
|
|
81
|
-
endpoints_to_change: EndpointsToChange =
|
|
82
|
-
endpoints_to_delete: EndpointsToDelete =
|
|
78
|
+
endpoints_to_add: EndpointsToAdd = []
|
|
79
|
+
endpoints_to_change: EndpointsToChange = []
|
|
80
|
+
endpoints_to_delete: EndpointsToDelete = []
|
|
83
81
|
|
|
84
82
|
@property
|
|
85
83
|
def hash(self) -> str:
|
|
@@ -2,7 +2,7 @@ from abc import (
|
|
|
2
2
|
ABC,
|
|
3
3
|
abstractmethod,
|
|
4
4
|
)
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import TypeVar
|
|
6
6
|
|
|
7
7
|
from reconcile.external_resources.aws import (
|
|
8
8
|
AWSDefaultResourceFactory,
|
|
@@ -32,16 +32,8 @@ from reconcile.utils.secret_reader import SecretReaderBase
|
|
|
32
32
|
|
|
33
33
|
T = TypeVar("T")
|
|
34
34
|
|
|
35
|
-
AWS_DEFAULT_TAGS = [
|
|
36
|
-
{
|
|
37
|
-
"tags": {
|
|
38
|
-
"app": "app-sre-infra",
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
]
|
|
42
35
|
|
|
43
|
-
|
|
44
|
-
class ObjectFactory(Generic[T]):
|
|
36
|
+
class ObjectFactory[T]:
|
|
45
37
|
def __init__(
|
|
46
38
|
self, factories: dict[str, T], default_factory: T | None = None
|
|
47
39
|
) -> None:
|
|
@@ -123,12 +115,14 @@ class AWSExternalResourceFactory(ExternalResourceFactory):
|
|
|
123
115
|
secret_reader: SecretReaderBase,
|
|
124
116
|
provision_factories: ObjectFactory[ModuleProvisionDataFactory],
|
|
125
117
|
resource_factories: ObjectFactory[AWSResourceFactory],
|
|
118
|
+
default_tags: dict[str, str],
|
|
126
119
|
):
|
|
127
120
|
self.provision_factories = provision_factories
|
|
128
121
|
self.resource_factories = resource_factories
|
|
129
122
|
self.module_inventory = module_inventory
|
|
130
123
|
self.er_inventory = er_inventory
|
|
131
124
|
self.secret_reader = secret_reader
|
|
125
|
+
self.default_tags = default_tags
|
|
132
126
|
|
|
133
127
|
def create_external_resource(
|
|
134
128
|
self,
|
|
@@ -137,8 +131,7 @@ class AWSExternalResourceFactory(ExternalResourceFactory):
|
|
|
137
131
|
) -> ExternalResource:
|
|
138
132
|
f = self.resource_factories.get_factory(spec.provider)
|
|
139
133
|
data = f.resolve(spec, module_conf)
|
|
140
|
-
data["tags"] = spec.tags(integration=QONTRACT_INTEGRATION)
|
|
141
|
-
data["default_tags"] = AWS_DEFAULT_TAGS
|
|
134
|
+
data["tags"] = self.default_tags | spec.tags(integration=QONTRACT_INTEGRATION)
|
|
142
135
|
|
|
143
136
|
region = data.get("region")
|
|
144
137
|
if region:
|
|
@@ -45,7 +45,7 @@ from reconcile.utils.secret_reader import SecretReaderBase, create_secret_reader
|
|
|
45
45
|
def fetch_current_state(
|
|
46
46
|
ri: ResourceInventory, oc: OCCli, cluster: str, namespace: str
|
|
47
47
|
) -> None:
|
|
48
|
-
for item in oc.get_items("Job", namespace=namespace):
|
|
48
|
+
for item in oc.get_items("Job.batch", namespace=namespace):
|
|
49
49
|
r = OpenshiftResource(item, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION)
|
|
50
50
|
ri.add_current(cluster, namespace, "Job", r.name, r)
|
|
51
51
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from collections import Counter
|
|
3
3
|
from collections.abc import Iterable
|
|
4
|
-
from
|
|
4
|
+
from typing import cast
|
|
5
5
|
|
|
6
6
|
from sretoolbox.utils import threaded
|
|
7
7
|
|
|
@@ -41,6 +41,7 @@ from reconcile.external_resources.state import (
|
|
|
41
41
|
from reconcile.gql_definitions.external_resources.external_resources_settings import (
|
|
42
42
|
ExternalResourcesSettingsV1,
|
|
43
43
|
)
|
|
44
|
+
from reconcile.utils.datetime_util import utc_now
|
|
44
45
|
from reconcile.utils.external_resource_spec import (
|
|
45
46
|
ExternalResourceSpec,
|
|
46
47
|
)
|
|
@@ -67,6 +68,7 @@ def setup_factories(
|
|
|
67
68
|
resource_factories=setup_aws_resource_factories(
|
|
68
69
|
er_inventory, secret_reader
|
|
69
70
|
),
|
|
71
|
+
default_tags=cast("dict[str, str]", settings.default_tags),
|
|
70
72
|
)
|
|
71
73
|
}
|
|
72
74
|
)
|
|
@@ -141,7 +143,7 @@ class ExternalResourcesManager:
|
|
|
141
143
|
def _resource_drift_detection_ttl_expired(
|
|
142
144
|
self, reconciliation: Reconciliation, state: ExternalResourceState
|
|
143
145
|
) -> bool:
|
|
144
|
-
return (
|
|
146
|
+
return (utc_now() - state.ts).total_seconds() > (
|
|
145
147
|
reconciliation.module_configuration.reconcile_drift_interval_minutes * 60
|
|
146
148
|
)
|
|
147
149
|
|
|
@@ -242,7 +244,7 @@ class ExternalResourcesManager:
|
|
|
242
244
|
reconciliation = Reconciliation(
|
|
243
245
|
key=key,
|
|
244
246
|
resource_hash=resource.hash(),
|
|
245
|
-
input=resource.
|
|
247
|
+
input=resource.export(),
|
|
246
248
|
action=Action.APPLY,
|
|
247
249
|
module_configuration=module_conf,
|
|
248
250
|
linked_resources=self._find_linked_resources(spec),
|
|
@@ -355,7 +357,7 @@ class ExternalResourcesManager:
|
|
|
355
357
|
def _set_resource_reconciliation_in_progress(
|
|
356
358
|
self, r: Reconciliation, state: ExternalResourceState
|
|
357
359
|
) -> None:
|
|
358
|
-
state.ts =
|
|
360
|
+
state.ts = utc_now()
|
|
359
361
|
if r.action == Action.APPLY:
|
|
360
362
|
state.resource_status = ResourceStatus.IN_PROGRESS
|
|
361
363
|
elif r.action == Action.DESTROY:
|
|
@@ -448,7 +450,8 @@ class ExternalResourcesManager:
|
|
|
448
450
|
r
|
|
449
451
|
for r in desired_r.union(deleted_r)
|
|
450
452
|
if self._reconciliation_needs_dry_run_run(
|
|
451
|
-
r,
|
|
453
|
+
r,
|
|
454
|
+
self.state_mgr.get_external_resource_state(key=r.key),
|
|
452
455
|
)
|
|
453
456
|
}
|
|
454
457
|
|
|
@@ -10,7 +10,6 @@ SECRET_ANN_PROVISIONER = SECRET_ANN_PREFIX + "/provisioner_name"
|
|
|
10
10
|
SECRET_ANN_PROVIDER = SECRET_ANN_PREFIX + "/provider"
|
|
11
11
|
SECRET_ANN_IDENTIFIER = SECRET_ANN_PREFIX + "/identifier"
|
|
12
12
|
SECRET_UPDATED_AT = SECRET_ANN_PREFIX + "/updated_at"
|
|
13
|
-
SECRET_UPDATED_AT_TIMEFORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
|
14
13
|
|
|
15
14
|
FLAG_RESOURCE_MANAGED_BY_ERV2 = "managed_by_erv2"
|
|
16
15
|
FLAG_DELETE_RESOURCE = "delete"
|
|
@@ -13,7 +13,7 @@ from reconcile.utils.metrics import (
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ExternalResourcesBaseMetric(BaseModel):
|
|
16
|
-
integration = normalize_integration_name(QONTRACT_INTEGRATION)
|
|
16
|
+
integration: str = normalize_integration_name(QONTRACT_INTEGRATION)
|
|
17
17
|
app: str
|
|
18
18
|
environment: str
|
|
19
19
|
provision_provider: str
|