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
@@ -1,4 +1,6 @@
|
|
1
|
+
# ruff: noqa: SIM114
|
1
2
|
import base64
|
3
|
+
import contextlib
|
2
4
|
import copy
|
3
5
|
import datetime
|
4
6
|
import hashlib
|
@@ -6,12 +8,12 @@ import json
|
|
6
8
|
import re
|
7
9
|
from collections.abc import Mapping
|
8
10
|
from threading import Lock
|
9
|
-
from typing import (
|
10
|
-
Optional,
|
11
|
-
Union,
|
12
|
-
)
|
13
11
|
|
14
12
|
import semver
|
13
|
+
from pydantic import BaseModel
|
14
|
+
|
15
|
+
from reconcile.external_resources.meta import SECRET_UPDATED_AT
|
16
|
+
from reconcile.utils.metrics import GaugeMetric
|
15
17
|
|
16
18
|
SECRET_MAX_KEY_LENGTH = 253
|
17
19
|
|
@@ -20,6 +22,10 @@ class ResourceKeyExistsError(Exception):
|
|
20
22
|
pass
|
21
23
|
|
22
24
|
|
25
|
+
class ResourceNotManagedError(Exception):
|
26
|
+
pass
|
27
|
+
|
28
|
+
|
23
29
|
class ConstructResourceError(Exception):
|
24
30
|
def __init__(self, msg):
|
25
31
|
super().__init__("error constructing openshift resource: " + str(msg))
|
@@ -40,7 +46,7 @@ IGNORABLE_DATA_FIELDS = ["service-ca.crt"]
|
|
40
46
|
# these labels existance and/or value is determined by a controller running
|
41
47
|
# on the cluster. we need to ignore their existance in the current state,
|
42
48
|
# otherwise we will deal with constant reconciliation
|
43
|
-
CONTROLLER_MANAGED_LABELS: dict[str, set[
|
49
|
+
CONTROLLER_MANAGED_LABELS: dict[str, set[str | re.Pattern]] = {
|
44
50
|
"ManagedCluster": {
|
45
51
|
"clusterID",
|
46
52
|
"managed-by",
|
@@ -49,7 +55,22 @@ CONTROLLER_MANAGED_LABELS: dict[str, set[Union[str, re.Pattern]]] = {
|
|
49
55
|
}
|
50
56
|
}
|
51
57
|
|
58
|
+
QONTRACT_ANNOTATION_INTEGRATION = "qontract.integration"
|
59
|
+
QONTRACT_ANNOTATION_INTEGRATION_VERSION = "qontract.integration_version"
|
60
|
+
QONTRACT_ANNOTATION_SHA256SUM = "qontract.sha256sum"
|
61
|
+
QONTRACT_ANNOTATION_UPDATE = "qontract.update"
|
62
|
+
QONTRACT_ANNOTATION_CALLER_NAME = "qontract.caller_name"
|
63
|
+
|
64
|
+
QONTRACT_ANNOTATIONS = {
|
65
|
+
QONTRACT_ANNOTATION_INTEGRATION,
|
66
|
+
QONTRACT_ANNOTATION_INTEGRATION_VERSION,
|
67
|
+
QONTRACT_ANNOTATION_SHA256SUM,
|
68
|
+
QONTRACT_ANNOTATION_UPDATE,
|
69
|
+
QONTRACT_ANNOTATION_CALLER_NAME,
|
70
|
+
}
|
71
|
+
|
52
72
|
|
73
|
+
# pylint: disable=R0904
|
53
74
|
class OpenshiftResource:
|
54
75
|
def __init__(
|
55
76
|
self,
|
@@ -81,7 +102,7 @@ class OpenshiftResource:
|
|
81
102
|
for obj1_k, obj1_v in obj1.items():
|
82
103
|
obj2_v = obj2.get(obj1_k, None)
|
83
104
|
if obj2_v is None:
|
84
|
-
if obj1_v
|
105
|
+
if obj1_v:
|
85
106
|
return False
|
86
107
|
if self.ignorable_field(obj1_k):
|
87
108
|
pass
|
@@ -100,7 +121,7 @@ class OpenshiftResource:
|
|
100
121
|
]
|
101
122
|
if diff or not self.obj_intersect_equal(obj1_v, obj2_v, depth + 1):
|
102
123
|
return False
|
103
|
-
elif obj1_k in
|
124
|
+
elif obj1_k in {"data", "matchLabels"}:
|
104
125
|
diff = [
|
105
126
|
k
|
106
127
|
for k in obj2_v
|
@@ -153,28 +174,22 @@ class OpenshiftResource:
|
|
153
174
|
"uid",
|
154
175
|
"fieldRef",
|
155
176
|
]
|
156
|
-
|
157
|
-
return True
|
158
|
-
return False
|
177
|
+
return val in ignorable_fields
|
159
178
|
|
160
179
|
@staticmethod
|
161
180
|
def ignorable_key_value_pair(key, val):
|
162
181
|
ignorable_key_value_pair = {"annotations": None, "divisor": "0"}
|
163
|
-
|
164
|
-
|
165
|
-
|
182
|
+
return bool(
|
183
|
+
key in ignorable_key_value_pair and ignorable_key_value_pair[key] == val
|
184
|
+
)
|
166
185
|
|
167
186
|
@staticmethod
|
168
187
|
def cpu_equal(val1, val2):
|
169
188
|
# normalize both to string
|
170
|
-
|
189
|
+
with contextlib.suppress(Exception):
|
171
190
|
val1 = f"{int(float(val1) * 1000)}m"
|
172
|
-
|
173
|
-
pass
|
174
|
-
try:
|
191
|
+
with contextlib.suppress(Exception):
|
175
192
|
val2 = f"{int(float(val2) * 1000)}m"
|
176
|
-
except Exception:
|
177
|
-
pass
|
178
193
|
return val1 == val2
|
179
194
|
|
180
195
|
@staticmethod
|
@@ -191,12 +206,20 @@ class OpenshiftResource:
|
|
191
206
|
|
192
207
|
@property
|
193
208
|
def name(self):
|
194
|
-
|
209
|
+
# PipelineRun name can be empty when creating
|
210
|
+
if self.kind == "PipelineRun" and "name" not in self.body["metadata"]:
|
211
|
+
return self.body["metadata"]["generateName"][:-1]
|
212
|
+
else:
|
213
|
+
return self.body["metadata"]["name"]
|
195
214
|
|
196
215
|
@property
|
197
216
|
def kind(self):
|
198
217
|
return self.body["kind"]
|
199
218
|
|
219
|
+
@property
|
220
|
+
def annotations(self):
|
221
|
+
return self.body["metadata"].get("annotations", {})
|
222
|
+
|
200
223
|
@property
|
201
224
|
def kind_and_group(self):
|
202
225
|
return fully_qualified_kind(self.kind, self.body["apiVersion"])
|
@@ -213,20 +236,18 @@ class OpenshiftResource:
|
|
213
236
|
|
214
237
|
def verify_valid_k8s_object(self):
|
215
238
|
try:
|
216
|
-
self.name
|
217
|
-
self.kind
|
239
|
+
assert self.name
|
240
|
+
assert self.kind
|
218
241
|
except (KeyError, TypeError) as e:
|
219
|
-
msg = "resource invalid data ({}). details: {}"
|
220
|
-
|
221
|
-
)
|
222
|
-
raise ConstructResourceError(msg)
|
242
|
+
msg = f"resource invalid data ({e.__class__.__name__}). details: {self.error_details}"
|
243
|
+
raise ConstructResourceError(msg) from None
|
223
244
|
|
224
|
-
if self.kind not in
|
245
|
+
if self.kind not in {
|
225
246
|
"Role",
|
226
247
|
"RoleBinding",
|
227
248
|
"ClusterRole",
|
228
249
|
"ClusterRoleBinding",
|
229
|
-
|
250
|
+
} and (
|
230
251
|
not DNS_SUBDOMAIN_RE.match(self.name)
|
231
252
|
or not len(self.name) <= DNS_SUBDOMAIN_MAX_LENGTH
|
232
253
|
):
|
@@ -283,15 +304,15 @@ class OpenshiftResource:
|
|
283
304
|
try:
|
284
305
|
annotations = self.body["metadata"]["annotations"]
|
285
306
|
|
286
|
-
assert annotations[
|
307
|
+
assert annotations[QONTRACT_ANNOTATION_INTEGRATION] == self.integration
|
287
308
|
|
288
|
-
integration_version = annotations[
|
309
|
+
integration_version = annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION]
|
289
310
|
assert (
|
290
311
|
semver.VersionInfo.parse(integration_version).major
|
291
312
|
== semver.VersionInfo.parse(self.integration_version).major
|
292
313
|
)
|
293
314
|
|
294
|
-
assert annotations[
|
315
|
+
assert annotations[QONTRACT_ANNOTATION_SHA256SUM] is not None
|
295
316
|
except KeyError:
|
296
317
|
return False
|
297
318
|
except AssertionError:
|
@@ -314,7 +335,7 @@ class OpenshiftResource:
|
|
314
335
|
except KeyError:
|
315
336
|
return False
|
316
337
|
|
317
|
-
def annotate(self):
|
338
|
+
def annotate(self, canonicalize=True):
|
318
339
|
"""
|
319
340
|
Creates a OpenshiftResource with the qontract annotations, and removes
|
320
341
|
unneeded Openshift fields.
|
@@ -323,10 +344,9 @@ class OpenshiftResource:
|
|
323
344
|
openshift_resource: new OpenshiftResource object with
|
324
345
|
annotations.
|
325
346
|
"""
|
347
|
+
body = self.canonicalize(self.body) if canonicalize else self.body
|
326
348
|
|
327
|
-
|
328
|
-
canonical_body = self.canonicalize(self.body)
|
329
|
-
sha256sum = self.calculate_sha256sum(self.serialize(canonical_body))
|
349
|
+
sha256sum = self.calculate_sha256sum(self.serialize(body))
|
330
350
|
|
331
351
|
# create new body object
|
332
352
|
body = copy.deepcopy(self.body)
|
@@ -339,13 +359,13 @@ class OpenshiftResource:
|
|
339
359
|
annotations = body["metadata"]["annotations"]
|
340
360
|
|
341
361
|
# add qontract annotations
|
342
|
-
annotations[
|
343
|
-
annotations[
|
344
|
-
annotations[
|
362
|
+
annotations[QONTRACT_ANNOTATION_INTEGRATION] = self.integration
|
363
|
+
annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION] = self.integration_version
|
364
|
+
annotations[QONTRACT_ANNOTATION_SHA256SUM] = sha256sum
|
345
365
|
now = datetime.datetime.utcnow().replace(microsecond=0).isoformat()
|
346
|
-
annotations[
|
366
|
+
annotations[QONTRACT_ANNOTATION_UPDATE] = now
|
347
367
|
if self.caller_name:
|
348
|
-
annotations[
|
368
|
+
annotations[QONTRACT_ANNOTATION_CALLER_NAME] = self.caller_name
|
349
369
|
|
350
370
|
return OpenshiftResource(body, self.integration, self.integration_version)
|
351
371
|
|
@@ -389,7 +409,7 @@ class OpenshiftResource:
|
|
389
409
|
|
390
410
|
# Default fields for specific resource types
|
391
411
|
# ConfigMaps and Secrets are by default Opaque
|
392
|
-
if body["kind"] in
|
412
|
+
if body["kind"] in {"ConfigMap", "Secret"} and body.get("type") == "Opaque":
|
393
413
|
body.pop("type")
|
394
414
|
|
395
415
|
if body["kind"] == "Secret":
|
@@ -397,7 +417,7 @@ class OpenshiftResource:
|
|
397
417
|
if string_data:
|
398
418
|
body.setdefault("data", {})
|
399
419
|
for k, v in string_data.items():
|
400
|
-
v =
|
420
|
+
v = base64_encode_secret_field_value(str(v))
|
401
421
|
body["data"][k] = v
|
402
422
|
|
403
423
|
if body["kind"] == "Deployment":
|
@@ -419,7 +439,7 @@ class OpenshiftResource:
|
|
419
439
|
tls.pop("key", None)
|
420
440
|
tls.pop("certificate", None)
|
421
441
|
subdomain = body["spec"].get("subdomain", None)
|
422
|
-
if subdomain
|
442
|
+
if not subdomain:
|
423
443
|
body["spec"].pop("subdomain", None)
|
424
444
|
|
425
445
|
if body["kind"] == "ServiceAccount":
|
@@ -448,9 +468,6 @@ class OpenshiftResource:
|
|
448
468
|
and not rule["attributeRestrictions"]
|
449
469
|
):
|
450
470
|
rule.pop("attributeRestrictions")
|
451
|
-
# TODO: remove this once we have no 3.11 clusters
|
452
|
-
if body["apiVersion"] == "authorization.openshift.io/v1":
|
453
|
-
body["apiVersion"] = "rbac.authorization.k8s.io/v1"
|
454
471
|
|
455
472
|
if body["kind"] == "OperatorGroup":
|
456
473
|
annotations.pop("olm.providedAPIs", None)
|
@@ -472,18 +489,11 @@ class OpenshiftResource:
|
|
472
489
|
if "namespace" in subject:
|
473
490
|
subject.pop("namespace")
|
474
491
|
if "apiGroup" in subject and (
|
475
|
-
subject["apiGroup"]
|
476
|
-
or subject["apiGroup"] in body["apiVersion"]
|
492
|
+
not subject["apiGroup"] or subject["apiGroup"] in body["apiVersion"]
|
477
493
|
):
|
478
494
|
subject.pop("apiGroup")
|
479
|
-
# TODO: remove this once we have no 3.11 clusters
|
480
|
-
if body["apiVersion"] == "rbac.authorization.k8s.io/v1":
|
481
|
-
body["apiVersion"] = "authorization.openshift.io/v1"
|
482
495
|
|
483
496
|
if body["kind"] == "ClusterRoleBinding":
|
484
|
-
# TODO: remove this once we have no 3.11 clusters
|
485
|
-
if body["apiVersion"] == "authorization.openshift.io/v1":
|
486
|
-
body["apiVersion"] = "rbac.authorization.k8s.io/v1"
|
487
497
|
if "userNames" in body:
|
488
498
|
body.pop("userNames")
|
489
499
|
if "roleRef" in body:
|
@@ -502,12 +512,11 @@ class OpenshiftResource:
|
|
502
512
|
spec.pop("clusterIP", None)
|
503
513
|
|
504
514
|
# remove qontract specific params
|
505
|
-
|
506
|
-
|
507
|
-
annotations.pop("qontract.sha256sum", None)
|
508
|
-
annotations.pop("qontract.update", None)
|
509
|
-
annotations.pop("qontract.caller_name", None)
|
515
|
+
for a in QONTRACT_ANNOTATIONS:
|
516
|
+
annotations.pop(a, None)
|
510
517
|
|
518
|
+
# Remove external resources annotation used for optimistic locking
|
519
|
+
annotations.pop(SECRET_UPDATED_AT, None)
|
511
520
|
return body
|
512
521
|
|
513
522
|
@staticmethod
|
@@ -528,6 +537,25 @@ def fully_qualified_kind(kind: str, api_version: str) -> str:
|
|
528
537
|
return kind
|
529
538
|
|
530
539
|
|
540
|
+
class OpenshiftResourceBaseMetric(BaseModel):
|
541
|
+
"Base class Openshift Resource metrics"
|
542
|
+
|
543
|
+
integration: str
|
544
|
+
|
545
|
+
|
546
|
+
class OpenshiftResourceInventoryGauge(OpenshiftResourceBaseMetric, GaugeMetric):
|
547
|
+
"Inventory Gauge"
|
548
|
+
|
549
|
+
cluster: str
|
550
|
+
namespace: str
|
551
|
+
kind: str
|
552
|
+
state: str
|
553
|
+
|
554
|
+
@classmethod
|
555
|
+
def name(cls) -> str:
|
556
|
+
return "qontract_reconcile_openshift_resource_inventory"
|
557
|
+
|
558
|
+
|
531
559
|
class ResourceInventory:
|
532
560
|
def __init__(self):
|
533
561
|
self._clusters = {}
|
@@ -535,11 +563,23 @@ class ResourceInventory:
|
|
535
563
|
self._error_registered_clusters = {}
|
536
564
|
self._lock = Lock()
|
537
565
|
|
538
|
-
def initialize_resource_type(
|
566
|
+
def initialize_resource_type(
|
567
|
+
self,
|
568
|
+
cluster,
|
569
|
+
namespace,
|
570
|
+
resource_type,
|
571
|
+
managed_names: list[str] | None = None,
|
572
|
+
):
|
539
573
|
self._clusters.setdefault(cluster, {})
|
540
574
|
self._clusters[cluster].setdefault(namespace, {})
|
541
575
|
self._clusters[cluster][namespace].setdefault(
|
542
|
-
resource_type,
|
576
|
+
resource_type,
|
577
|
+
{
|
578
|
+
"current": {},
|
579
|
+
"desired": {},
|
580
|
+
"use_admin_token": {},
|
581
|
+
"managed_names": managed_names,
|
582
|
+
},
|
543
583
|
)
|
544
584
|
|
545
585
|
def is_cluster_present(self, cluster: str) -> bool:
|
@@ -575,6 +615,13 @@ class ResourceInventory:
|
|
575
615
|
# mismatch between schema and implementation for now, it will enable
|
576
616
|
# us to implement per-resource configuration in the future
|
577
617
|
with self._lock:
|
618
|
+
# fail if the name of the resource is not within the managed names if they are defined
|
619
|
+
managed_names = self._clusters[cluster][namespace][resource_type][
|
620
|
+
"managed_names"
|
621
|
+
]
|
622
|
+
if managed_names is not None and name not in managed_names:
|
623
|
+
raise ResourceNotManagedError(name)
|
624
|
+
|
578
625
|
desired = self._clusters[cluster][namespace][resource_type]["desired"]
|
579
626
|
if name in desired:
|
580
627
|
raise ResourceKeyExistsError(name)
|
@@ -630,10 +677,9 @@ def build_secret(
|
|
630
677
|
integration_version: str,
|
631
678
|
unencoded_data: Mapping[str, str],
|
632
679
|
error_details: str = "",
|
633
|
-
caller_name:
|
634
|
-
annotations:
|
680
|
+
caller_name: str | None = None,
|
681
|
+
annotations: Mapping[str, str] | None = None,
|
635
682
|
) -> OpenshiftResource:
|
636
|
-
|
637
683
|
encoded_data = {
|
638
684
|
k: base64_encode_secret_field_value(v) for k, v in unencoded_data.items()
|
639
685
|
}
|
@@ -655,7 +701,7 @@ def build_secret(
|
|
655
701
|
)
|
656
702
|
|
657
703
|
|
658
|
-
def base64_encode_secret_field_value(value: str) ->
|
659
|
-
if value
|
660
|
-
return
|
704
|
+
def base64_encode_secret_field_value(value: str) -> str:
|
705
|
+
if not value:
|
706
|
+
return ""
|
661
707
|
return base64.b64encode(str(value).encode()).decode("utf-8")
|
reconcile/utils/output.py
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
import json
|
2
|
+
import re
|
2
3
|
from collections.abc import (
|
3
4
|
Iterable,
|
4
5
|
Mapping,
|
5
6
|
)
|
6
|
-
from typing import Union
|
7
7
|
|
8
8
|
import yaml
|
9
9
|
from tabulate import tabulate
|
10
10
|
|
11
11
|
|
12
12
|
def print_output(
|
13
|
-
options: Mapping[str,
|
13
|
+
options: Mapping[str, str | bool],
|
14
14
|
content: list[dict],
|
15
15
|
columns: Iterable[str] = (),
|
16
|
-
):
|
16
|
+
) -> str | None:
|
17
17
|
if options["sort"]:
|
18
18
|
content.sort(key=lambda c: tuple(c.values()))
|
19
19
|
if options.get("to_string"):
|
@@ -23,17 +23,26 @@ def print_output(
|
|
23
23
|
|
24
24
|
output = options["output"]
|
25
25
|
|
26
|
+
formatted_content = None
|
26
27
|
if output == "table":
|
27
|
-
|
28
|
+
formatted_content = format_table(content, columns)
|
29
|
+
print(formatted_content)
|
28
30
|
elif output == "md":
|
29
|
-
|
31
|
+
formatted_content = re.sub(
|
32
|
+
r" +", " ", format_table(content, columns, table_format="github")
|
33
|
+
)
|
34
|
+
print(formatted_content)
|
30
35
|
elif output == "json":
|
31
|
-
|
36
|
+
formatted_content = json.dumps(content)
|
37
|
+
print(formatted_content)
|
32
38
|
elif output == "yaml":
|
33
|
-
|
39
|
+
formatted_content = yaml.dump(content)
|
40
|
+
print(formatted_content)
|
34
41
|
else:
|
35
42
|
pass # error
|
36
43
|
|
44
|
+
return formatted_content
|
45
|
+
|
37
46
|
|
38
47
|
def format_table(content, columns, table_format="simple") -> str:
|
39
48
|
headers = [column.upper() for column in columns]
|
@@ -53,10 +62,8 @@ def format_table(content, columns, table_format="simple") -> str:
|
|
53
62
|
cell = "<br />".join(cell)
|
54
63
|
else:
|
55
64
|
cell = "\n".join(cell)
|
65
|
+
if table_format == "github" and isinstance(cell, str):
|
66
|
+
cell = cell.replace("|", "|")
|
56
67
|
row_data.append(cell)
|
57
68
|
table_data.append(row_data)
|
58
69
|
return tabulate(table_data, headers=headers, tablefmt=table_format)
|
59
|
-
|
60
|
-
|
61
|
-
def print_table(content, columns, table_format="simple"):
|
62
|
-
print(format_table(content, columns, table_format))
|
reconcile/utils/pagerduty_api.py
CHANGED
@@ -4,8 +4,8 @@ from collections.abc import (
|
|
4
4
|
Iterable,
|
5
5
|
)
|
6
6
|
from datetime import datetime as dt
|
7
|
+
from datetime import timedelta
|
7
8
|
from typing import (
|
8
|
-
Optional,
|
9
9
|
Protocol,
|
10
10
|
)
|
11
11
|
|
@@ -44,7 +44,7 @@ class PagerDutyUser(Protocol):
|
|
44
44
|
which must be implemented by a class to be compatible."""
|
45
45
|
|
46
46
|
org_username: str
|
47
|
-
pagerduty_username:
|
47
|
+
pagerduty_username: str | None
|
48
48
|
|
49
49
|
|
50
50
|
class PagerDutyTarget(Protocol):
|
@@ -53,8 +53,8 @@ class PagerDutyTarget(Protocol):
|
|
53
53
|
|
54
54
|
name: str
|
55
55
|
instance: PagerDutyInstance
|
56
|
-
escalation_policy_id:
|
57
|
-
schedule_id:
|
56
|
+
escalation_policy_id: str | None
|
57
|
+
schedule_id: str | None
|
58
58
|
|
59
59
|
|
60
60
|
class PagerDutyConfig(BaseModel):
|
@@ -75,7 +75,7 @@ class PagerDutyApi:
|
|
75
75
|
self.users: list[pypd.User] = []
|
76
76
|
|
77
77
|
def init_users(self) -> None:
|
78
|
-
self.users = pypd.User.find()
|
78
|
+
self.users = pypd.User.find(limit=100)
|
79
79
|
|
80
80
|
def get_pagerduty_users(
|
81
81
|
self, resource_type: str, resource_id: str
|
@@ -104,7 +104,8 @@ class PagerDutyApi:
|
|
104
104
|
return user.email.split("@")[0]
|
105
105
|
|
106
106
|
def get_schedule_users(self, schedule_id: str, now: dt) -> list[pypd.User]:
|
107
|
-
|
107
|
+
until = now + timedelta(seconds=60)
|
108
|
+
s = pypd.Schedule.fetch(id=schedule_id, since=now, until=until, time_zone="UTC")
|
108
109
|
entries = s["final_schedule"]["rendered_schedule_entries"]
|
109
110
|
|
110
111
|
return [
|
@@ -164,16 +165,21 @@ class PagerDutyMap:
|
|
164
165
|
|
165
166
|
def get_pagerduty_map(
|
166
167
|
secret_reader: SecretReader,
|
167
|
-
pagerduty_instances: Iterable[PagerDutyInstance],
|
168
|
+
pagerduty_instances: Iterable[PagerDutyInstance] | None,
|
168
169
|
init_users: bool = True,
|
169
170
|
pager_duty_api_class: type[PagerDutyApi] = PagerDutyApi,
|
170
171
|
) -> PagerDutyMap:
|
171
172
|
"""Initiate a PagerDutyMap for given PagerDuty instances."""
|
172
|
-
|
173
|
-
|
173
|
+
instances = (
|
174
|
+
[
|
174
175
|
PagerDutyConfig(name=i.name, token=secret_reader.read_secret(i.token))
|
175
176
|
for i in pagerduty_instances
|
176
|
-
]
|
177
|
+
]
|
178
|
+
if pagerduty_instances
|
179
|
+
else []
|
180
|
+
)
|
181
|
+
return PagerDutyMap(
|
182
|
+
instances=instances,
|
177
183
|
init_users=init_users,
|
178
184
|
pager_duty_api_class=pager_duty_api_class,
|
179
185
|
)
|
@@ -31,6 +31,18 @@ HANDLE_UNIT_MAP = {
|
|
31
31
|
}
|
32
32
|
|
33
33
|
|
34
|
+
def seconds_to_hms(seconds: int) -> str:
|
35
|
+
minutes, s = divmod(seconds, 60)
|
36
|
+
if minutes == 0:
|
37
|
+
return f"{s}s"
|
38
|
+
|
39
|
+
h, m = divmod(minutes, 60)
|
40
|
+
if h == 0:
|
41
|
+
return f"{m}m{s}s"
|
42
|
+
|
43
|
+
return f"{h}h{m}m{s}s"
|
44
|
+
|
45
|
+
|
34
46
|
def dhms_to_seconds(time_str: str) -> int:
|
35
47
|
"""Parses durations and returns seconds. The format is a subset of Go's
|
36
48
|
ParseDuration format, only allowing from days to seconds in resolution,
|
@@ -46,7 +58,7 @@ def dhms_to_seconds(time_str: str) -> int:
|
|
46
58
|
if s.isnumeric():
|
47
59
|
previous_number += s
|
48
60
|
else:
|
49
|
-
if previous_number
|
61
|
+
if not previous_number:
|
50
62
|
raise BadHDMSDurationError(f"Invalid time duration {time_str}")
|
51
63
|
|
52
64
|
if s in HANDLE_UNIT_MAP:
|
@@ -0,0 +1,123 @@
|
|
1
|
+
from typing import NamedTuple, Protocol
|
2
|
+
|
3
|
+
import requests
|
4
|
+
from pydantic import BaseModel, Field
|
5
|
+
|
6
|
+
from reconcile.gql_definitions.fragments.prometheus_instance import (
|
7
|
+
PrometheusInstance,
|
8
|
+
PrometheusInstanceBearerAuthV1,
|
9
|
+
PrometheusInstanceOidcAuthV1,
|
10
|
+
)
|
11
|
+
from reconcile.utils.secret_reader import SecretReaderBase
|
12
|
+
|
13
|
+
INSTANT_VECTOR_RESULT_TYPE = "vector"
|
14
|
+
|
15
|
+
|
16
|
+
class PrometheusQueryError(Exception):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
class PrometheusValue(NamedTuple):
|
21
|
+
timestamp: float
|
22
|
+
value: float
|
23
|
+
|
24
|
+
|
25
|
+
class PrometheusVector(BaseModel):
|
26
|
+
metric: dict[str, str]
|
27
|
+
raw_value: PrometheusValue = Field(..., alias="value")
|
28
|
+
|
29
|
+
@property
|
30
|
+
def name(self) -> str:
|
31
|
+
return self.metric["__name__"]
|
32
|
+
|
33
|
+
@property
|
34
|
+
def timestamp(self) -> float:
|
35
|
+
return self.raw_value[0]
|
36
|
+
|
37
|
+
@property
|
38
|
+
def value(self) -> float:
|
39
|
+
return self.raw_value[1]
|
40
|
+
|
41
|
+
def mandatory_label(self, label_name: str) -> str:
|
42
|
+
return self.metric[label_name]
|
43
|
+
|
44
|
+
def label(self, label_name: str, default: str | None = None) -> str | None:
|
45
|
+
return self.metric.get(label_name, default)
|
46
|
+
|
47
|
+
|
48
|
+
class PrometheusQuerier(Protocol):
|
49
|
+
"""
|
50
|
+
A protocol for a querier of Prometheus.
|
51
|
+
"""
|
52
|
+
|
53
|
+
def instant_vector_query(self, query: str) -> list[PrometheusVector]:
|
54
|
+
"""
|
55
|
+
Query for instant vectors.
|
56
|
+
"""
|
57
|
+
|
58
|
+
|
59
|
+
class PrometheusHttpQuerier(BaseModel):
|
60
|
+
query_url: str
|
61
|
+
auth_token: str
|
62
|
+
|
63
|
+
def instant_vector_query(self, query: str) -> list[PrometheusVector]:
|
64
|
+
response = requests.get(
|
65
|
+
self.query_url,
|
66
|
+
params={"query": query},
|
67
|
+
headers={
|
68
|
+
"Authorization": f"Bearer {self.auth_token}",
|
69
|
+
},
|
70
|
+
)
|
71
|
+
|
72
|
+
response.raise_for_status()
|
73
|
+
|
74
|
+
# Parse the response JSON
|
75
|
+
try:
|
76
|
+
parsed = response.json()
|
77
|
+
except Exception as e:
|
78
|
+
raise PrometheusQueryError(
|
79
|
+
f"Query failed with invalid JSON response: {response.text[:100]}..."
|
80
|
+
) from e
|
81
|
+
if parsed.get("status") != "success":
|
82
|
+
raise PrometheusQueryError(
|
83
|
+
f"Query response status was not `success`but {parsed.get('status')}"
|
84
|
+
)
|
85
|
+
if "data" not in parsed:
|
86
|
+
raise PrometheusQueryError(
|
87
|
+
f"Query response does not contain `data`: {response.text[:100]}..."
|
88
|
+
)
|
89
|
+
result_type = parsed.get("data", {}).get("resultType")
|
90
|
+
if result_type != INSTANT_VECTOR_RESULT_TYPE:
|
91
|
+
raise PrometheusQueryError(
|
92
|
+
f"Query failed with unexpected result type. Expected {INSTANT_VECTOR_RESULT_TYPE} got {result_type}"
|
93
|
+
)
|
94
|
+
return [PrometheusVector(**m) for m in parsed["data"]["result"]]
|
95
|
+
|
96
|
+
|
97
|
+
def init_prometheus_http_querier_from_prometheus_instance(
|
98
|
+
prometheus: PrometheusInstance, secret_reader: SecretReaderBase
|
99
|
+
) -> PrometheusHttpQuerier:
|
100
|
+
match prometheus.auth:
|
101
|
+
case PrometheusInstanceBearerAuthV1():
|
102
|
+
auth_token = secret_reader.read_secret(prometheus.auth.token)
|
103
|
+
case PrometheusInstanceOidcAuthV1():
|
104
|
+
client_secret = secret_reader.read_secret(
|
105
|
+
prometheus.auth.access_token_client_secret
|
106
|
+
)
|
107
|
+
data = {
|
108
|
+
"grant_type": "client_credentials",
|
109
|
+
"client_id": prometheus.auth.access_token_client_id,
|
110
|
+
"client_secret": client_secret,
|
111
|
+
}
|
112
|
+
response = requests.post(
|
113
|
+
prometheus.auth.access_token_url, data=data, timeout=15
|
114
|
+
)
|
115
|
+
response.raise_for_status()
|
116
|
+
auth_token = response.json().get("access_token")
|
117
|
+
case _:
|
118
|
+
raise Exception(f"Unsupported auth type: {prometheus.auth.provider}")
|
119
|
+
|
120
|
+
return PrometheusHttpQuerier(
|
121
|
+
query_url=f"{prometheus.base_url}/{prometheus.query_path}",
|
122
|
+
auth_token=auth_token,
|
123
|
+
)
|