qontract-reconcile 0.10.0__py3-none-any.whl → 0.10.1.dev1203__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.1.dev1203.dist-info/METADATA +500 -0
- qontract_reconcile-0.10.1.dev1203.dist-info/RECORD +771 -0
- {qontract_reconcile-0.10.0.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
- {qontract_reconcile-0.10.0.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/entry_points.txt +4 -2
- reconcile/acs_notifiers.py +126 -0
- reconcile/acs_policies.py +243 -0
- reconcile/acs_rbac.py +596 -0
- reconcile/aus/advanced_upgrade_service.py +621 -8
- reconcile/aus/aus_label_source.py +115 -0
- reconcile/aus/base.py +1053 -353
- reconcile/{utils → aus}/cluster_version_data.py +27 -12
- reconcile/aus/healthchecks.py +77 -0
- reconcile/aus/metrics.py +158 -0
- reconcile/aus/models.py +245 -5
- reconcile/aus/node_pool_spec.py +35 -0
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +225 -110
- reconcile/aus/ocm_upgrade_scheduler.py +76 -71
- reconcile/aus/ocm_upgrade_scheduler_org.py +81 -23
- reconcile/aus/version_gate_approver.py +204 -0
- reconcile/aus/version_gates/__init__.py +12 -0
- reconcile/aus/version_gates/handler.py +33 -0
- reconcile/aus/version_gates/ingress_gate_handler.py +32 -0
- reconcile/aus/version_gates/ocp_gate_handler.py +26 -0
- reconcile/aus/version_gates/sts_version_gate_handler.py +100 -0
- reconcile/aws_account_manager/README.md +5 -0
- reconcile/aws_account_manager/integration.py +373 -0
- reconcile/aws_account_manager/merge_request_manager.py +114 -0
- reconcile/aws_account_manager/metrics.py +39 -0
- reconcile/aws_account_manager/reconciler.py +403 -0
- reconcile/aws_account_manager/utils.py +41 -0
- reconcile/aws_ami_cleanup/integration.py +273 -0
- reconcile/aws_ami_share.py +18 -14
- reconcile/aws_cloudwatch_log_retention/integration.py +253 -0
- reconcile/aws_iam_keys.py +1 -1
- reconcile/aws_iam_password_reset.py +56 -20
- reconcile/aws_saml_idp/integration.py +204 -0
- reconcile/aws_saml_roles/integration.py +322 -0
- reconcile/aws_support_cases_sos.py +2 -2
- reconcile/aws_version_sync/integration.py +430 -0
- reconcile/aws_version_sync/merge_request_manager/merge_request.py +156 -0
- reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py +160 -0
- reconcile/aws_version_sync/utils.py +64 -0
- reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
- reconcile/change_owners/README.md +34 -0
- reconcile/change_owners/approver.py +7 -9
- reconcile/change_owners/bundle.py +134 -9
- reconcile/change_owners/change_log_tracking.py +236 -0
- reconcile/change_owners/change_owners.py +204 -194
- reconcile/change_owners/change_types.py +183 -265
- reconcile/change_owners/changes.py +488 -0
- reconcile/change_owners/decision.py +120 -41
- reconcile/change_owners/diff.py +63 -92
- reconcile/change_owners/implicit_ownership.py +19 -16
- reconcile/change_owners/self_service_roles.py +158 -35
- reconcile/change_owners/tester.py +20 -18
- reconcile/checkpoint.py +4 -6
- reconcile/cli.py +1523 -242
- reconcile/closedbox_endpoint_monitoring_base.py +10 -17
- reconcile/cluster_auth_rhidp/integration.py +257 -0
- reconcile/cluster_deployment_mapper.py +2 -5
- reconcile/cna/assets/asset.py +4 -7
- reconcile/cna/assets/null.py +2 -5
- reconcile/cna/integration.py +2 -3
- reconcile/cna/state.py +6 -9
- reconcile/dashdotdb_base.py +31 -10
- reconcile/dashdotdb_cso.py +3 -6
- reconcile/dashdotdb_dora.py +530 -0
- reconcile/dashdotdb_dvo.py +10 -13
- reconcile/dashdotdb_slo.py +75 -19
- reconcile/database_access_manager.py +753 -0
- reconcile/deadmanssnitch.py +207 -0
- reconcile/dynatrace_token_provider/dependencies.py +69 -0
- reconcile/dynatrace_token_provider/integration.py +656 -0
- reconcile/dynatrace_token_provider/metrics.py +62 -0
- reconcile/dynatrace_token_provider/model.py +14 -0
- reconcile/dynatrace_token_provider/ocm.py +140 -0
- reconcile/dynatrace_token_provider/validate.py +48 -0
- reconcile/endpoints_discovery/integration.py +348 -0
- reconcile/endpoints_discovery/merge_request.py +96 -0
- reconcile/endpoints_discovery/merge_request_manager.py +178 -0
- reconcile/external_resources/aws.py +204 -0
- reconcile/external_resources/factories.py +163 -0
- reconcile/external_resources/integration.py +194 -0
- reconcile/external_resources/integration_secrets_sync.py +47 -0
- reconcile/external_resources/manager.py +405 -0
- reconcile/external_resources/meta.py +17 -0
- reconcile/external_resources/metrics.py +95 -0
- reconcile/external_resources/model.py +350 -0
- reconcile/external_resources/reconciler.py +265 -0
- reconcile/external_resources/secrets_sync.py +465 -0
- reconcile/external_resources/state.py +258 -0
- reconcile/gabi_authorized_users.py +19 -11
- reconcile/gcr_mirror.py +43 -34
- reconcile/github_org.py +4 -6
- reconcile/github_owners.py +1 -1
- reconcile/github_repo_invites.py +2 -5
- reconcile/gitlab_fork_compliance.py +14 -13
- reconcile/gitlab_housekeeping.py +185 -91
- reconcile/gitlab_labeler.py +15 -14
- reconcile/gitlab_members.py +126 -120
- reconcile/gitlab_owners.py +53 -66
- reconcile/gitlab_permissions.py +167 -6
- reconcile/glitchtip/README.md +150 -0
- reconcile/glitchtip/integration.py +99 -51
- reconcile/glitchtip/reconciler.py +99 -70
- reconcile/glitchtip_project_alerts/__init__.py +0 -0
- reconcile/glitchtip_project_alerts/integration.py +333 -0
- reconcile/glitchtip_project_dsn/integration.py +43 -43
- reconcile/gql_definitions/acs/__init__.py +0 -0
- reconcile/gql_definitions/acs/acs_instances.py +83 -0
- reconcile/gql_definitions/acs/acs_policies.py +239 -0
- reconcile/gql_definitions/acs/acs_rbac.py +111 -0
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +46 -8
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +38 -8
- reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py +0 -0
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +61 -0
- reconcile/gql_definitions/aws_account_manager/__init__.py +0 -0
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +177 -0
- reconcile/gql_definitions/aws_ami_cleanup/__init__.py +0 -0
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +161 -0
- reconcile/gql_definitions/aws_saml_idp/__init__.py +0 -0
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +117 -0
- reconcile/gql_definitions/aws_saml_roles/__init__.py +0 -0
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +117 -0
- reconcile/gql_definitions/aws_saml_roles/roles.py +97 -0
- reconcile/gql_definitions/aws_version_sync/__init__.py +0 -0
- reconcile/gql_definitions/aws_version_sync/clusters.py +83 -0
- reconcile/gql_definitions/aws_version_sync/namespaces.py +143 -0
- reconcile/gql_definitions/change_owners/queries/change_types.py +16 -29
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +45 -11
- reconcile/gql_definitions/cluster_auth_rhidp/__init__.py +0 -0
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +128 -0
- reconcile/gql_definitions/cna/queries/cna_provisioners.py +6 -8
- reconcile/gql_definitions/cna/queries/cna_resources.py +3 -5
- reconcile/gql_definitions/common/alerting_services_settings.py +2 -2
- reconcile/gql_definitions/common/app_code_component_repos.py +9 -5
- reconcile/gql_definitions/{glitchtip/glitchtip_settings.py → common/app_interface_custom_messages.py} +14 -16
- reconcile/gql_definitions/common/app_interface_dms_settings.py +86 -0
- reconcile/gql_definitions/common/app_interface_repo_settings.py +2 -2
- reconcile/gql_definitions/common/app_interface_state_settings.py +3 -5
- reconcile/gql_definitions/common/app_interface_vault_settings.py +3 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +120 -0
- reconcile/gql_definitions/common/apps.py +72 -0
- reconcile/gql_definitions/common/aws_vpc_requests.py +109 -0
- reconcile/gql_definitions/common/aws_vpcs.py +84 -0
- reconcile/gql_definitions/common/clusters.py +120 -254
- reconcile/gql_definitions/common/clusters_minimal.py +11 -35
- reconcile/gql_definitions/common/clusters_with_dms.py +72 -0
- reconcile/gql_definitions/common/clusters_with_peering.py +70 -98
- reconcile/gql_definitions/common/github_orgs.py +2 -2
- reconcile/gql_definitions/common/jira_settings.py +68 -0
- reconcile/gql_definitions/common/jiralert_settings.py +68 -0
- reconcile/gql_definitions/common/namespaces.py +74 -32
- reconcile/gql_definitions/common/namespaces_minimal.py +4 -10
- reconcile/gql_definitions/common/ocm_env_telemeter.py +95 -0
- reconcile/gql_definitions/common/ocm_environments.py +4 -2
- reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -11
- reconcile/gql_definitions/common/pipeline_providers.py +45 -90
- reconcile/gql_definitions/common/quay_instances.py +64 -0
- reconcile/gql_definitions/common/quay_orgs.py +68 -0
- reconcile/gql_definitions/common/reserved_networks.py +94 -0
- reconcile/gql_definitions/common/saas_files.py +133 -95
- reconcile/gql_definitions/common/saas_target_namespaces.py +41 -26
- reconcile/gql_definitions/common/saasherder_settings.py +2 -2
- reconcile/gql_definitions/common/slack_workspaces.py +62 -0
- reconcile/gql_definitions/common/smtp_client_settings.py +2 -2
- reconcile/gql_definitions/common/state_aws_account.py +77 -0
- reconcile/gql_definitions/common/users.py +3 -2
- reconcile/gql_definitions/cost_report/__init__.py +0 -0
- reconcile/gql_definitions/cost_report/app_names.py +68 -0
- reconcile/gql_definitions/cost_report/cost_namespaces.py +86 -0
- reconcile/gql_definitions/cost_report/settings.py +77 -0
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +42 -12
- reconcile/gql_definitions/dynatrace_token_provider/__init__.py +0 -0
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +79 -0
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +84 -0
- reconcile/gql_definitions/endpoints_discovery/__init__.py +0 -0
- reconcile/gql_definitions/endpoints_discovery/namespaces.py +127 -0
- reconcile/gql_definitions/external_resources/__init__.py +0 -0
- reconcile/gql_definitions/external_resources/aws_accounts.py +73 -0
- reconcile/gql_definitions/external_resources/external_resources_modules.py +78 -0
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +1111 -0
- reconcile/gql_definitions/external_resources/external_resources_settings.py +98 -0
- reconcile/gql_definitions/fragments/aus_organization.py +34 -39
- reconcile/gql_definitions/fragments/aws_account_common.py +62 -0
- reconcile/gql_definitions/fragments/aws_account_managed.py +57 -0
- reconcile/gql_definitions/fragments/aws_account_sso.py +35 -0
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +2 -2
- reconcile/gql_definitions/fragments/aws_vpc.py +47 -0
- reconcile/gql_definitions/fragments/aws_vpc_request.py +65 -0
- reconcile/gql_definitions/fragments/aws_vpc_request_subnet.py +29 -0
- reconcile/gql_definitions/fragments/deplopy_resources.py +7 -7
- reconcile/gql_definitions/fragments/disable.py +28 -0
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +2 -2
- reconcile/gql_definitions/fragments/membership_source.py +47 -0
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +29 -0
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +4 -9
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +30 -0
- reconcile/gql_definitions/fragments/prometheus_instance.py +48 -0
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +29 -0
- reconcile/gql_definitions/fragments/{resource_requirements.py → resource_requests_requirements.py} +3 -3
- reconcile/gql_definitions/fragments/resource_values.py +2 -2
- reconcile/gql_definitions/fragments/saas_target_namespace.py +55 -12
- reconcile/gql_definitions/fragments/serviceaccount_token.py +38 -0
- reconcile/gql_definitions/fragments/terraform_state.py +36 -0
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -3
- reconcile/gql_definitions/fragments/user.py +3 -2
- reconcile/gql_definitions/fragments/vault_secret.py +2 -2
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +6 -2
- reconcile/gql_definitions/gitlab_members/permissions.py +3 -5
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +16 -2
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +22 -23
- reconcile/gql_definitions/glitchtip_project_alerts/__init__.py +0 -0
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +173 -0
- reconcile/gql_definitions/integrations/integrations.py +62 -45
- reconcile/gql_definitions/introspection.json +51176 -0
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +13 -5
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +79 -0
- reconcile/gql_definitions/jira/__init__.py +0 -0
- reconcile/gql_definitions/jira/jira_servers.py +80 -0
- reconcile/gql_definitions/jira_permissions_validator/__init__.py +0 -0
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +131 -0
- reconcile/gql_definitions/jumphosts/jumphosts.py +3 -5
- reconcile/gql_definitions/ldap_groups/__init__.py +0 -0
- reconcile/gql_definitions/ldap_groups/roles.py +111 -0
- reconcile/gql_definitions/ldap_groups/settings.py +79 -0
- reconcile/gql_definitions/maintenance/__init__.py +0 -0
- reconcile/gql_definitions/maintenance/maintenances.py +101 -0
- reconcile/gql_definitions/membershipsources/__init__.py +0 -0
- reconcile/gql_definitions/membershipsources/roles.py +112 -0
- reconcile/gql_definitions/ocm_labels/__init__.py +0 -0
- reconcile/gql_definitions/ocm_labels/clusters.py +112 -0
- reconcile/gql_definitions/ocm_labels/organizations.py +78 -0
- reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
- reconcile/gql_definitions/openshift_cluster_bots/__init__.py +0 -0
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +126 -0
- reconcile/gql_definitions/openshift_groups/managed_groups.py +2 -2
- reconcile/gql_definitions/openshift_groups/managed_roles.py +3 -2
- reconcile/gql_definitions/openshift_serviceaccount_tokens/__init__.py +0 -0
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +132 -0
- reconcile/gql_definitions/quay_membership/quay_membership.py +3 -5
- reconcile/gql_definitions/rhidp/__init__.py +0 -0
- reconcile/gql_definitions/rhidp/organizations.py +96 -0
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +2 -2
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +9 -31
- reconcile/gql_definitions/sharding/aws_accounts.py +2 -2
- reconcile/gql_definitions/sharding/ocm_organization.py +63 -0
- reconcile/gql_definitions/skupper_network/site_controller_template.py +2 -2
- reconcile/gql_definitions/skupper_network/skupper_networks.py +12 -38
- reconcile/gql_definitions/slack_usergroups/clusters.py +2 -2
- reconcile/gql_definitions/slack_usergroups/permissions.py +8 -15
- reconcile/gql_definitions/slack_usergroups/users.py +3 -2
- reconcile/gql_definitions/slo_documents/__init__.py +0 -0
- reconcile/gql_definitions/slo_documents/slo_documents.py +142 -0
- reconcile/gql_definitions/status_board/__init__.py +0 -0
- reconcile/gql_definitions/status_board/status_board.py +163 -0
- reconcile/gql_definitions/statuspage/statuspages.py +56 -7
- reconcile/gql_definitions/templating/__init__.py +0 -0
- reconcile/gql_definitions/templating/template_collection.py +130 -0
- reconcile/gql_definitions/templating/templates.py +108 -0
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +4 -8
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +8 -8
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +6 -8
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +45 -56
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +4 -8
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +4 -8
- reconcile/gql_definitions/terraform_init/__init__.py +0 -0
- reconcile/gql_definitions/terraform_init/aws_accounts.py +93 -0
- reconcile/gql_definitions/terraform_repo/__init__.py +0 -0
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +141 -0
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +158 -0
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +153 -162
- reconcile/gql_definitions/terraform_tgw_attachments/__init__.py +0 -0
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +119 -0
- reconcile/gql_definitions/unleash_feature_toggles/__init__.py +0 -0
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +113 -0
- reconcile/gql_definitions/vault_instances/vault_instances.py +17 -50
- reconcile/gql_definitions/vault_policies/vault_policies.py +2 -2
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +49 -12
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +7 -2
- reconcile/integrations_manager.py +25 -13
- reconcile/jenkins/types.py +5 -1
- reconcile/jenkins_base.py +36 -0
- reconcile/jenkins_job_builder.py +10 -48
- reconcile/jenkins_job_builds_cleaner.py +40 -25
- reconcile/jenkins_job_cleaner.py +1 -3
- reconcile/jenkins_roles.py +22 -26
- reconcile/jenkins_webhooks.py +9 -6
- reconcile/jenkins_worker_fleets.py +11 -6
- reconcile/jira_permissions_validator.py +340 -0
- reconcile/jira_watcher.py +3 -5
- reconcile/ldap_groups/__init__.py +0 -0
- reconcile/ldap_groups/integration.py +279 -0
- reconcile/ldap_users.py +3 -0
- reconcile/ocm/types.py +39 -59
- reconcile/ocm_additional_routers.py +0 -1
- reconcile/ocm_addons_upgrade_tests_trigger.py +10 -15
- reconcile/ocm_aws_infrastructure_access.py +30 -32
- reconcile/ocm_clusters.py +217 -130
- reconcile/ocm_external_configuration_labels.py +15 -0
- reconcile/ocm_github_idp.py +1 -1
- reconcile/ocm_groups.py +25 -5
- reconcile/ocm_internal_notifications/__init__.py +0 -0
- reconcile/ocm_internal_notifications/integration.py +119 -0
- reconcile/ocm_labels/__init__.py +0 -0
- reconcile/ocm_labels/integration.py +409 -0
- reconcile/ocm_machine_pools.py +517 -108
- reconcile/ocm_upgrade_scheduler_org_updater.py +15 -11
- reconcile/openshift_base.py +609 -207
- reconcile/openshift_cluster_bots.py +344 -0
- reconcile/openshift_clusterrolebindings.py +15 -15
- reconcile/openshift_groups.py +42 -45
- reconcile/openshift_limitranges.py +1 -0
- reconcile/openshift_namespace_labels.py +22 -28
- reconcile/openshift_namespaces.py +22 -22
- reconcile/openshift_network_policies.py +4 -8
- reconcile/openshift_prometheus_rules.py +43 -0
- reconcile/openshift_resourcequotas.py +2 -16
- reconcile/openshift_resources.py +12 -10
- reconcile/openshift_resources_base.py +304 -328
- reconcile/openshift_rolebindings.py +18 -20
- reconcile/openshift_saas_deploy.py +105 -21
- reconcile/openshift_saas_deploy_change_tester.py +30 -35
- reconcile/openshift_saas_deploy_trigger_base.py +39 -36
- reconcile/openshift_saas_deploy_trigger_cleaner.py +41 -27
- reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
- reconcile/openshift_saas_deploy_trigger_images.py +1 -2
- reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
- reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
- reconcile/openshift_serviceaccount_tokens.py +138 -74
- reconcile/openshift_tekton_resources.py +89 -24
- reconcile/openshift_upgrade_watcher.py +110 -62
- reconcile/openshift_users.py +16 -15
- reconcile/openshift_vault_secrets.py +11 -6
- reconcile/oum/__init__.py +0 -0
- reconcile/oum/base.py +387 -0
- reconcile/oum/labelset.py +55 -0
- reconcile/oum/metrics.py +71 -0
- reconcile/oum/models.py +69 -0
- reconcile/oum/providers.py +59 -0
- reconcile/oum/standalone.py +196 -0
- reconcile/prometheus_rules_tester/integration.py +31 -23
- reconcile/quay_base.py +4 -1
- reconcile/quay_membership.py +1 -2
- reconcile/quay_mirror.py +111 -61
- reconcile/quay_mirror_org.py +34 -21
- reconcile/quay_permissions.py +7 -3
- reconcile/quay_repos.py +24 -32
- reconcile/queries.py +263 -198
- reconcile/query_validator.py +3 -5
- reconcile/resource_scraper.py +3 -4
- reconcile/{template_tester.py → resource_template_tester.py} +3 -3
- reconcile/rhidp/__init__.py +0 -0
- reconcile/rhidp/common.py +214 -0
- reconcile/rhidp/metrics.py +20 -0
- reconcile/rhidp/ocm_oidc_idp/__init__.py +0 -0
- reconcile/rhidp/ocm_oidc_idp/base.py +221 -0
- reconcile/rhidp/ocm_oidc_idp/integration.py +56 -0
- reconcile/rhidp/ocm_oidc_idp/metrics.py +22 -0
- reconcile/rhidp/sso_client/__init__.py +0 -0
- reconcile/rhidp/sso_client/base.py +266 -0
- reconcile/rhidp/sso_client/integration.py +60 -0
- reconcile/rhidp/sso_client/metrics.py +39 -0
- reconcile/run_integration.py +293 -0
- reconcile/saas_auto_promotions_manager/integration.py +69 -24
- reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +208 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py +28 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py +3 -4
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +172 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/metrics.py +42 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +226 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/open_merge_requests.py +23 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +108 -32
- reconcile/saas_auto_promotions_manager/meta.py +4 -0
- reconcile/saas_auto_promotions_manager/publisher.py +32 -4
- reconcile/saas_auto_promotions_manager/s3_exporter.py +77 -0
- reconcile/saas_auto_promotions_manager/subscriber.py +110 -23
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +48 -41
- reconcile/saas_file_validator.py +16 -6
- reconcile/sendgrid_teammates.py +27 -12
- reconcile/service_dependencies.py +0 -3
- reconcile/signalfx_endpoint_monitoring.py +2 -5
- reconcile/skupper_network/integration.py +10 -11
- reconcile/skupper_network/models.py +3 -5
- reconcile/skupper_network/reconciler.py +28 -35
- reconcile/skupper_network/site_controller.py +8 -8
- reconcile/slack_base.py +4 -7
- reconcile/slack_usergroups.py +249 -171
- reconcile/sql_query.py +324 -171
- reconcile/status.py +0 -1
- reconcile/status_board.py +275 -0
- reconcile/statuspage/__init__.py +0 -5
- reconcile/statuspage/atlassian.py +219 -80
- reconcile/statuspage/integration.py +9 -97
- reconcile/statuspage/integrations/__init__.py +0 -0
- reconcile/statuspage/integrations/components.py +77 -0
- reconcile/statuspage/integrations/maintenances.py +111 -0
- reconcile/statuspage/page.py +107 -72
- reconcile/statuspage/state.py +6 -11
- reconcile/statuspage/status.py +8 -12
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +60 -0
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +61 -0
- reconcile/templating/__init__.py +0 -0
- reconcile/templating/lib/__init__.py +0 -0
- reconcile/templating/lib/merge_request_manager.py +180 -0
- reconcile/templating/lib/model.py +20 -0
- reconcile/templating/lib/rendering.py +191 -0
- reconcile/templating/renderer.py +410 -0
- reconcile/templating/validator.py +153 -0
- reconcile/terraform_aws_route53.py +13 -10
- reconcile/terraform_cloudflare_dns.py +92 -122
- reconcile/terraform_cloudflare_resources.py +15 -13
- reconcile/terraform_cloudflare_users.py +27 -27
- reconcile/terraform_init/__init__.py +0 -0
- reconcile/terraform_init/integration.py +165 -0
- reconcile/terraform_init/merge_request.py +57 -0
- reconcile/terraform_init/merge_request_manager.py +102 -0
- reconcile/terraform_repo.py +403 -0
- reconcile/terraform_resources.py +266 -168
- reconcile/terraform_tgw_attachments.py +417 -167
- reconcile/terraform_users.py +40 -17
- reconcile/terraform_vpc_peerings.py +310 -142
- reconcile/terraform_vpc_resources/__init__.py +0 -0
- reconcile/terraform_vpc_resources/integration.py +220 -0
- reconcile/terraform_vpc_resources/merge_request.py +57 -0
- reconcile/terraform_vpc_resources/merge_request_manager.py +107 -0
- reconcile/typed_queries/alerting_services_settings.py +1 -2
- reconcile/typed_queries/app_interface_custom_messages.py +24 -0
- reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +17 -0
- reconcile/typed_queries/app_interface_metrics_exporter/__init__.py +0 -0
- reconcile/typed_queries/app_interface_metrics_exporter/onboarding_status.py +13 -0
- reconcile/typed_queries/app_interface_repo_url.py +1 -2
- reconcile/typed_queries/app_interface_state_settings.py +1 -3
- reconcile/typed_queries/app_interface_vault_settings.py +1 -2
- reconcile/typed_queries/app_quay_repos_escalation_policies.py +14 -0
- reconcile/typed_queries/apps.py +11 -0
- reconcile/typed_queries/aws_vpc_requests.py +9 -0
- reconcile/typed_queries/aws_vpcs.py +12 -0
- reconcile/typed_queries/cloudflare.py +10 -0
- reconcile/typed_queries/clusters.py +7 -5
- reconcile/typed_queries/clusters_minimal.py +6 -5
- reconcile/typed_queries/clusters_with_dms.py +16 -0
- reconcile/typed_queries/cost_report/__init__.py +0 -0
- reconcile/typed_queries/cost_report/app_names.py +22 -0
- reconcile/typed_queries/cost_report/cost_namespaces.py +43 -0
- reconcile/typed_queries/cost_report/settings.py +15 -0
- reconcile/typed_queries/dynatrace.py +10 -0
- reconcile/typed_queries/dynatrace_environments.py +14 -0
- reconcile/typed_queries/dynatrace_token_provider_token_specs.py +14 -0
- reconcile/typed_queries/external_resources.py +46 -0
- reconcile/typed_queries/get_state_aws_account.py +20 -0
- reconcile/typed_queries/glitchtip.py +10 -0
- reconcile/typed_queries/jenkins.py +25 -0
- reconcile/typed_queries/jira.py +7 -0
- reconcile/typed_queries/jira_settings.py +16 -0
- reconcile/typed_queries/jiralert_settings.py +22 -0
- reconcile/typed_queries/ocm.py +8 -0
- reconcile/typed_queries/pagerduty_instances.py +2 -7
- reconcile/typed_queries/quay.py +23 -0
- reconcile/typed_queries/repos.py +20 -8
- reconcile/typed_queries/reserved_networks.py +12 -0
- reconcile/typed_queries/saas_files.py +221 -167
- reconcile/typed_queries/slack.py +7 -0
- reconcile/typed_queries/slo_documents.py +12 -0
- reconcile/typed_queries/status_board.py +58 -0
- reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
- reconcile/typed_queries/terraform_namespaces.py +1 -2
- reconcile/typed_queries/terraform_tgw_attachments/__init__.py +0 -0
- reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +16 -0
- reconcile/typed_queries/unleash.py +10 -0
- reconcile/typed_queries/users.py +11 -0
- reconcile/typed_queries/vault.py +10 -0
- reconcile/unleash_feature_toggles/__init__.py +0 -0
- reconcile/unleash_feature_toggles/integration.py +287 -0
- reconcile/utils/acs/__init__.py +0 -0
- reconcile/utils/acs/base.py +81 -0
- reconcile/utils/acs/notifiers.py +143 -0
- reconcile/utils/acs/policies.py +163 -0
- reconcile/utils/acs/rbac.py +277 -0
- reconcile/utils/aggregated_list.py +11 -9
- reconcile/utils/amtool.py +6 -4
- reconcile/utils/aws_api.py +279 -66
- reconcile/utils/aws_api_typed/__init__.py +0 -0
- reconcile/utils/aws_api_typed/account.py +23 -0
- reconcile/utils/aws_api_typed/api.py +273 -0
- reconcile/utils/aws_api_typed/dynamodb.py +16 -0
- reconcile/utils/aws_api_typed/iam.py +67 -0
- reconcile/utils/aws_api_typed/organization.py +152 -0
- reconcile/utils/aws_api_typed/s3.py +26 -0
- reconcile/utils/aws_api_typed/service_quotas.py +79 -0
- reconcile/utils/aws_api_typed/sts.py +36 -0
- reconcile/utils/aws_api_typed/support.py +79 -0
- reconcile/utils/aws_helper.py +42 -3
- reconcile/utils/batches.py +11 -0
- reconcile/utils/binary.py +7 -9
- reconcile/utils/cloud_resource_best_practice/__init__.py +0 -0
- reconcile/utils/cloud_resource_best_practice/aws_rds.py +66 -0
- reconcile/utils/clusterhealth/__init__.py +0 -0
- reconcile/utils/clusterhealth/providerbase.py +39 -0
- reconcile/utils/clusterhealth/telemeter.py +39 -0
- reconcile/utils/config.py +3 -4
- reconcile/utils/deadmanssnitch_api.py +86 -0
- reconcile/utils/differ.py +205 -0
- reconcile/utils/disabled_integrations.py +4 -6
- reconcile/utils/dynatrace/__init__.py +0 -0
- reconcile/utils/dynatrace/client.py +93 -0
- reconcile/utils/early_exit_cache.py +289 -0
- reconcile/utils/elasticsearch_exceptions.py +5 -0
- reconcile/utils/environ.py +2 -2
- reconcile/utils/exceptions.py +4 -0
- reconcile/utils/expiration.py +4 -8
- reconcile/utils/extended_early_exit.py +210 -0
- reconcile/utils/external_resource_spec.py +34 -12
- reconcile/utils/external_resources.py +48 -20
- reconcile/utils/filtering.py +16 -0
- reconcile/utils/git.py +49 -16
- reconcile/utils/github_api.py +10 -9
- reconcile/utils/gitlab_api.py +333 -190
- reconcile/utils/glitchtip/client.py +97 -100
- reconcile/utils/glitchtip/models.py +89 -11
- reconcile/utils/gql.py +157 -58
- reconcile/utils/grouping.py +17 -0
- reconcile/utils/helm.py +89 -18
- reconcile/utils/helpers.py +51 -0
- reconcile/utils/imap_client.py +5 -6
- reconcile/utils/internal_groups/__init__.py +0 -0
- reconcile/utils/internal_groups/client.py +160 -0
- reconcile/utils/internal_groups/models.py +71 -0
- reconcile/utils/jenkins_api.py +10 -34
- reconcile/utils/jinja2/__init__.py +0 -0
- reconcile/utils/{jinja2_ext.py → jinja2/extensions.py} +6 -4
- reconcile/utils/jinja2/filters.py +142 -0
- reconcile/utils/jinja2/utils.py +278 -0
- reconcile/utils/jira_client.py +165 -8
- reconcile/utils/jjb_client.py +47 -35
- reconcile/utils/jobcontroller/__init__.py +0 -0
- reconcile/utils/jobcontroller/controller.py +413 -0
- reconcile/utils/jobcontroller/models.py +195 -0
- reconcile/utils/jsonpath.py +4 -5
- reconcile/utils/jump_host.py +13 -12
- reconcile/utils/keycloak.py +106 -0
- reconcile/utils/ldap_client.py +35 -6
- reconcile/utils/lean_terraform_client.py +115 -6
- reconcile/utils/membershipsources/__init__.py +0 -0
- reconcile/utils/membershipsources/app_interface_resolver.py +60 -0
- reconcile/utils/membershipsources/models.py +91 -0
- reconcile/utils/membershipsources/resolver.py +110 -0
- reconcile/utils/merge_request_manager/__init__.py +0 -0
- reconcile/utils/merge_request_manager/merge_request_manager.py +99 -0
- reconcile/utils/merge_request_manager/parser.py +67 -0
- reconcile/utils/metrics.py +511 -1
- reconcile/utils/models.py +123 -0
- reconcile/utils/mr/README.md +198 -0
- reconcile/utils/mr/__init__.py +14 -10
- reconcile/utils/mr/app_interface_reporter.py +2 -2
- reconcile/utils/mr/aws_access.py +4 -4
- reconcile/utils/mr/base.py +51 -31
- reconcile/utils/mr/clusters_updates.py +10 -7
- reconcile/utils/mr/glitchtip_access_reporter.py +2 -4
- reconcile/utils/mr/labels.py +14 -1
- reconcile/utils/mr/notificator.py +1 -3
- reconcile/utils/mr/ocm_update_recommended_version.py +1 -2
- reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +7 -3
- reconcile/utils/mr/promote_qontract.py +203 -0
- reconcile/utils/mr/user_maintenance.py +24 -4
- reconcile/utils/oauth2_backend_application_session.py +132 -0
- reconcile/utils/oc.py +194 -170
- reconcile/utils/oc_connection_parameters.py +40 -51
- reconcile/utils/oc_filters.py +11 -13
- reconcile/utils/oc_map.py +14 -35
- reconcile/utils/ocm/__init__.py +30 -1
- reconcile/utils/ocm/addons.py +228 -0
- reconcile/utils/ocm/base.py +618 -5
- reconcile/utils/ocm/cluster_groups.py +5 -56
- reconcile/utils/ocm/clusters.py +111 -99
- reconcile/utils/ocm/identity_providers.py +66 -0
- reconcile/utils/ocm/label_sources.py +75 -0
- reconcile/utils/ocm/labels.py +139 -54
- reconcile/utils/ocm/manifests.py +39 -0
- reconcile/utils/ocm/ocm.py +182 -928
- reconcile/utils/ocm/products.py +758 -0
- reconcile/utils/ocm/search_filters.py +20 -28
- reconcile/utils/ocm/service_log.py +32 -79
- reconcile/utils/ocm/sre_capability_labels.py +51 -0
- reconcile/utils/ocm/status_board.py +66 -0
- reconcile/utils/ocm/subscriptions.py +49 -59
- reconcile/utils/ocm/syncsets.py +39 -0
- reconcile/utils/ocm/upgrades.py +181 -0
- reconcile/utils/ocm_base_client.py +71 -36
- reconcile/utils/openshift_resource.py +113 -67
- reconcile/utils/output.py +18 -11
- reconcile/utils/pagerduty_api.py +16 -10
- reconcile/utils/parse_dhms_duration.py +13 -1
- reconcile/utils/prometheus.py +123 -0
- reconcile/utils/promotion_state.py +56 -19
- reconcile/utils/promtool.py +5 -8
- reconcile/utils/quay_api.py +13 -25
- reconcile/utils/raw_github_api.py +3 -5
- reconcile/utils/repo_owners.py +2 -8
- reconcile/utils/rest_api_base.py +126 -0
- reconcile/utils/rosa/__init__.py +0 -0
- reconcile/utils/rosa/rosa_cli.py +310 -0
- reconcile/utils/rosa/session.py +201 -0
- reconcile/utils/ruamel.py +16 -0
- reconcile/utils/runtime/__init__.py +0 -1
- reconcile/utils/runtime/desired_state_diff.py +9 -20
- reconcile/utils/runtime/environment.py +33 -8
- reconcile/utils/runtime/integration.py +28 -12
- reconcile/utils/runtime/meta.py +1 -3
- reconcile/utils/runtime/runner.py +8 -11
- reconcile/utils/runtime/sharding.py +93 -36
- reconcile/utils/saasherder/__init__.py +1 -1
- reconcile/utils/saasherder/interfaces.py +143 -138
- reconcile/utils/saasherder/models.py +201 -43
- reconcile/utils/saasherder/saasherder.py +508 -378
- reconcile/utils/secret_reader.py +22 -27
- reconcile/utils/semver_helper.py +15 -1
- reconcile/utils/slack_api.py +124 -36
- reconcile/utils/smtp_client.py +1 -2
- reconcile/utils/sqs_gateway.py +10 -6
- reconcile/utils/state.py +276 -127
- reconcile/utils/terraform/config_client.py +6 -7
- reconcile/utils/terraform_client.py +284 -125
- reconcile/utils/terrascript/cloudflare_client.py +38 -17
- reconcile/utils/terrascript/cloudflare_resources.py +67 -18
- reconcile/utils/terrascript/models.py +2 -3
- reconcile/utils/terrascript/resources.py +1 -2
- reconcile/utils/terrascript_aws_client.py +1292 -540
- reconcile/utils/three_way_diff_strategy.py +157 -0
- reconcile/utils/unleash/__init__.py +11 -0
- reconcile/utils/{unleash.py → unleash/client.py} +35 -29
- reconcile/utils/unleash/server.py +145 -0
- reconcile/utils/vault.py +42 -32
- reconcile/utils/vaultsecretref.py +2 -4
- reconcile/utils/vcs.py +250 -0
- reconcile/vault_replication.py +38 -31
- reconcile/vpc_peerings_validator.py +82 -13
- tools/app_interface_metrics_exporter.py +70 -0
- tools/app_interface_reporter.py +44 -157
- tools/cli_commands/container_images_report.py +154 -0
- tools/cli_commands/cost_report/__init__.py +0 -0
- tools/cli_commands/cost_report/aws.py +137 -0
- tools/cli_commands/cost_report/cost_management_api.py +155 -0
- tools/cli_commands/cost_report/model.py +49 -0
- tools/cli_commands/cost_report/openshift.py +166 -0
- tools/cli_commands/cost_report/openshift_cost_optimization.py +187 -0
- tools/cli_commands/cost_report/response.py +124 -0
- tools/cli_commands/cost_report/util.py +72 -0
- tools/cli_commands/cost_report/view.py +524 -0
- tools/cli_commands/erv2.py +620 -0
- tools/cli_commands/gpg_encrypt.py +5 -8
- tools/cli_commands/systems_and_tools.py +489 -0
- tools/glitchtip_access_revalidation.py +1 -1
- tools/qontract_cli.py +2301 -673
- tools/saas_metrics_exporter/__init__.py +0 -0
- tools/saas_metrics_exporter/commit_distance/__init__.py +0 -0
- tools/saas_metrics_exporter/commit_distance/channel.py +63 -0
- tools/saas_metrics_exporter/commit_distance/commit_distance.py +103 -0
- tools/saas_metrics_exporter/commit_distance/metrics.py +19 -0
- tools/saas_metrics_exporter/main.py +99 -0
- tools/saas_promotion_state/__init__.py +0 -0
- tools/saas_promotion_state/saas_promotion_state.py +105 -0
- tools/sd_app_sre_alert_report.py +145 -0
- tools/template_validation.py +107 -0
- e2e_tests/cli.py +0 -83
- e2e_tests/create_namespace.py +0 -43
- e2e_tests/dedicated_admin_rolebindings.py +0 -44
- e2e_tests/dedicated_admin_test_base.py +0 -39
- e2e_tests/default_network_policies.py +0 -47
- e2e_tests/default_project_labels.py +0 -52
- e2e_tests/network_policy_test_base.py +0 -17
- e2e_tests/test_base.py +0 -56
- qontract_reconcile-0.10.0.dist-info/LICENSE +0 -201
- qontract_reconcile-0.10.0.dist-info/METADATA +0 -63
- qontract_reconcile-0.10.0.dist-info/RECORD +0 -586
- qontract_reconcile-0.10.0.dist-info/top_level.txt +0 -4
- reconcile/ecr_mirror.py +0 -152
- reconcile/github_scanner.py +0 -74
- reconcile/gitlab_integrations.py +0 -63
- reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
- reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
- reconcile/integrations_validator.py +0 -18
- reconcile/jenkins_plugins.py +0 -129
- reconcile/kafka_clusters.py +0 -208
- reconcile/ocm_cluster_admin.py +0 -42
- reconcile/ocm_oidc_idp.py +0 -198
- reconcile/ocp_release_mirror.py +0 -373
- reconcile/prometheus_rules_tester_old.py +0 -436
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
- reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
- reconcile/sentry_config.py +0 -613
- reconcile/sentry_helper.py +0 -69
- reconcile/test/conftest.py +0 -187
- reconcile/test/fixtures.py +0 -24
- reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
- reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
- reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
- reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
- reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
- reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
- reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
- reconcile/test/test_aggregated_list.py +0 -237
- reconcile/test/test_amtool.py +0 -37
- reconcile/test/test_auto_promoter.py +0 -295
- reconcile/test/test_aws_ami_share.py +0 -68
- reconcile/test/test_aws_iam_keys.py +0 -70
- reconcile/test/test_aws_iam_password_reset.py +0 -35
- reconcile/test/test_aws_support_cases_sos.py +0 -23
- reconcile/test/test_checkpoint.py +0 -178
- reconcile/test/test_cli.py +0 -41
- reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
- reconcile/test/test_gabi_authorized_users.py +0 -72
- reconcile/test/test_github_org.py +0 -154
- reconcile/test/test_github_repo_invites.py +0 -123
- reconcile/test/test_gitlab_housekeeping.py +0 -88
- reconcile/test/test_gitlab_labeler.py +0 -129
- reconcile/test/test_gitlab_members.py +0 -283
- reconcile/test/test_instrumented_wrappers.py +0 -18
- reconcile/test/test_integrations_manager.py +0 -995
- reconcile/test/test_jenkins_worker_fleets.py +0 -55
- reconcile/test/test_jump_host.py +0 -117
- reconcile/test/test_ldap_users.py +0 -123
- reconcile/test/test_make.py +0 -28
- reconcile/test/test_ocm_additional_routers.py +0 -134
- reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
- reconcile/test/test_ocm_clusters.py +0 -598
- reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
- reconcile/test/test_ocm_oidc_idp.py +0 -315
- reconcile/test/test_ocm_update_recommended_version.py +0 -145
- reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
- reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
- reconcile/test/test_openshift_base.py +0 -730
- reconcile/test/test_openshift_namespace_labels.py +0 -345
- reconcile/test/test_openshift_namespaces.py +0 -256
- reconcile/test/test_openshift_resource.py +0 -415
- reconcile/test/test_openshift_resources_base.py +0 -440
- reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
- reconcile/test/test_openshift_tekton_resources.py +0 -253
- reconcile/test/test_openshift_upgrade_watcher.py +0 -146
- reconcile/test/test_prometheus_rules_tester.py +0 -151
- reconcile/test/test_prometheus_rules_tester_old.py +0 -77
- reconcile/test/test_quay_membership.py +0 -86
- reconcile/test/test_quay_mirror.py +0 -109
- reconcile/test/test_quay_mirror_org.py +0 -70
- reconcile/test/test_quay_repos.py +0 -59
- reconcile/test/test_queries.py +0 -53
- reconcile/test/test_repo_owners.py +0 -47
- reconcile/test/test_requests_sender.py +0 -139
- reconcile/test/test_saasherder.py +0 -1074
- reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
- reconcile/test/test_secret_reader.py +0 -153
- reconcile/test/test_slack_base.py +0 -185
- reconcile/test/test_slack_usergroups.py +0 -744
- reconcile/test/test_sql_query.py +0 -19
- reconcile/test/test_terraform_cloudflare_dns.py +0 -117
- reconcile/test/test_terraform_cloudflare_resources.py +0 -106
- reconcile/test/test_terraform_cloudflare_users.py +0 -749
- reconcile/test/test_terraform_resources.py +0 -257
- reconcile/test/test_terraform_tgw_attachments.py +0 -631
- reconcile/test/test_terraform_users.py +0 -57
- reconcile/test/test_terraform_vpc_peerings.py +0 -499
- reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
- reconcile/test/test_unleash.py +0 -138
- reconcile/test/test_utils_aws_api.py +0 -240
- reconcile/test/test_utils_aws_helper.py +0 -80
- reconcile/test/test_utils_cluster_version_data.py +0 -177
- reconcile/test/test_utils_data_structures.py +0 -13
- reconcile/test/test_utils_disabled_integrations.py +0 -86
- reconcile/test/test_utils_expiration.py +0 -109
- reconcile/test/test_utils_external_resource_spec.py +0 -383
- reconcile/test/test_utils_external_resources.py +0 -247
- reconcile/test/test_utils_github_api.py +0 -73
- reconcile/test/test_utils_gitlab_api.py +0 -20
- reconcile/test/test_utils_gpg.py +0 -69
- reconcile/test/test_utils_gql.py +0 -81
- reconcile/test/test_utils_helm.py +0 -306
- reconcile/test/test_utils_helpers.py +0 -55
- reconcile/test/test_utils_imap_client.py +0 -65
- reconcile/test/test_utils_jjb_client.py +0 -52
- reconcile/test/test_utils_jsonpath.py +0 -286
- reconcile/test/test_utils_ldap_client.py +0 -51
- reconcile/test/test_utils_mr.py +0 -226
- reconcile/test/test_utils_mr_clusters_updates.py +0 -77
- reconcile/test/test_utils_oc.py +0 -984
- reconcile/test/test_utils_ocm.py +0 -110
- reconcile/test/test_utils_pagerduty_api.py +0 -251
- reconcile/test/test_utils_parse_dhms_duration.py +0 -34
- reconcile/test/test_utils_password_validator.py +0 -155
- reconcile/test/test_utils_quay_api.py +0 -86
- reconcile/test/test_utils_semver_helper.py +0 -19
- reconcile/test/test_utils_sharding.py +0 -56
- reconcile/test/test_utils_slack_api.py +0 -439
- reconcile/test/test_utils_smtp_client.py +0 -73
- reconcile/test/test_utils_state.py +0 -256
- reconcile/test/test_utils_terraform.py +0 -13
- reconcile/test/test_utils_terraform_client.py +0 -585
- reconcile/test/test_utils_terraform_config_client.py +0 -219
- reconcile/test/test_utils_terrascript_aws_client.py +0 -277
- reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
- reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
- reconcile/test/test_vault_replication.py +0 -515
- reconcile/test/test_vault_utils.py +0 -47
- reconcile/test/test_version_bump.py +0 -18
- reconcile/test/test_vpc_peerings_validator.py +0 -103
- reconcile/test/test_wrong_region.py +0 -78
- reconcile/typed_queries/glitchtip_settings.py +0 -18
- reconcile/typed_queries/ocp_release_mirror.py +0 -11
- reconcile/unleash_watcher.py +0 -120
- reconcile/utils/git_secrets.py +0 -63
- reconcile/utils/mr/auto_promoter.py +0 -218
- reconcile/utils/sentry_client.py +0 -383
- release/test_version.py +0 -50
- release/version.py +0 -100
- tools/test/test_qontract_cli.py +0 -60
- tools/test/test_sre_checkpoints.py +0 -79
- /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
- /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
- /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
- {release → reconcile/endpoints_discovery}/__init__.py +0 -0
- {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -0,0 +1,413 @@
|
|
1
|
+
import logging
|
2
|
+
import time
|
3
|
+
from datetime import datetime
|
4
|
+
from typing import Protocol, TextIO
|
5
|
+
|
6
|
+
from kubernetes.client import ( # type: ignore[attr-defined]
|
7
|
+
ApiClient,
|
8
|
+
V1Job,
|
9
|
+
V1ObjectMeta,
|
10
|
+
V1OwnerReference,
|
11
|
+
V1Secret,
|
12
|
+
)
|
13
|
+
|
14
|
+
from reconcile.typed_queries.clusters_minimal import get_clusters_minimal
|
15
|
+
from reconcile.utils.jobcontroller.models import (
|
16
|
+
JOB_GENERATION_ANNOTATION,
|
17
|
+
JobConcurrencyPolicy,
|
18
|
+
JobStatus,
|
19
|
+
JobValidationError,
|
20
|
+
K8sJob,
|
21
|
+
)
|
22
|
+
from reconcile.utils.oc import OCCli
|
23
|
+
from reconcile.utils.oc_map import init_oc_map_from_clusters
|
24
|
+
from reconcile.utils.openshift_resource import OpenshiftResource
|
25
|
+
from reconcile.utils.secret_reader import SecretReaderBase
|
26
|
+
|
27
|
+
|
28
|
+
def build_job_controller(
|
29
|
+
integration: str,
|
30
|
+
integration_version: str,
|
31
|
+
cluster: str,
|
32
|
+
namespace: str,
|
33
|
+
secret_reader: SecretReaderBase,
|
34
|
+
dry_run: bool,
|
35
|
+
) -> "K8sJobController":
|
36
|
+
"""
|
37
|
+
Builds a job controller that will act on the given cluster and namespace.
|
38
|
+
The integration name and integration_version are used to annotate the jobs
|
39
|
+
created by the controller so there is a way to identify the source for them.
|
40
|
+
|
41
|
+
The cluster parameter is the name of a cluster defined in app-interface. The namespace
|
42
|
+
is expected to exist in the cluster.
|
43
|
+
|
44
|
+
If dry_run is set to True, the controller will not perform any changes to the cluster.
|
45
|
+
"""
|
46
|
+
clusters = get_clusters_minimal(name=cluster)
|
47
|
+
oc_map = init_oc_map_from_clusters(
|
48
|
+
clusters=clusters,
|
49
|
+
secret_reader=secret_reader,
|
50
|
+
integration=integration,
|
51
|
+
thread_pool_size=1,
|
52
|
+
init_api_resources=False,
|
53
|
+
)
|
54
|
+
oc = oc_map.get_cluster(cluster=cluster)
|
55
|
+
return K8sJobController(
|
56
|
+
oc=oc,
|
57
|
+
cluster=cluster,
|
58
|
+
namespace=namespace,
|
59
|
+
integration=integration,
|
60
|
+
integration_version=integration_version,
|
61
|
+
dry_run=dry_run,
|
62
|
+
)
|
63
|
+
|
64
|
+
|
65
|
+
class TimeProtocol(Protocol):
|
66
|
+
def time(self) -> float: ...
|
67
|
+
|
68
|
+
def sleep(self, seconds: float) -> None: ...
|
69
|
+
|
70
|
+
|
71
|
+
class K8sJobController:
|
72
|
+
def __init__(
|
73
|
+
self,
|
74
|
+
oc: OCCli,
|
75
|
+
cluster: str,
|
76
|
+
namespace: str,
|
77
|
+
integration: str,
|
78
|
+
integration_version: str,
|
79
|
+
dry_run: bool = False,
|
80
|
+
time_module: TimeProtocol = time,
|
81
|
+
) -> None:
|
82
|
+
self.cluster = cluster
|
83
|
+
self.namespace = namespace
|
84
|
+
self.integration = integration
|
85
|
+
self.integration_version = integration_version
|
86
|
+
self.oc = oc
|
87
|
+
self.dry_run = dry_run
|
88
|
+
self.time_module = time_module
|
89
|
+
self._cache: dict[str, OpenshiftResource] | None = None
|
90
|
+
|
91
|
+
@property
|
92
|
+
def cache(self) -> dict[str, OpenshiftResource]:
|
93
|
+
if self._cache is None:
|
94
|
+
return self.update_cache()
|
95
|
+
return self._cache
|
96
|
+
|
97
|
+
def update_cache(self) -> dict[str, OpenshiftResource]:
|
98
|
+
"""
|
99
|
+
Updates the cache with the latest jobs in the namespace.
|
100
|
+
"""
|
101
|
+
new_cache = {}
|
102
|
+
for item in self.oc.get_items(
|
103
|
+
kind="Job",
|
104
|
+
namespace=self.namespace,
|
105
|
+
):
|
106
|
+
openshift_resource = OpenshiftResource(
|
107
|
+
body=item,
|
108
|
+
integration=self.integration,
|
109
|
+
integration_version=self.integration_version,
|
110
|
+
)
|
111
|
+
new_cache[openshift_resource.name] = openshift_resource
|
112
|
+
self._cache = new_cache
|
113
|
+
return self._cache
|
114
|
+
|
115
|
+
def get_job_generation(self, job_name: str) -> str | None:
|
116
|
+
"""
|
117
|
+
Returns the generation annotation for a job.
|
118
|
+
"""
|
119
|
+
job_resource = self.cache.get(job_name)
|
120
|
+
if job_resource is None:
|
121
|
+
return None
|
122
|
+
return (
|
123
|
+
job_resource.body.get("metadata", {})
|
124
|
+
.get("annotations", {})
|
125
|
+
.get(JOB_GENERATION_ANNOTATION)
|
126
|
+
)
|
127
|
+
|
128
|
+
def get_job_status(self, job_name: str) -> JobStatus:
|
129
|
+
"""
|
130
|
+
Looks up the status for a job. It expects the cache to be up to date, so
|
131
|
+
the caller of this function should consider calling update_cache before
|
132
|
+
calling this function.
|
133
|
+
"""
|
134
|
+
job_resource = self.cache.get(job_name)
|
135
|
+
|
136
|
+
if job_resource is None:
|
137
|
+
return JobStatus.NOT_EXISTS
|
138
|
+
|
139
|
+
status = job_resource.body.get("status") or {}
|
140
|
+
backofflimit = job_resource.body["spec"].get("backoffLimit", 6)
|
141
|
+
if status.get("succeeded", 0) > 0:
|
142
|
+
return JobStatus.SUCCESS
|
143
|
+
elif status.get("failed", 0) > backofflimit:
|
144
|
+
return JobStatus.ERROR
|
145
|
+
return JobStatus.IN_PROGRESS
|
146
|
+
|
147
|
+
def get_success_job_duration(self, job_name: str) -> int | None:
|
148
|
+
"""
|
149
|
+
Returns the number of seconds the job took to complete.
|
150
|
+
* If a job is not completed with success, returns None
|
151
|
+
"""
|
152
|
+
if self.get_job_status(job_name) != JobStatus.SUCCESS:
|
153
|
+
return None
|
154
|
+
job_resource = self.cache.get(job_name)
|
155
|
+
if job_resource is None:
|
156
|
+
return None
|
157
|
+
status = job_resource.body.get("status") or {}
|
158
|
+
start_time = status.get("startTime", None)
|
159
|
+
completion_time = status.get("completionTime", None)
|
160
|
+
if not completion_time or not start_time:
|
161
|
+
return None
|
162
|
+
dt_start_time = datetime.fromisoformat(start_time)
|
163
|
+
dt_completion_time = datetime.fromisoformat(completion_time)
|
164
|
+
return int((dt_completion_time - dt_start_time).total_seconds())
|
165
|
+
|
166
|
+
def wait_for_job_list_completion(
|
167
|
+
self, job_names: set[str], check_interval_seconds: int, timeout_seconds: int
|
168
|
+
) -> dict[str, JobStatus]:
|
169
|
+
"""
|
170
|
+
Waits for all jobs in the list to complete, and returns their statuses.
|
171
|
+
* if a job from the list does not exist, it will have the status NOT_EXISTS set in the result.
|
172
|
+
* if a job did not finish within the timeout boundaries, it will have the status
|
173
|
+
IN_PROGRESS set in the result
|
174
|
+
* failed and successful jobs report SUCCESS or ERROR respectively
|
175
|
+
|
176
|
+
The check_interval_seconds parameter is the time to wait between checks for job completion.
|
177
|
+
The timeout_seconds parameter is the maximum time to wait for all jobs to complete. If set to -1,
|
178
|
+
the function will wait indefinitely. If a timeout occures, a TimeoutError will be raised.
|
179
|
+
"""
|
180
|
+
jobs_left = job_names.copy()
|
181
|
+
job_statuses: dict[str, JobStatus] = dict.fromkeys(
|
182
|
+
job_names, JobStatus.NOT_EXISTS
|
183
|
+
)
|
184
|
+
|
185
|
+
start_time = self.time_module.time()
|
186
|
+
while jobs_left:
|
187
|
+
self.update_cache()
|
188
|
+
for job_name in list(jobs_left):
|
189
|
+
status = self.get_job_status(job_name)
|
190
|
+
job_statuses[job_name] = status
|
191
|
+
if status in {JobStatus.SUCCESS, JobStatus.ERROR}:
|
192
|
+
jobs_left.remove(job_name)
|
193
|
+
if jobs_left:
|
194
|
+
elapsed_time = self.time_module.time() - start_time
|
195
|
+
if timeout_seconds >= 0 and elapsed_time >= timeout_seconds:
|
196
|
+
logging.warning(
|
197
|
+
f"Timeout waiting for jobs to complete: {jobs_left}"
|
198
|
+
)
|
199
|
+
break
|
200
|
+
logging.info(
|
201
|
+
f"Waiting for {jobs_left} to complete. Rechecking in {check_interval_seconds} seconds"
|
202
|
+
)
|
203
|
+
self._sleep_until_timeout(
|
204
|
+
elapsed_time, timeout_seconds, check_interval_seconds
|
205
|
+
)
|
206
|
+
return job_statuses
|
207
|
+
|
208
|
+
def enqueue_job_and_wait_for_completion(
|
209
|
+
self,
|
210
|
+
job: K8sJob,
|
211
|
+
check_interval_seconds: int,
|
212
|
+
timeout_seconds: int,
|
213
|
+
concurrency_policy: JobConcurrencyPolicy = JobConcurrencyPolicy.NO_REPLACE,
|
214
|
+
) -> JobStatus:
|
215
|
+
"""
|
216
|
+
Schedules a job and waits for it to complete.
|
217
|
+
* For the concurrency_policy, see documentation on the enqueue_job function
|
218
|
+
* For check_interval_seconds and timeout_seconds, see documentation on the wait_for_job_completion function
|
219
|
+
"""
|
220
|
+
self.enqueue_job(job, concurrency_policy)
|
221
|
+
success = self.wait_for_job_completion(
|
222
|
+
job.name(), check_interval_seconds, timeout_seconds
|
223
|
+
)
|
224
|
+
return JobStatus.SUCCESS if success else JobStatus.ERROR
|
225
|
+
|
226
|
+
def enqueue_job(
|
227
|
+
self,
|
228
|
+
job: K8sJob,
|
229
|
+
concurrency_policy: JobConcurrencyPolicy = JobConcurrencyPolicy.NO_REPLACE,
|
230
|
+
) -> bool:
|
231
|
+
"""
|
232
|
+
Schedules a job on a cluster.
|
233
|
+
|
234
|
+
In general a new job will not be scheduled if one with the same name already exists. This behaviour can
|
235
|
+
be influenced by the concurrency_policy parameter. The following flags are available:
|
236
|
+
|
237
|
+
* REPLACE_FAILED: if a job with the same name exists and it has failed, it will be replaced
|
238
|
+
* REPLACE_IN_PROGRESS: if a job with the same name exists and it is in progress, it will be replaced
|
239
|
+
* REPLACE_FINISHED: if a job with the same name exists and it has finished, it will be replaced
|
240
|
+
|
241
|
+
True is returned when the job was scheduled or replaced an existing job, False otherwise.
|
242
|
+
"""
|
243
|
+
job_name = job.name()
|
244
|
+
job_status = self.get_job_status(job_name)
|
245
|
+
|
246
|
+
cancel_existing_job = False
|
247
|
+
create_job = False
|
248
|
+
match job_status:
|
249
|
+
case JobStatus.IN_PROGRESS:
|
250
|
+
if concurrency_policy & JobConcurrencyPolicy.REPLACE_IN_PROGRESS:
|
251
|
+
cancel_existing_job = True
|
252
|
+
create_job = True
|
253
|
+
case JobStatus.ERROR:
|
254
|
+
if concurrency_policy & JobConcurrencyPolicy.REPLACE_FAILED:
|
255
|
+
cancel_existing_job = True
|
256
|
+
create_job = True
|
257
|
+
case JobStatus.SUCCESS:
|
258
|
+
if concurrency_policy & JobConcurrencyPolicy.REPLACE_FINISHED:
|
259
|
+
cancel_existing_job = True
|
260
|
+
create_job = True
|
261
|
+
case JobStatus.NOT_EXISTS:
|
262
|
+
create_job = True
|
263
|
+
|
264
|
+
if cancel_existing_job:
|
265
|
+
self.delete_job(job.name())
|
266
|
+
if create_job:
|
267
|
+
self.create_job(job)
|
268
|
+
return True
|
269
|
+
return False
|
270
|
+
|
271
|
+
def _lookup_job_uid(self, job_name: str) -> str | None:
|
272
|
+
job_resource = self.oc.get(
|
273
|
+
self.namespace, "Job", job_name, allow_not_found=True
|
274
|
+
)
|
275
|
+
if not job_resource:
|
276
|
+
return None
|
277
|
+
return job_resource.get("metadata", {}).get("uid")
|
278
|
+
|
279
|
+
def build_secret(self, job: K8sJob) -> V1Secret | None:
|
280
|
+
secret_data = job.secret_data()
|
281
|
+
script_data = job.scripts()
|
282
|
+
# fail if both dicts have overlapping keys
|
283
|
+
if not set(secret_data).isdisjoint(script_data):
|
284
|
+
raise JobValidationError(
|
285
|
+
f"Secret data and script data have overlapping keys for {job.name()}"
|
286
|
+
)
|
287
|
+
data = {**secret_data, **script_data}
|
288
|
+
if not data:
|
289
|
+
return None
|
290
|
+
|
291
|
+
job_name = job.name()
|
292
|
+
job_uid = self._lookup_job_uid(job_name)
|
293
|
+
if not job_uid:
|
294
|
+
raise Exception(f"Failed to lookup job uid for {job_name}")
|
295
|
+
return V1Secret(
|
296
|
+
api_version="v1",
|
297
|
+
kind="Secret",
|
298
|
+
metadata=V1ObjectMeta(
|
299
|
+
name=job_name,
|
300
|
+
annotations=job.annotations(),
|
301
|
+
labels=job.labels(),
|
302
|
+
owner_references=[
|
303
|
+
V1OwnerReference(
|
304
|
+
api_version="batch/v1",
|
305
|
+
kind="Job",
|
306
|
+
name=job_name,
|
307
|
+
uid=job_uid,
|
308
|
+
)
|
309
|
+
],
|
310
|
+
),
|
311
|
+
string_data=data,
|
312
|
+
)
|
313
|
+
|
314
|
+
def create_job(self, job: K8sJob) -> None:
|
315
|
+
"""
|
316
|
+
Creates the K8S job on the cluster and namespace.
|
317
|
+
"""
|
318
|
+
job_spec = job.build_job()
|
319
|
+
self.validate_job(job_spec)
|
320
|
+
api = ApiClient()
|
321
|
+
self.oc.apply(
|
322
|
+
namespace=self.namespace,
|
323
|
+
resource=OpenshiftResource(
|
324
|
+
api.sanitize_for_serialization(job.build_job()),
|
325
|
+
self.integration,
|
326
|
+
self.integration_version,
|
327
|
+
).annotate(),
|
328
|
+
)
|
329
|
+
|
330
|
+
# if the job defines secret data, we need to create the secret
|
331
|
+
# with proper owner reference
|
332
|
+
job_secret = self.build_secret(job)
|
333
|
+
if job_secret:
|
334
|
+
self.oc.apply(
|
335
|
+
namespace=self.namespace,
|
336
|
+
resource=OpenshiftResource(
|
337
|
+
api.sanitize_for_serialization(job_secret),
|
338
|
+
self.integration,
|
339
|
+
self.integration_version,
|
340
|
+
).annotate(),
|
341
|
+
)
|
342
|
+
|
343
|
+
def validate_job(self, job: V1Job) -> None:
|
344
|
+
if not job.spec:
|
345
|
+
raise JobValidationError("Job spec is missing")
|
346
|
+
if not job.spec.ttl_seconds_after_finished:
|
347
|
+
raise JobValidationError("Job spec is missing ttlSecondsAfterFinished")
|
348
|
+
|
349
|
+
def delete_job(self, job_name: str) -> None:
|
350
|
+
job_status = self.get_job_status(job_name)
|
351
|
+
if job_status != JobStatus.NOT_EXISTS:
|
352
|
+
self.oc.delete(self.namespace, "Job", job_name)
|
353
|
+
|
354
|
+
def wait_for_job_completion(
|
355
|
+
self, job_name: str, check_interval_seconds: int, timeout_seconds: int
|
356
|
+
) -> bool:
|
357
|
+
"""
|
358
|
+
Waits for a job to complete. Returns True if the job was successful, False otherwise.
|
359
|
+
|
360
|
+
The check_interval_seconds parameter is the time to wait between checks for job completion.
|
361
|
+
The timeout_seconds parameter is the maximum time to wait for all jobs to complete. If set to -1,
|
362
|
+
the function will wait indefinitely. If a timeout occures, a TimeoutError will be raised.
|
363
|
+
"""
|
364
|
+
start_time = self.time_module.time()
|
365
|
+
while True:
|
366
|
+
self.update_cache()
|
367
|
+
status = self.get_job_status(job_name)
|
368
|
+
match status:
|
369
|
+
case JobStatus.SUCCESS:
|
370
|
+
return True
|
371
|
+
case JobStatus.ERROR:
|
372
|
+
return False
|
373
|
+
elapsed_time = self.time_module.time() - start_time
|
374
|
+
if timeout_seconds >= 0 and elapsed_time >= timeout_seconds:
|
375
|
+
raise TimeoutError(f"Timeout waiting for job {job_name} to complete")
|
376
|
+
self._sleep_until_timeout(
|
377
|
+
elapsed_time, timeout_seconds, check_interval_seconds
|
378
|
+
)
|
379
|
+
|
380
|
+
def _sleep_until_timeout(
|
381
|
+
self,
|
382
|
+
elapsed_time: float,
|
383
|
+
timeout_seconds: float,
|
384
|
+
default_sleep_interval_seconds: float,
|
385
|
+
) -> None:
|
386
|
+
sleep_interval_seconds = default_sleep_interval_seconds
|
387
|
+
if timeout_seconds >= 0:
|
388
|
+
sleep_interval_seconds = min(
|
389
|
+
default_sleep_interval_seconds, timeout_seconds - elapsed_time
|
390
|
+
)
|
391
|
+
if sleep_interval_seconds > 0:
|
392
|
+
self.time_module.sleep(sleep_interval_seconds)
|
393
|
+
|
394
|
+
def store_job_logs(self, job_name: str, output_dir_path: str) -> str:
|
395
|
+
"""
|
396
|
+
Stores the logs of a job in the given output directory.
|
397
|
+
The filename will be the name of the job.
|
398
|
+
"""
|
399
|
+
return self.oc.job_logs_latest_pod(
|
400
|
+
namespace=self.namespace,
|
401
|
+
name=job_name,
|
402
|
+
output=output_dir_path,
|
403
|
+
)
|
404
|
+
|
405
|
+
def get_job_logs(self, job_name: str, output: str | TextIO) -> None:
|
406
|
+
return self.oc.job_logs(
|
407
|
+
namespace=self.namespace,
|
408
|
+
name=job_name,
|
409
|
+
output=output,
|
410
|
+
follow=False,
|
411
|
+
wait_for_job_running=False,
|
412
|
+
wait_for_logs_process=True,
|
413
|
+
)
|
@@ -0,0 +1,195 @@
|
|
1
|
+
import hashlib
|
2
|
+
import inspect
|
3
|
+
from abc import ABC, abstractmethod
|
4
|
+
from enum import IntFlag, StrEnum
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from deepdiff import DeepHash
|
8
|
+
from kubernetes.client import (
|
9
|
+
V1EnvVar,
|
10
|
+
V1EnvVarSource,
|
11
|
+
V1Job,
|
12
|
+
V1JobSpec,
|
13
|
+
V1KeyToPath,
|
14
|
+
V1ObjectMeta,
|
15
|
+
V1SecretKeySelector,
|
16
|
+
V1SecretVolumeSource,
|
17
|
+
V1Volume,
|
18
|
+
V1VolumeMount,
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
class JobStatus(StrEnum):
|
23
|
+
SUCCESS: str = "SUCCESS"
|
24
|
+
ERROR: str = "ERROR"
|
25
|
+
IN_PROGRESS: str = "IN_PROGRESS"
|
26
|
+
NOT_EXISTS: str = "NOT_EXISTS"
|
27
|
+
|
28
|
+
|
29
|
+
class JobConcurrencyPolicy(IntFlag):
|
30
|
+
NO_REPLACE: int = 1
|
31
|
+
REPLACE_FAILED: int = 2
|
32
|
+
REPLACE_IN_PROGRESS: int = 4
|
33
|
+
REPLACE_FINISHED: int = 8
|
34
|
+
|
35
|
+
|
36
|
+
class JobValidationError(Exception):
|
37
|
+
pass
|
38
|
+
|
39
|
+
|
40
|
+
JOB_GENERATION_ANNOTATION = "qontract-reconcile/job.generation"
|
41
|
+
|
42
|
+
|
43
|
+
class K8sJob(ABC):
|
44
|
+
"""
|
45
|
+
This is the base class for all jobs that will be managed by the
|
46
|
+
K8sJobController.
|
47
|
+
|
48
|
+
A job needs to implement the following methods:
|
49
|
+
- name_prefix: return the prefix of the job name. This is useful to group
|
50
|
+
jobs of the same type together. The prefix is part of the final job name.
|
51
|
+
|
52
|
+
- unit_of_work_identity: return the data that uniquely identifies the unit
|
53
|
+
of work that the job will perform. This data will be used to calculate a
|
54
|
+
hash that will be used as part of the job name. This way a unit of work
|
55
|
+
can be uniquely identified by the job name.
|
56
|
+
|
57
|
+
- job_spec: return the job spec that will be used as the spec part of
|
58
|
+
the Kubernetes Job.
|
59
|
+
|
60
|
+
The job can optionally also implement the following methods:
|
61
|
+
- annotations: return a dictionary with the annotations that will be used
|
62
|
+
in the job metadata.
|
63
|
+
- labels: return a dictionary with the labels that will be used in the job
|
64
|
+
metadata.
|
65
|
+
- build_job: return the V1Job object that will be used to create the job in
|
66
|
+
Kubernetes. Override this method if you need to customize the job that
|
67
|
+
will represent your unit of work in Kubernetes.
|
68
|
+
- name: return the name of the job. Override this method if you need to
|
69
|
+
customize the name of the job that will represent your unit of work in
|
70
|
+
Kubernetes. Keep in mind that the name of the job is used to identify job
|
71
|
+
and the controllers concurrency policy functionality is based on the job name.
|
72
|
+
"""
|
73
|
+
|
74
|
+
def name(self) -> str:
|
75
|
+
return f"{self.name_prefix()}-{self.unit_of_work_digest()}"
|
76
|
+
|
77
|
+
@abstractmethod
|
78
|
+
def name_prefix(self) -> str:
|
79
|
+
"""
|
80
|
+
Return the prefix of the job name. This is useful to group jobs of the
|
81
|
+
same type together. The prefix is part of the final job name.
|
82
|
+
"""
|
83
|
+
...
|
84
|
+
|
85
|
+
def unit_of_work_digest(self, length: int = 10) -> str:
|
86
|
+
data = self.unit_of_work_identity()
|
87
|
+
hash = DeepHash(data).get(data)
|
88
|
+
return str(hash)[:length]
|
89
|
+
|
90
|
+
@abstractmethod
|
91
|
+
def unit_of_work_identity(self) -> Any:
|
92
|
+
"""
|
93
|
+
Return the data that uniquely identifies the unit of work that the job
|
94
|
+
will perform. This data will be used to calculate a hash that will be
|
95
|
+
used as part of the job name.
|
96
|
+
"""
|
97
|
+
...
|
98
|
+
|
99
|
+
def annotations(self) -> dict[str, Any]:
|
100
|
+
return {}
|
101
|
+
|
102
|
+
def labels(self) -> dict[str, str]:
|
103
|
+
return {}
|
104
|
+
|
105
|
+
def build_job(self) -> V1Job:
|
106
|
+
job_annotations = self.annotations()
|
107
|
+
job_annotations[JOB_GENERATION_ANNOTATION] = self.job_spec_generation_digest()
|
108
|
+
return V1Job(
|
109
|
+
api_version="batch/v1",
|
110
|
+
kind="Job",
|
111
|
+
metadata=V1ObjectMeta(
|
112
|
+
name=self.name(),
|
113
|
+
annotations=job_annotations,
|
114
|
+
labels=self.labels(),
|
115
|
+
),
|
116
|
+
spec=self.job_spec(),
|
117
|
+
)
|
118
|
+
|
119
|
+
@abstractmethod
|
120
|
+
def job_spec(self) -> V1JobSpec: ...
|
121
|
+
|
122
|
+
def job_spec_generation_digest(self, length: int = 10) -> str:
|
123
|
+
"""
|
124
|
+
Calculate a hash of the job spec source code to be used as a generation
|
125
|
+
identifier for the job spec. This is useful to determine if the job
|
126
|
+
spec has changed and a job needs to be replaced.
|
127
|
+
"""
|
128
|
+
job_spec_source_code = inspect.getsource(self.job_spec)
|
129
|
+
hash_object = hashlib.sha256(job_spec_source_code.encode())
|
130
|
+
hash = hash_object.hexdigest()
|
131
|
+
return hash[:length]
|
132
|
+
|
133
|
+
def secret_data(self) -> dict[str, str]:
|
134
|
+
"""
|
135
|
+
If a job relies on some secret data, it should return it here. The
|
136
|
+
job controller will manage the lifecycle of a kubernetes Secret.
|
137
|
+
"""
|
138
|
+
return {}
|
139
|
+
|
140
|
+
def scripts(self) -> dict[str, str]:
|
141
|
+
"""
|
142
|
+
If a job relies on some scripts, it should return them here. The
|
143
|
+
job controller will manage the lifecycle of a kubernetes Secret containing them.
|
144
|
+
"""
|
145
|
+
return {}
|
146
|
+
|
147
|
+
def secret_data_to_env_vars_secret_refs(self) -> list[V1EnvVar]:
|
148
|
+
"""
|
149
|
+
Helper function to generate env var references from the `secret_data`,
|
150
|
+
to be used in container specs
|
151
|
+
"""
|
152
|
+
secret_name = self.name()
|
153
|
+
return [
|
154
|
+
V1EnvVar(
|
155
|
+
name=secret_key_name,
|
156
|
+
value_from=V1EnvVarSource(
|
157
|
+
secret_key_ref=V1SecretKeySelector(
|
158
|
+
name=secret_name,
|
159
|
+
key=secret_key_name,
|
160
|
+
)
|
161
|
+
),
|
162
|
+
)
|
163
|
+
for secret_key_name in self.secret_data()
|
164
|
+
]
|
165
|
+
|
166
|
+
def scripts_volume_mount(self, directory: str) -> V1VolumeMount:
|
167
|
+
"""
|
168
|
+
Helper function to generate a volume mount for the `scripts` to be used
|
169
|
+
in container specs
|
170
|
+
"""
|
171
|
+
secret_name = self.name()
|
172
|
+
return V1VolumeMount(
|
173
|
+
name=secret_name,
|
174
|
+
mount_path=directory,
|
175
|
+
)
|
176
|
+
|
177
|
+
def scripts_volume(self) -> V1Volume:
|
178
|
+
"""
|
179
|
+
Helper function to generate a volume for the `scripts` to be used in
|
180
|
+
pod specs
|
181
|
+
"""
|
182
|
+
secret_name = self.name()
|
183
|
+
return V1Volume(
|
184
|
+
name=secret_name,
|
185
|
+
secret=V1SecretVolumeSource(
|
186
|
+
secret_name=secret_name,
|
187
|
+
items=[
|
188
|
+
V1KeyToPath(
|
189
|
+
key=script_name,
|
190
|
+
path=script_name,
|
191
|
+
)
|
192
|
+
for script_name in self.scripts()
|
193
|
+
],
|
194
|
+
),
|
195
|
+
)
|
reconcile/utils/jsonpath.py
CHANGED
@@ -4,7 +4,6 @@ from functools import (
|
|
4
4
|
reduce,
|
5
5
|
)
|
6
6
|
from itertools import zip_longest
|
7
|
-
from typing import Optional
|
8
7
|
|
9
8
|
import jsonpath_ng
|
10
9
|
import jsonpath_ng.ext.filter
|
@@ -54,11 +53,11 @@ def narrow_jsonpath_node(
|
|
54
53
|
if path_2.fields == ("*",):
|
55
54
|
return path_1
|
56
55
|
elif isinstance(path_1, jsonpath_ng.Index) and isinstance(
|
57
|
-
path_2,
|
56
|
+
path_2, jsonpath_ng.Slice | jsonpath_ng.ext.filter.Filter
|
58
57
|
):
|
59
58
|
return path_1
|
60
59
|
elif isinstance(
|
61
|
-
path_1,
|
60
|
+
path_1, jsonpath_ng.Slice | jsonpath_ng.ext.filter.Filter
|
62
61
|
) and isinstance(path_2, jsonpath_ng.Index):
|
63
62
|
return path_2
|
64
63
|
elif isinstance(path_1, jsonpath_ng.ext.filter.Filter) and isinstance(
|
@@ -119,7 +118,7 @@ def apply_constraint_to_path(
|
|
119
118
|
path: jsonpath_ng.JSONPath,
|
120
119
|
path_constraint: jsonpath_ng.JSONPath,
|
121
120
|
min_common_prefix_length: int = 1,
|
122
|
-
) ->
|
121
|
+
) -> jsonpath_ng.JSONPath | None:
|
123
122
|
"""
|
124
123
|
Narrow the `path` with a more specific `path_constraint`.
|
125
124
|
e.g. if the path constraints a slice `[*]` and the constraints a
|
@@ -148,7 +147,7 @@ def apply_constraint_to_path(
|
|
148
147
|
|
149
148
|
def remove_prefix_from_path(
|
150
149
|
path: jsonpath_ng.JSONPath, prefix: jsonpath_ng.JSONPath
|
151
|
-
) ->
|
150
|
+
) -> jsonpath_ng.JSONPath | None:
|
152
151
|
path_parts = jsonpath_parts(path, ignore_root=True)
|
153
152
|
prefix_parts = jsonpath_parts(prefix, ignore_root=True)
|
154
153
|
|