qontract-reconcile 0.10.2.dev299__py3-none-any.whl → 0.10.2.dev430__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/METADATA +13 -12
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/RECORD +399 -394
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +18 -12
- reconcile/aus/base.py +134 -32
- reconcile/aus/cluster_version_data.py +15 -5
- reconcile/aus/models.py +3 -1
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
- reconcile/aus/ocm_upgrade_scheduler.py +8 -1
- reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
- reconcile/aus/version_gates/sts_version_gate_handler.py +54 -1
- reconcile/automated_actions/config/integration.py +16 -4
- reconcile/aws_account_manager/integration.py +8 -8
- reconcile/aws_account_manager/reconciler.py +3 -3
- reconcile/aws_ami_cleanup/integration.py +8 -12
- reconcile/aws_ami_share.py +69 -62
- reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
- reconcile/aws_ecr_image_pull_secrets.py +4 -4
- reconcile/aws_iam_keys.py +1 -0
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +32 -25
- reconcile/aws_version_sync/integration.py +125 -84
- reconcile/change_owners/bundle.py +3 -3
- reconcile/change_owners/change_log_tracking.py +3 -2
- reconcile/change_owners/change_owners.py +1 -1
- reconcile/change_owners/diff.py +2 -4
- reconcile/checkpoint.py +12 -4
- reconcile/cli.py +111 -18
- reconcile/cluster_deployment_mapper.py +2 -3
- reconcile/dashdotdb_dora.py +5 -12
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +125 -121
- reconcile/deadmanssnitch.py +1 -5
- reconcile/dynatrace_token_provider/integration.py +1 -1
- reconcile/endpoints_discovery/integration.py +4 -1
- reconcile/endpoints_discovery/merge_request.py +1 -1
- reconcile/endpoints_discovery/merge_request_manager.py +9 -11
- reconcile/external_resources/factories.py +5 -12
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +8 -5
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +20 -20
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +8 -11
- reconcile/external_resources/state.py +26 -16
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gabi_authorized_users.py +8 -5
- reconcile/gcp_image_mirror.py +2 -2
- reconcile/github_org.py +1 -1
- reconcile/github_owners.py +4 -0
- reconcile/gitlab_housekeeping.py +13 -15
- reconcile/gitlab_members.py +6 -12
- reconcile/gitlab_mr_sqs_consumer.py +2 -2
- reconcile/gitlab_owners.py +15 -11
- reconcile/gitlab_permissions.py +8 -12
- reconcile/glitchtip_project_alerts/integration.py +3 -1
- reconcile/gql_definitions/acs/acs_instances.py +10 -10
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +6 -6
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +32 -32
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +26 -26
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +6 -7
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
- reconcile/gql_definitions/automated_actions/instance.py +51 -12
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +11 -11
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +28 -68
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +10 -10
- reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
- reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +9 -9
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +18 -18
- reconcile/gql_definitions/common/alerting_services_settings.py +9 -9
- reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
- reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
- reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_roles.py +120 -0
- reconcile/gql_definitions/common/app_interface_state_settings.py +10 -10
- reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
- reconcile/gql_definitions/common/apps.py +5 -5
- reconcile/gql_definitions/common/aws_vpc_requests.py +23 -10
- reconcile/gql_definitions/common/aws_vpcs.py +11 -11
- reconcile/gql_definitions/common/clusters.py +37 -35
- reconcile/gql_definitions/common/clusters_minimal.py +14 -14
- reconcile/gql_definitions/common/clusters_with_dms.py +6 -6
- reconcile/gql_definitions/common/clusters_with_peering.py +29 -30
- reconcile/gql_definitions/common/github_orgs.py +10 -10
- reconcile/gql_definitions/common/jira_settings.py +10 -10
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +42 -44
- reconcile/gql_definitions/common/namespaces_minimal.py +15 -13
- reconcile/gql_definitions/common/ocm_env_telemeter.py +12 -12
- reconcile/gql_definitions/common/ocm_environments.py +19 -19
- reconcile/gql_definitions/common/pagerduty_instances.py +9 -9
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +6 -6
- reconcile/gql_definitions/common/pipeline_providers.py +29 -29
- reconcile/gql_definitions/common/quay_instances.py +5 -5
- reconcile/gql_definitions/common/quay_orgs.py +5 -5
- reconcile/gql_definitions/common/reserved_networks.py +5 -5
- reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
- reconcile/gql_definitions/common/saas_files.py +44 -44
- reconcile/gql_definitions/common/saas_target_namespaces.py +10 -10
- reconcile/gql_definitions/common/saasherder_settings.py +5 -5
- reconcile/gql_definitions/common/slack_workspaces.py +5 -5
- reconcile/gql_definitions/common/smtp_client_settings.py +19 -19
- reconcile/gql_definitions/common/state_aws_account.py +7 -8
- reconcile/gql_definitions/common/users.py +5 -5
- reconcile/gql_definitions/common/users_with_paths.py +5 -5
- reconcile/gql_definitions/cost_report/app_names.py +5 -5
- reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
- reconcile/gql_definitions/cost_report/settings.py +9 -9
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +43 -43
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +10 -10
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
- reconcile/gql_definitions/email_sender/apps.py +5 -5
- reconcile/gql_definitions/email_sender/emails.py +8 -8
- reconcile/gql_definitions/email_sender/users.py +6 -6
- reconcile/gql_definitions/endpoints_discovery/apps.py +10 -10
- reconcile/gql_definitions/external_resources/aws_accounts.py +9 -9
- reconcile/gql_definitions/external_resources/external_resources_modules.py +23 -23
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +492 -410
- reconcile/gql_definitions/external_resources/external_resources_settings.py +28 -26
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +40 -40
- reconcile/gql_definitions/fragments/aus_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
- reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
- reconcile/gql_definitions/fragments/{aws_vpc_request_subnet.py → aws_organization.py} +12 -8
- reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc_request.py +10 -5
- reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
- reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
- reconcile/gql_definitions/fragments/disable.py +5 -5
- reconcile/gql_definitions/fragments/email_service.py +5 -5
- reconcile/gql_definitions/fragments/email_user.py +5 -5
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
- reconcile/gql_definitions/fragments/membership_source.py +5 -5
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
- reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_values.py +5 -5
- reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
- reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
- reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
- reconcile/gql_definitions/fragments/terraform_state.py +5 -5
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
- reconcile/gql_definitions/fragments/user.py +5 -5
- reconcile/gql_definitions/fragments/vault_secret.py +5 -5
- reconcile/gql_definitions/gcp/gcp_docker_repos.py +9 -9
- reconcile/gql_definitions/gcp/gcp_projects.py +9 -9
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +9 -9
- reconcile/gql_definitions/gitlab_members/permissions.py +9 -9
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +9 -9
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +11 -11
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +9 -9
- reconcile/gql_definitions/integrations/integrations.py +48 -51
- reconcile/gql_definitions/introspection.json +3050 -1393
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +11 -11
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +10 -10
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +14 -10
- reconcile/gql_definitions/jumphosts/jumphosts.py +13 -13
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +9 -9
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +18 -19
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +22 -22
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +6 -6
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +10 -10
- reconcile/gql_definitions/quay_membership/quay_membership.py +6 -6
- reconcile/gql_definitions/rhcs/certs.py +33 -87
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
- reconcile/gql_definitions/rhidp/organizations.py +18 -18
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +8 -8
- reconcile/gql_definitions/sharding/aws_accounts.py +10 -10
- reconcile/gql_definitions/sharding/ocm_organization.py +8 -8
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +10 -10
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +9 -9
- reconcile/gql_definitions/slack_usergroups/users.py +5 -5
- reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
- reconcile/gql_definitions/status_board/status_board.py +6 -7
- reconcile/gql_definitions/statuspage/statuspages.py +9 -9
- reconcile/gql_definitions/templating/template_collection.py +5 -5
- reconcile/gql_definitions/templating/templates.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +6 -6
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +11 -11
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +11 -11
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +20 -25
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +6 -6
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +12 -12
- reconcile/gql_definitions/terraform_init/aws_accounts.py +23 -9
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +9 -9
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +448 -402
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +23 -17
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +9 -9
- reconcile/gql_definitions/vault_instances/vault_instances.py +61 -61
- reconcile/gql_definitions/vault_policies/vault_policies.py +11 -11
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +8 -8
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_job_builder.py +1 -1
- reconcile/jenkins_worker_fleets.py +80 -11
- reconcile/jira_permissions_validator.py +237 -122
- reconcile/ldap_groups/integration.py +1 -1
- reconcile/ocm/types.py +35 -56
- reconcile/ocm_aws_infrastructure_access.py +1 -1
- reconcile/ocm_clusters.py +4 -4
- reconcile/ocm_labels/integration.py +3 -2
- reconcile/ocm_machine_pools.py +33 -27
- reconcile/openshift_base.py +122 -10
- reconcile/openshift_cluster_bots.py +5 -5
- reconcile/openshift_groups.py +5 -0
- reconcile/openshift_limitranges.py +1 -1
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +10 -5
- reconcile/openshift_rhcs_certs.py +77 -40
- reconcile/openshift_rolebindings.py +230 -130
- reconcile/openshift_saas_deploy.py +6 -7
- reconcile/openshift_saas_deploy_change_tester.py +9 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
- reconcile/openshift_serviceaccount_tokens.py +8 -7
- reconcile/openshift_tekton_resources.py +1 -1
- reconcile/openshift_upgrade_watcher.py +4 -4
- reconcile/openshift_users.py +5 -3
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/oum/providers.py +1 -1
- reconcile/prometheus_rules_tester/integration.py +4 -4
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +131 -0
- reconcile/requests_sender.py +8 -3
- reconcile/resource_scraper.py +1 -5
- reconcile/rhidp/common.py +5 -5
- reconcile/rhidp/sso_client/base.py +19 -10
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
- reconcile/sendgrid_teammates.py +20 -9
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +35 -14
- reconcile/sql_query.py +1 -0
- reconcile/status.py +2 -2
- reconcile/status_board.py +6 -6
- reconcile/statuspage/atlassian.py +7 -7
- reconcile/statuspage/integrations/maintenances.py +4 -3
- reconcile/statuspage/page.py +4 -9
- reconcile/statuspage/status.py +5 -8
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +4 -0
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
- reconcile/templating/lib/merge_request_manager.py +2 -2
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +12 -13
- reconcile/terraform_aws_route53.py +18 -8
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +12 -13
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +187 -23
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +18 -10
- reconcile/terraform_tgw_attachments.py +27 -19
- reconcile/terraform_users.py +29 -21
- reconcile/terraform_vpc_peerings.py +16 -4
- reconcile/terraform_vpc_resources/integration.py +32 -2
- reconcile/typed_queries/app_interface_roles.py +10 -0
- reconcile/typed_queries/aws_account_tags.py +41 -0
- reconcile/typed_queries/cost_report/app_names.py +1 -1
- reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
- reconcile/typed_queries/saas_files.py +13 -13
- reconcile/typed_queries/status_board.py +2 -2
- reconcile/unleash_feature_toggles/integration.py +4 -2
- reconcile/utils/acs/base.py +6 -3
- reconcile/utils/acs/policies.py +2 -2
- reconcile/utils/aggregated_list.py +4 -3
- reconcile/utils/aws_api.py +51 -20
- reconcile/utils/aws_api_typed/api.py +38 -9
- reconcile/utils/aws_api_typed/cloudformation.py +149 -0
- reconcile/utils/aws_api_typed/logs.py +73 -0
- reconcile/utils/aws_api_typed/organization.py +4 -2
- reconcile/utils/binary.py +7 -12
- reconcile/utils/datetime_util.py +67 -0
- reconcile/utils/deadmanssnitch_api.py +1 -1
- reconcile/utils/differ.py +2 -3
- reconcile/utils/early_exit_cache.py +11 -12
- reconcile/utils/expiration.py +7 -3
- reconcile/utils/external_resource_spec.py +24 -1
- reconcile/utils/filtering.py +1 -1
- reconcile/utils/gitlab_api.py +7 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gpg.py +5 -3
- reconcile/utils/gql.py +4 -7
- reconcile/utils/helm.py +2 -1
- reconcile/utils/helpers.py +1 -1
- reconcile/utils/imap_client.py +1 -1
- reconcile/utils/instrumented_wrappers.py +1 -1
- reconcile/utils/internal_groups/client.py +2 -2
- reconcile/utils/internal_groups/models.py +8 -17
- reconcile/utils/jenkins_api.py +24 -1
- reconcile/utils/jinja2/utils.py +6 -8
- reconcile/utils/jira_client.py +82 -63
- reconcile/utils/jjb_client.py +59 -43
- reconcile/utils/jobcontroller/controller.py +2 -2
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +74 -0
- reconcile/utils/ldap_client.py +4 -3
- reconcile/utils/lean_terraform_client.py +3 -1
- reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
- reconcile/utils/membershipsources/models.py +16 -23
- reconcile/utils/membershipsources/resolver.py +4 -2
- reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
- reconcile/utils/merge_request_manager/parser.py +6 -6
- reconcile/utils/metrics.py +5 -5
- reconcile/utils/models.py +304 -82
- reconcile/utils/mr/__init__.py +3 -1
- reconcile/utils/mr/app_interface_reporter.py +6 -3
- reconcile/utils/mr/aws_access.py +1 -1
- reconcile/utils/mr/base.py +7 -13
- reconcile/utils/mr/clusters_updates.py +4 -2
- reconcile/utils/mr/notificator.py +3 -3
- reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +4 -1
- reconcile/utils/mr/promote_qontract.py +28 -12
- reconcile/utils/mr/update_access_report_base.py +3 -4
- reconcile/utils/mr/user_maintenance.py +7 -6
- reconcile/utils/oc.py +445 -336
- reconcile/utils/oc_filters.py +3 -3
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +27 -20
- reconcile/utils/ocm/cluster_groups.py +1 -1
- reconcile/utils/ocm/identity_providers.py +2 -2
- reconcile/utils/ocm/labels.py +1 -1
- reconcile/utils/ocm/ocm.py +81 -71
- reconcile/utils/ocm/products.py +9 -3
- reconcile/utils/ocm/search_filters.py +3 -6
- reconcile/utils/ocm/service_log.py +4 -6
- reconcile/utils/ocm/sre_capability_labels.py +20 -13
- reconcile/utils/ocm_base_client.py +4 -4
- reconcile/utils/openshift_resource.py +83 -52
- reconcile/utils/openssl.py +2 -2
- reconcile/utils/output.py +3 -2
- reconcile/utils/pagerduty_api.py +10 -7
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/raw_github_api.py +11 -8
- reconcile/utils/repo_owners.py +21 -29
- reconcile/utils/rhcsv2_certs.py +138 -35
- reconcile/utils/rosa/session.py +16 -0
- reconcile/utils/runtime/integration.py +2 -3
- reconcile/utils/runtime/meta.py +2 -1
- reconcile/utils/runtime/runner.py +2 -2
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +25 -21
- reconcile/utils/saasherder/saasherder.py +60 -32
- reconcile/utils/secret_reader.py +6 -6
- reconcile/utils/sharding.py +1 -1
- reconcile/utils/slack_api.py +26 -4
- reconcile/utils/sloth.py +224 -0
- reconcile/utils/sqs_gateway.py +16 -11
- reconcile/utils/state.py +2 -1
- reconcile/utils/structs.py +4 -4
- reconcile/utils/terraform_client.py +32 -29
- reconcile/utils/terrascript_aws_client.py +658 -480
- reconcile/utils/three_way_diff_strategy.py +1 -1
- reconcile/utils/throughput.py +1 -1
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +44 -41
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +119 -58
- reconcile/vpc_peerings_validator.py +2 -2
- tools/app_interface_reporter.py +4 -4
- tools/cli_commands/cost_report/cost_management_api.py +3 -3
- tools/cli_commands/cost_report/view.py +7 -6
- tools/cli_commands/erv2.py +1 -1
- tools/cli_commands/gpg_encrypt.py +4 -1
- tools/cli_commands/systems_and_tools.py +5 -1
- tools/qontract_cli.py +36 -21
- tools/sre_checkpoints/util.py +5 -3
- tools/template_validation.py +3 -1
- reconcile/gql_definitions/ocm_oidc_idp/__init__.py +0 -0
- reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
- reconcile/jenkins/__init__.py +0 -0
- reconcile/jenkins/types.py +0 -77
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/entry_points.txt +0 -0
|
@@ -1,58 +1,209 @@
|
|
|
1
|
-
import contextlib
|
|
2
1
|
import sys
|
|
3
|
-
from collections.abc import Callable
|
|
4
|
-
from
|
|
2
|
+
from collections.abc import Callable
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Self
|
|
5
|
+
|
|
6
|
+
from pydantic.main import BaseModel
|
|
5
7
|
|
|
6
8
|
import reconcile.openshift_base as ob
|
|
7
|
-
from reconcile import
|
|
9
|
+
from reconcile.gql_definitions.common.app_interface_roles import (
|
|
10
|
+
AccessV1,
|
|
11
|
+
BotV1,
|
|
12
|
+
ClusterV1,
|
|
13
|
+
NamespaceV1,
|
|
14
|
+
RoleV1,
|
|
15
|
+
UserV1,
|
|
16
|
+
)
|
|
17
|
+
from reconcile.gql_definitions.common.namespaces import NamespaceV1 as CommonNamespaceV1
|
|
18
|
+
from reconcile.typed_queries.app_interface_roles import get_app_interface_roles
|
|
19
|
+
from reconcile.typed_queries.namespaces import get_namespaces
|
|
8
20
|
from reconcile.utils import (
|
|
9
21
|
expiration,
|
|
10
|
-
gql,
|
|
11
22
|
)
|
|
12
23
|
from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
|
|
13
24
|
from reconcile.utils.defer import defer
|
|
14
25
|
from reconcile.utils.openshift_resource import OpenshiftResource as OR
|
|
15
26
|
from reconcile.utils.openshift_resource import (
|
|
16
27
|
ResourceInventory,
|
|
17
|
-
ResourceKeyExistsError,
|
|
18
28
|
)
|
|
19
29
|
from reconcile.utils.semver_helper import make_semver
|
|
20
30
|
from reconcile.utils.sharding import is_in_shard
|
|
21
31
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
QONTRACT_INTEGRATION = "openshift-rolebindings"
|
|
33
|
+
QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OCResource(BaseModel, arbitrary_types_allowed=True):
|
|
37
|
+
resource: OR
|
|
38
|
+
resource_name: str
|
|
39
|
+
privileged: bool
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class ServiceAccountSpec:
|
|
44
|
+
sa_namespace_name: str
|
|
45
|
+
sa_name: str
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def create_sa_spec(cls, bots: list[BotV1] | None) -> list[Self]:
|
|
49
|
+
return [
|
|
50
|
+
cls(
|
|
51
|
+
sa_namespace_name=full_service_account[0],
|
|
52
|
+
sa_name=full_service_account[1],
|
|
53
|
+
)
|
|
54
|
+
for bot in bots or []
|
|
55
|
+
if bot.openshift_serviceaccount
|
|
56
|
+
and (full_service_account := bot.openshift_serviceaccount.split("/"))
|
|
57
|
+
and len(full_service_account) == 2
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RoleBindingSpec(BaseModel, validate_by_alias=True, arbitrary_types_allowed=True):
|
|
62
|
+
role_name: str
|
|
63
|
+
role_kind: str
|
|
64
|
+
namespace: NamespaceV1
|
|
65
|
+
cluster: ClusterV1
|
|
66
|
+
privileged: bool
|
|
67
|
+
usernames: set[str]
|
|
68
|
+
openshift_service_accounts: list[ServiceAccountSpec]
|
|
69
|
+
|
|
70
|
+
def get_users_desired_state(self) -> list[dict[str, str]]:
|
|
71
|
+
return [
|
|
72
|
+
{"cluster": self.cluster.name, "user": username}
|
|
73
|
+
for username in self.usernames
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def create_role_binding_spec(
|
|
78
|
+
cls,
|
|
79
|
+
access: AccessV1,
|
|
80
|
+
users: list[UserV1] | None = None,
|
|
81
|
+
enforced_user_keys: list[str] | None = None,
|
|
82
|
+
bots: list[BotV1] | None = None,
|
|
83
|
+
support_role_ref: bool = False,
|
|
84
|
+
) -> Self | None:
|
|
85
|
+
if not access.namespace:
|
|
86
|
+
return None
|
|
87
|
+
if not (access.role or access.cluster_role):
|
|
88
|
+
return None
|
|
89
|
+
privileged = access.namespace.cluster_admin or False
|
|
90
|
+
auth_dict = [
|
|
91
|
+
auth.model_dump(by_alias=True) for auth in access.namespace.cluster.auth
|
|
92
|
+
]
|
|
93
|
+
usernames = RoleBindingSpec.get_usernames_from_users(
|
|
94
|
+
users,
|
|
95
|
+
ob.determine_user_keys_for_access(
|
|
96
|
+
access.namespace.cluster.name,
|
|
97
|
+
auth_dict,
|
|
98
|
+
enforced_user_keys,
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
service_accounts = ServiceAccountSpec.create_sa_spec(bots) if bots else []
|
|
102
|
+
role_kind = "Role" if access.role and support_role_ref else "ClusterRole"
|
|
103
|
+
return cls(
|
|
104
|
+
role_name=access.role or access.cluster_role,
|
|
105
|
+
role_kind=role_kind,
|
|
106
|
+
namespace=access.namespace,
|
|
107
|
+
cluster=access.namespace.cluster,
|
|
108
|
+
privileged=privileged,
|
|
109
|
+
usernames=usernames,
|
|
110
|
+
openshift_service_accounts=service_accounts,
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
@classmethod
|
|
114
|
+
def create_rb_specs_from_role(
|
|
115
|
+
cls,
|
|
116
|
+
role: RoleV1,
|
|
117
|
+
enforced_user_keys: list[str] | None = None,
|
|
118
|
+
support_role_ref: bool = False,
|
|
119
|
+
) -> list[Self]:
|
|
120
|
+
rolebinding_spec_list = [
|
|
121
|
+
role_binding_spec
|
|
122
|
+
for access in role.access or []
|
|
123
|
+
if (
|
|
124
|
+
access.namespace
|
|
125
|
+
and is_valid_namespace(access.namespace)
|
|
126
|
+
and (
|
|
127
|
+
role_binding_spec := cls.create_role_binding_spec(
|
|
128
|
+
access,
|
|
129
|
+
role.users,
|
|
130
|
+
enforced_user_keys,
|
|
131
|
+
role.bots,
|
|
132
|
+
support_role_ref,
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
]
|
|
137
|
+
return rolebinding_spec_list
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def get_usernames_from_users(
|
|
141
|
+
users: list[UserV1] | None = None, user_keys: list[str] | None = None
|
|
142
|
+
) -> set[str]:
|
|
143
|
+
return {
|
|
144
|
+
name
|
|
145
|
+
for user in users or []
|
|
146
|
+
for user_key in user_keys or []
|
|
147
|
+
if (name := getattr(user, user_key, None))
|
|
44
148
|
}
|
|
45
|
-
}
|
|
46
|
-
role
|
|
47
|
-
}
|
|
48
|
-
expirationDate
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
"""
|
|
52
149
|
|
|
150
|
+
def construct_user_oc_resource(self, user: str) -> OCResource:
|
|
151
|
+
name = f"{self.role_name}-{user}"
|
|
152
|
+
body: dict[str, Any] = {
|
|
153
|
+
"apiVersion": "rbac.authorization.k8s.io/v1",
|
|
154
|
+
"kind": "RoleBinding",
|
|
155
|
+
"metadata": {"name": name},
|
|
156
|
+
"roleRef": {"kind": self.role_kind, "name": self.role_name},
|
|
157
|
+
"subjects": [{"kind": "User", "name": user}],
|
|
158
|
+
}
|
|
159
|
+
return OCResource(
|
|
160
|
+
resource=OR(
|
|
161
|
+
body,
|
|
162
|
+
QONTRACT_INTEGRATION,
|
|
163
|
+
QONTRACT_INTEGRATION_VERSION,
|
|
164
|
+
error_details=name,
|
|
165
|
+
),
|
|
166
|
+
resource_name=name,
|
|
167
|
+
privileged=self.privileged,
|
|
168
|
+
)
|
|
53
169
|
|
|
54
|
-
|
|
55
|
-
|
|
170
|
+
def get_oc_resources(self) -> list[OCResource]:
|
|
171
|
+
user_oc_resources = [
|
|
172
|
+
self.construct_user_oc_resource(username) for username in self.usernames
|
|
173
|
+
]
|
|
174
|
+
sa_oc_resources = [
|
|
175
|
+
self.construct_sa_oc_resource(sa.sa_namespace_name, sa.sa_name)
|
|
176
|
+
for sa in self.openshift_service_accounts
|
|
177
|
+
]
|
|
178
|
+
return user_oc_resources + sa_oc_resources
|
|
179
|
+
|
|
180
|
+
def construct_sa_oc_resource(
|
|
181
|
+
self, sa_namespace_name: str, sa_name: str
|
|
182
|
+
) -> OCResource:
|
|
183
|
+
name = f"{self.role_name}-{sa_namespace_name}-{sa_name}"
|
|
184
|
+
body: dict[str, Any] = {
|
|
185
|
+
"apiVersion": "rbac.authorization.k8s.io/v1",
|
|
186
|
+
"kind": "RoleBinding",
|
|
187
|
+
"metadata": {"name": name},
|
|
188
|
+
"roleRef": {"kind": self.role_kind, "name": self.role_name},
|
|
189
|
+
"subjects": [
|
|
190
|
+
{
|
|
191
|
+
"kind": "ServiceAccount",
|
|
192
|
+
"name": sa_name,
|
|
193
|
+
"namespace": sa_namespace_name,
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
}
|
|
197
|
+
return OCResource(
|
|
198
|
+
resource=OR(
|
|
199
|
+
body,
|
|
200
|
+
QONTRACT_INTEGRATION,
|
|
201
|
+
QONTRACT_INTEGRATION_VERSION,
|
|
202
|
+
error_details=name,
|
|
203
|
+
),
|
|
204
|
+
resource_name=name,
|
|
205
|
+
privileged=self.privileged,
|
|
206
|
+
)
|
|
56
207
|
|
|
57
208
|
|
|
58
209
|
def construct_user_oc_resource(role: str, user: str) -> tuple[OR, str]:
|
|
@@ -93,116 +244,65 @@ def construct_sa_oc_resource(role: str, namespace: str, sa_name: str) -> tuple[O
|
|
|
93
244
|
|
|
94
245
|
def fetch_desired_state(
|
|
95
246
|
ri: ResourceInventory | None,
|
|
96
|
-
|
|
247
|
+
support_role_ref: bool = False,
|
|
97
248
|
enforced_user_keys: list[str] | None = None,
|
|
249
|
+
allowed_clusters: set[str] | None = None,
|
|
98
250
|
) -> list[dict[str, str]]:
|
|
99
|
-
|
|
100
|
-
roles_query_result = gqlapi.query(ROLES_QUERY)
|
|
101
|
-
if not roles_query_result:
|
|
251
|
+
if allowed_clusters is not None and not allowed_clusters:
|
|
102
252
|
return []
|
|
103
|
-
roles:
|
|
104
|
-
users_desired_state = []
|
|
253
|
+
roles: list[RoleV1] = expiration.filter(get_app_interface_roles())
|
|
254
|
+
users_desired_state: list[dict[str, str]] = []
|
|
105
255
|
for role in roles:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if not permissions:
|
|
119
|
-
continue
|
|
120
|
-
|
|
121
|
-
service_accounts = [
|
|
122
|
-
bot["openshift_serviceaccount"]
|
|
123
|
-
for bot in role["bots"]
|
|
124
|
-
if bot.get("openshift_serviceaccount")
|
|
125
|
-
]
|
|
126
|
-
|
|
127
|
-
for permission in permissions:
|
|
128
|
-
cluster_info = permission["cluster"]
|
|
129
|
-
cluster = cluster_info["name"]
|
|
130
|
-
namespace_info = permission["namespace"]
|
|
131
|
-
perm_namespace_name = namespace_info["name"]
|
|
132
|
-
privileged = namespace_info.get("clusterAdmin") or False
|
|
133
|
-
if not is_in_shard(f"{cluster}/{perm_namespace_name}"):
|
|
134
|
-
continue
|
|
135
|
-
if oc_map and not oc_map.get(cluster):
|
|
256
|
+
rolebindings: list[RoleBindingSpec] = RoleBindingSpec.create_rb_specs_from_role(
|
|
257
|
+
role, enforced_user_keys, support_role_ref
|
|
258
|
+
)
|
|
259
|
+
if allowed_clusters is not None:
|
|
260
|
+
rolebindings = [
|
|
261
|
+
rolebinding
|
|
262
|
+
for rolebinding in rolebindings
|
|
263
|
+
if rolebinding.cluster.name in allowed_clusters
|
|
264
|
+
]
|
|
265
|
+
for rolebinding in rolebindings:
|
|
266
|
+
users_desired_state.extend(rolebinding.get_users_desired_state())
|
|
267
|
+
if ri is None:
|
|
136
268
|
continue
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
# used by openshift-users and github integrations
|
|
150
|
-
# this is just to simplify things a bit on the their side
|
|
151
|
-
users_desired_state.append({"cluster": cluster, "user": username})
|
|
152
|
-
if ri is None:
|
|
153
|
-
continue
|
|
154
|
-
oc_resource, resource_name = construct_user_oc_resource(
|
|
155
|
-
permission["role"], username
|
|
156
|
-
)
|
|
157
|
-
with contextlib.suppress(ResourceKeyExistsError):
|
|
158
|
-
# a user may have a Role assigned to them
|
|
159
|
-
# from multiple app-interface roles
|
|
160
|
-
ri.add_desired(
|
|
161
|
-
cluster,
|
|
162
|
-
perm_namespace_name,
|
|
163
|
-
"RoleBinding.rbac.authorization.k8s.io",
|
|
164
|
-
resource_name,
|
|
165
|
-
oc_resource,
|
|
166
|
-
privileged=privileged,
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
for sa in service_accounts:
|
|
170
|
-
if ri is None:
|
|
171
|
-
continue
|
|
172
|
-
sa_namespace_name, sa_name = sa.split("/")
|
|
173
|
-
oc_resource, resource_name = construct_sa_oc_resource(
|
|
174
|
-
permission["role"], sa_namespace_name, sa_name
|
|
175
|
-
)
|
|
176
|
-
with contextlib.suppress(ResourceKeyExistsError):
|
|
177
|
-
# a ServiceAccount may have a Role assigned to it
|
|
178
|
-
# from multiple app-interface roles
|
|
179
|
-
ri.add_desired(
|
|
180
|
-
cluster,
|
|
181
|
-
perm_namespace_name,
|
|
182
|
-
"RoleBinding.rbac.authorization.k8s.io",
|
|
183
|
-
resource_name,
|
|
184
|
-
oc_resource,
|
|
185
|
-
privileged=privileged,
|
|
269
|
+
for oc_resource in rolebinding.get_oc_resources():
|
|
270
|
+
if not ri.get_desired(
|
|
271
|
+
rolebinding.cluster.name,
|
|
272
|
+
rolebinding.namespace.name,
|
|
273
|
+
"RoleBinding.rbac.authorization.k8s.io",
|
|
274
|
+
oc_resource.resource_name,
|
|
275
|
+
):
|
|
276
|
+
ri.add_desired_resource(
|
|
277
|
+
cluster=rolebinding.cluster.name,
|
|
278
|
+
namespace=rolebinding.namespace.name,
|
|
279
|
+
resource=oc_resource.resource,
|
|
280
|
+
privileged=oc_resource.privileged,
|
|
186
281
|
)
|
|
187
282
|
return users_desired_state
|
|
188
283
|
|
|
189
284
|
|
|
285
|
+
def is_valid_namespace(namespace: NamespaceV1 | CommonNamespaceV1) -> bool:
|
|
286
|
+
return (
|
|
287
|
+
bool(namespace.managed_roles)
|
|
288
|
+
and is_in_shard(f"{namespace.cluster.name}/{namespace.name}")
|
|
289
|
+
and not ob.is_namespace_deleted(namespace.model_dump(by_alias=True))
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
190
293
|
@defer
|
|
191
294
|
def run(
|
|
192
295
|
dry_run: bool,
|
|
193
296
|
thread_pool_size: int = DEFAULT_THREAD_POOL_SIZE,
|
|
194
297
|
internal: bool | None = None,
|
|
195
298
|
use_jump_host: bool = True,
|
|
299
|
+
support_role_ref: bool = False,
|
|
196
300
|
defer: Callable | None = None,
|
|
197
301
|
) -> None:
|
|
198
302
|
namespaces = [
|
|
199
|
-
|
|
200
|
-
for
|
|
201
|
-
if
|
|
202
|
-
and is_in_shard(
|
|
203
|
-
f"{namespace_info['cluster']['name']}/" + f"{namespace_info['name']}"
|
|
204
|
-
)
|
|
205
|
-
and not ob.is_namespace_deleted(namespace_info)
|
|
303
|
+
namespace.model_dump(by_alias=True, exclude={"openshift_resources"})
|
|
304
|
+
for namespace in get_namespaces()
|
|
305
|
+
if is_valid_namespace(namespace)
|
|
206
306
|
]
|
|
207
307
|
ri, oc_map = ob.fetch_current_state(
|
|
208
308
|
namespaces=namespaces,
|
|
@@ -215,7 +315,7 @@ def run(
|
|
|
215
315
|
)
|
|
216
316
|
if defer:
|
|
217
317
|
defer(oc_map.cleanup)
|
|
218
|
-
fetch_desired_state(ri, oc_map)
|
|
318
|
+
fetch_desired_state(ri, support_role_ref, allowed_clusters=set(oc_map.clusters()))
|
|
219
319
|
ob.publish_metrics(ri, QONTRACT_INTEGRATION)
|
|
220
320
|
ob.realize_data(dry_run, oc_map, ri, thread_pool_size)
|
|
221
321
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import logging
|
|
3
2
|
import os
|
|
4
3
|
import sys
|
|
@@ -28,6 +27,7 @@ from reconcile.typed_queries.saas_files import (
|
|
|
28
27
|
from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
|
|
29
28
|
from reconcile.utils.defer import defer
|
|
30
29
|
from reconcile.utils.gitlab_api import GitLabApi
|
|
30
|
+
from reconcile.utils.json import json_dumps
|
|
31
31
|
from reconcile.utils.openshift_resource import ResourceInventory
|
|
32
32
|
from reconcile.utils.saasherder import SaasHerder
|
|
33
33
|
from reconcile.utils.secret_reader import create_secret_reader
|
|
@@ -150,7 +150,7 @@ def run(
|
|
|
150
150
|
+ "when using slack notifications"
|
|
151
151
|
)
|
|
152
152
|
slack = slackapi_from_slack_workspace(
|
|
153
|
-
saas_file.slack.
|
|
153
|
+
saas_file.slack.model_dump(by_alias=True),
|
|
154
154
|
secret_reader,
|
|
155
155
|
QONTRACT_INTEGRATION,
|
|
156
156
|
init_usergroups=False,
|
|
@@ -224,7 +224,7 @@ def run(
|
|
|
224
224
|
default=False,
|
|
225
225
|
)
|
|
226
226
|
ri, oc_map = ob.fetch_current_state(
|
|
227
|
-
namespaces=[ns.
|
|
227
|
+
namespaces=[ns.model_dump(by_alias=True) for ns in saasherder.namespaces],
|
|
228
228
|
thread_pool_size=thread_pool_size,
|
|
229
229
|
integration=QONTRACT_INTEGRATION,
|
|
230
230
|
integration_version=QONTRACT_INTEGRATION_VERSION,
|
|
@@ -319,14 +319,13 @@ def run(
|
|
|
319
319
|
openshift_saas_deploy_trigger_upstream_jobs.QONTRACT_INTEGRATION,
|
|
320
320
|
openshift_saas_deploy_trigger_images.QONTRACT_INTEGRATION,
|
|
321
321
|
]
|
|
322
|
-
|
|
322
|
+
if (
|
|
323
323
|
not dry_run
|
|
324
324
|
and len(saas_files) == 1
|
|
325
325
|
and trigger_integration
|
|
326
326
|
and trigger_integration in allowed_integration
|
|
327
327
|
and trigger_reason
|
|
328
|
-
)
|
|
329
|
-
if scan:
|
|
328
|
+
):
|
|
330
329
|
saas_file = saas_files[0]
|
|
331
330
|
owners = saas_file.app.service_owners or []
|
|
332
331
|
emails = " ".join([o.email for o in owners])
|
|
@@ -346,4 +345,4 @@ def run(
|
|
|
346
345
|
if image_auth.auth_server:
|
|
347
346
|
json_file = os.path.join(io_dir, "dockerconfigjson")
|
|
348
347
|
with open(json_file, "w", encoding="locale") as f:
|
|
349
|
-
f.write(
|
|
348
|
+
f.write(json_dumps(image_auth.get_docker_config_json(), indent=2))
|
|
@@ -34,7 +34,7 @@ class Definition(BaseModel):
|
|
|
34
34
|
class State(BaseModel):
|
|
35
35
|
saas_file_path: str
|
|
36
36
|
saas_file_name: str
|
|
37
|
-
saas_file_deploy_resources: DeployResourcesV1 | None
|
|
37
|
+
saas_file_deploy_resources: DeployResourcesV1 | None = None
|
|
38
38
|
resource_template_name: str
|
|
39
39
|
cluster: str
|
|
40
40
|
namespace: str
|
|
@@ -44,10 +44,10 @@ class State(BaseModel):
|
|
|
44
44
|
parameters: dict[str, Any]
|
|
45
45
|
secret_parameters: dict[str, VaultSecret]
|
|
46
46
|
saas_file_definitions: Definition
|
|
47
|
-
upstream: SaasResourceTemplateTargetUpstreamV1 | None
|
|
48
|
-
disable: bool | None
|
|
49
|
-
delete: bool | None
|
|
50
|
-
target_path: str | None
|
|
47
|
+
upstream: SaasResourceTemplateTargetUpstreamV1 | None = None
|
|
48
|
+
disable: bool | None = None
|
|
49
|
+
delete: bool | None = None
|
|
50
|
+
target_path: str | None = None
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def osd_run_wrapper(
|
|
@@ -213,11 +213,13 @@ def run(
|
|
|
213
213
|
saas_file_list = SaasFileList()
|
|
214
214
|
desired_saas_file_state = collect_state(saas_file_list.saas_files)
|
|
215
215
|
# compare dicts against dicts which is much faster than comparing BaseModel objects
|
|
216
|
-
comparison_saas_file_state_dicts = [
|
|
216
|
+
comparison_saas_file_state_dicts = [
|
|
217
|
+
s.model_dump() for s in comparison_saas_file_state
|
|
218
|
+
]
|
|
217
219
|
saas_file_state_diffs = [
|
|
218
220
|
s
|
|
219
221
|
for s in desired_saas_file_state
|
|
220
|
-
if s.
|
|
222
|
+
if s.model_dump() not in comparison_saas_file_state_dicts
|
|
221
223
|
]
|
|
222
224
|
if not saas_file_state_diffs:
|
|
223
225
|
return
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from collections.abc import Callable
|
|
3
3
|
from datetime import (
|
|
4
|
-
UTC,
|
|
5
4
|
datetime,
|
|
6
5
|
timedelta,
|
|
7
6
|
)
|
|
8
7
|
from typing import Any
|
|
9
8
|
|
|
10
|
-
from dateutil import parser
|
|
11
|
-
|
|
12
9
|
from reconcile.gql_definitions.fragments.pipeline_provider_retention import (
|
|
13
10
|
PipelineProviderRetention,
|
|
14
11
|
)
|
|
@@ -19,6 +16,7 @@ from reconcile.typed_queries.tekton_pipeline_providers import (
|
|
|
19
16
|
get_tekton_pipeline_providers,
|
|
20
17
|
)
|
|
21
18
|
from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
|
|
19
|
+
from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
|
|
22
20
|
from reconcile.utils.defer import defer
|
|
23
21
|
from reconcile.utils.oc_map import (
|
|
24
22
|
OCLogMsg,
|
|
@@ -35,7 +33,7 @@ def within_retention_days(
|
|
|
35
33
|
resource: dict[str, Any], days: int, now_date: datetime
|
|
36
34
|
) -> bool:
|
|
37
35
|
metadata = resource["metadata"]
|
|
38
|
-
creation_date =
|
|
36
|
+
creation_date = from_utc_iso_format(metadata["creationTimestamp"])
|
|
39
37
|
interval = now_date.timestamp() - creation_date.timestamp()
|
|
40
38
|
|
|
41
39
|
return interval < timedelta(days=days).total_seconds()
|
|
@@ -69,7 +67,7 @@ def run(
|
|
|
69
67
|
use_jump_host: bool = True,
|
|
70
68
|
defer: Callable | None = None,
|
|
71
69
|
) -> None:
|
|
72
|
-
now_date =
|
|
70
|
+
now_date = utc_now()
|
|
73
71
|
vault_settings = get_app_interface_vault_settings()
|
|
74
72
|
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
|
75
73
|
pipeline_providers = get_tekton_pipeline_providers()
|
|
@@ -87,13 +87,14 @@ def fetch_desired_state(
|
|
|
87
87
|
if not namespace.openshift_service_account_tokens:
|
|
88
88
|
continue
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
oc = oc_map.get(namespace.cluster.name)
|
|
91
|
+
if isinstance(oc, ob.OCLogMsg):
|
|
91
92
|
logging.log(level=oc.log_level, msg=oc.message)
|
|
92
93
|
continue
|
|
93
94
|
|
|
94
95
|
for sat in namespace.openshift_service_account_tokens:
|
|
95
96
|
oc = oc_map.get(sat.namespace.cluster.name)
|
|
96
|
-
if
|
|
97
|
+
if isinstance(oc, ob.OCLogMsg):
|
|
97
98
|
if oc.log_level >= logging.ERROR:
|
|
98
99
|
ri.register_error()
|
|
99
100
|
logging.log(level=oc.log_level, msg=oc.message)
|
|
@@ -156,11 +157,11 @@ def write_outputs_to_vault(
|
|
|
156
157
|
f"{vault_path}/{integration_name}/{cluster}/{namespace}/{name}"
|
|
157
158
|
)
|
|
158
159
|
secret = {"path": secret_path, "data": body_data}
|
|
159
|
-
vault_client.write(secret)
|
|
160
|
+
vault_client.write(secret)
|
|
160
161
|
# write secret to shared-resources location
|
|
161
162
|
secret_path = f"{vault_path}/{integration_name}/shared-resources/{name}"
|
|
162
163
|
secret = {"path": secret_path, "data": body_data}
|
|
163
|
-
vault_client.write(secret)
|
|
164
|
+
vault_client.write(secret)
|
|
164
165
|
|
|
165
166
|
|
|
166
167
|
def canonicalize_namespaces(namespaces: Iterable[NamespaceV1]) -> list[NamespaceV1]:
|
|
@@ -176,7 +177,7 @@ def canonicalize_namespaces(namespaces: Iterable[NamespaceV1]) -> list[Namespace
|
|
|
176
177
|
key = f"{sat.namespace.cluster.name}/{sat.namespace.name}"
|
|
177
178
|
if key not in canonicalized_namespaces:
|
|
178
179
|
canonicalized_namespaces[key] = NamespaceV1(
|
|
179
|
-
**sat.namespace.
|
|
180
|
+
**sat.namespace.model_dump(by_alias=True),
|
|
180
181
|
sharedResources=None,
|
|
181
182
|
openshiftServiceAccountTokens=None,
|
|
182
183
|
)
|
|
@@ -216,7 +217,7 @@ def run(
|
|
|
216
217
|
get_namespaces_with_serviceaccount_tokens(gql_api.query)
|
|
217
218
|
)
|
|
218
219
|
ri, oc_map = ob.fetch_current_state(
|
|
219
|
-
namespaces=[ns.
|
|
220
|
+
namespaces=[ns.model_dump(by_alias=True) for ns in namespaces],
|
|
220
221
|
thread_pool_size=thread_pool_size,
|
|
221
222
|
integration=QONTRACT_INTEGRATION,
|
|
222
223
|
integration_version=QONTRACT_INTEGRATION_VERSION,
|
|
@@ -230,7 +231,7 @@ def run(
|
|
|
230
231
|
ob.publish_metrics(ri, QONTRACT_INTEGRATION)
|
|
231
232
|
ob.realize_data(dry_run, oc_map, ri, thread_pool_size)
|
|
232
233
|
if not dry_run and vault_output_path:
|
|
233
|
-
write_outputs_to_vault(VaultClient(), vault_output_path, ri)
|
|
234
|
+
write_outputs_to_vault(VaultClient.get_instance(), vault_output_path, ri)
|
|
234
235
|
|
|
235
236
|
if ri.has_error_registered():
|
|
236
237
|
sys.exit(1)
|
|
@@ -456,7 +456,7 @@ def run(
|
|
|
456
456
|
|
|
457
457
|
LOG.debug("Adding desired resources to inventory")
|
|
458
458
|
for desired_resource in desired_resources:
|
|
459
|
-
ri.add_desired(**desired_resource)
|
|
459
|
+
ri.add_desired(**desired_resource) # type: ignore
|
|
460
460
|
|
|
461
461
|
LOG.debug("Publishing metrics")
|
|
462
462
|
ob.publish_metrics(ri, QONTRACT_INTEGRATION)
|
|
@@ -3,7 +3,6 @@ from collections.abc import (
|
|
|
3
3
|
Callable,
|
|
4
4
|
Iterable,
|
|
5
5
|
)
|
|
6
|
-
from datetime import datetime
|
|
7
6
|
|
|
8
7
|
from reconcile import queries
|
|
9
8
|
from reconcile.gql_definitions.common.clusters import ClusterV1
|
|
@@ -13,6 +12,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
|
|
|
13
12
|
)
|
|
14
13
|
from reconcile.typed_queries.clusters import get_clusters
|
|
15
14
|
from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
|
|
15
|
+
from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
|
|
16
16
|
from reconcile.utils.defer import defer
|
|
17
17
|
from reconcile.utils.oc_map import (
|
|
18
18
|
OCLogMsg,
|
|
@@ -101,7 +101,7 @@ def notify_upgrades_start(
|
|
|
101
101
|
state: State,
|
|
102
102
|
slack: SlackApi | None,
|
|
103
103
|
) -> None:
|
|
104
|
-
now =
|
|
104
|
+
now = utc_now()
|
|
105
105
|
for cluster in clusters:
|
|
106
106
|
if cluster.spec and not cluster.spec.hypershift:
|
|
107
107
|
upgrade_at, version = _get_start_osd(oc_map, cluster.name)
|
|
@@ -113,7 +113,7 @@ def notify_upgrades_start(
|
|
|
113
113
|
continue
|
|
114
114
|
|
|
115
115
|
if upgrade_at and version:
|
|
116
|
-
upgrade_at_obj =
|
|
116
|
+
upgrade_at_obj = from_utc_iso_format(upgrade_at)
|
|
117
117
|
state_key = f"{cluster.name}-{upgrade_at}1"
|
|
118
118
|
# if this is the first iteration in which 'now' had passed
|
|
119
119
|
# the upgrade at date time, we send a notification
|
|
@@ -185,7 +185,7 @@ def run(
|
|
|
185
185
|
if defer:
|
|
186
186
|
defer(oc_map.cleanup)
|
|
187
187
|
|
|
188
|
-
cluster_like_objects = [cluster.
|
|
188
|
+
cluster_like_objects = [cluster.model_dump(by_alias=True) for cluster in clusters]
|
|
189
189
|
ocm_map = OCMMap(
|
|
190
190
|
clusters=cluster_like_objects,
|
|
191
191
|
integration=QONTRACT_INTEGRATION,
|
reconcile/openshift_users.py
CHANGED
|
@@ -101,14 +101,16 @@ def fetch_desired_state(
|
|
|
101
101
|
oc_map: OCMap | None, enforced_user_keys: Any = None
|
|
102
102
|
) -> list[Any]:
|
|
103
103
|
desired_state = []
|
|
104
|
-
|
|
104
|
+
filtered_clusters = oc_map.clusters() if oc_map else None
|
|
105
105
|
flat_rolebindings_desired_state = openshift_rolebindings.fetch_desired_state(
|
|
106
|
-
ri=None,
|
|
106
|
+
ri=None,
|
|
107
|
+
enforced_user_keys=enforced_user_keys,
|
|
108
|
+
allowed_clusters=set(filtered_clusters) if filtered_clusters else None,
|
|
107
109
|
)
|
|
108
110
|
desired_state.extend(flat_rolebindings_desired_state)
|
|
109
111
|
|
|
110
112
|
groups_desired_state = openshift_groups.fetch_desired_state(
|
|
111
|
-
clusters=
|
|
113
|
+
clusters=filtered_clusters or [],
|
|
112
114
|
enforced_user_keys=enforced_user_keys,
|
|
113
115
|
)
|
|
114
116
|
flat_groups_desired_state = [
|