qontract-reconcile 0.10.2.dev394__py3-none-any.whl → 0.10.2.dev427__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.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/METADATA +5 -4
- {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/RECORD +316 -315
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +18 -12
- reconcile/aus/base.py +117 -18
- 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 +6 -6
- reconcile/aws_account_manager/reconciler.py +3 -3
- reconcile/aws_ami_cleanup/integration.py +2 -5
- reconcile/aws_ami_share.py +69 -62
- reconcile/aws_saml_idp/integration.py +5 -3
- reconcile/aws_saml_roles/integration.py +23 -22
- reconcile/aws_version_sync/integration.py +6 -12
- 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/cli.py +62 -4
- reconcile/dashdotdb_dora.py +1 -1
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +8 -9
- 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 +1 -1
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +3 -2
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +13 -13
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +2 -2
- reconcile/external_resources/state.py +22 -13
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gcp_image_mirror.py +2 -2
- reconcile/github_org.py +1 -1
- reconcile/github_owners.py +4 -0
- reconcile/gitlab_members.py +6 -12
- reconcile/gitlab_permissions.py +8 -12
- reconcile/glitchtip_project_alerts/integration.py +3 -1
- reconcile/gql_definitions/acs/acs_instances.py +5 -5
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
- reconcile/gql_definitions/automated_actions/instance.py +46 -7
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
- reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
- reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
- reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
- reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
- reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
- reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_roles.py +5 -5
- reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
- reconcile/gql_definitions/common/apps.py +5 -5
- reconcile/gql_definitions/common/aws_vpc_requests.py +5 -5
- reconcile/gql_definitions/common/aws_vpcs.py +5 -5
- reconcile/gql_definitions/common/clusters.py +5 -5
- reconcile/gql_definitions/common/clusters_minimal.py +5 -5
- reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
- reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
- reconcile/gql_definitions/common/github_orgs.py +5 -5
- reconcile/gql_definitions/common/jira_settings.py +5 -5
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +5 -5
- reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
- reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
- reconcile/gql_definitions/common/ocm_environments.py +5 -5
- reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
- reconcile/gql_definitions/common/pipeline_providers.py +5 -5
- reconcile/gql_definitions/common/quay_instances.py +5 -5
- reconcile/gql_definitions/common/quay_orgs.py +5 -5
- reconcile/gql_definitions/common/reserved_networks.py +5 -5
- reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
- reconcile/gql_definitions/common/saas_files.py +5 -5
- reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
- reconcile/gql_definitions/common/saasherder_settings.py +5 -5
- reconcile/gql_definitions/common/slack_workspaces.py +5 -5
- reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
- reconcile/gql_definitions/common/state_aws_account.py +5 -5
- reconcile/gql_definitions/common/users.py +5 -5
- reconcile/gql_definitions/common/users_with_paths.py +5 -5
- reconcile/gql_definitions/cost_report/app_names.py +5 -5
- reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
- reconcile/gql_definitions/cost_report/settings.py +5 -5
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
- reconcile/gql_definitions/email_sender/apps.py +5 -5
- reconcile/gql_definitions/email_sender/emails.py +5 -5
- reconcile/gql_definitions/email_sender/users.py +5 -5
- reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
- reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
- reconcile/gql_definitions/fragments/aus_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_common.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
- reconcile/gql_definitions/fragments/aws_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc_request.py +5 -5
- reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
- reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
- reconcile/gql_definitions/fragments/disable.py +5 -5
- reconcile/gql_definitions/fragments/email_service.py +5 -5
- reconcile/gql_definitions/fragments/email_user.py +5 -5
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
- reconcile/gql_definitions/fragments/membership_source.py +5 -5
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
- reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_values.py +5 -5
- reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
- reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
- reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
- reconcile/gql_definitions/fragments/terraform_state.py +5 -5
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
- reconcile/gql_definitions/fragments/user.py +5 -5
- reconcile/gql_definitions/fragments/vault_secret.py +5 -5
- reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
- reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
- reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
- reconcile/gql_definitions/integrations/integrations.py +5 -5
- reconcile/gql_definitions/introspection.json +231 -0
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +5 -5
- reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +5 -5
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
- reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
- reconcile/gql_definitions/rhcs/certs.py +24 -79
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +42 -0
- reconcile/gql_definitions/rhidp/organizations.py +5 -5
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
- reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
- reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
- reconcile/gql_definitions/slack_usergroups/users.py +5 -5
- reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
- reconcile/gql_definitions/status_board/status_board.py +5 -5
- reconcile/gql_definitions/statuspage/statuspages.py +5 -5
- reconcile/gql_definitions/templating/template_collection.py +5 -5
- reconcile/gql_definitions/templating/templates.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
- reconcile/gql_definitions/terraform_init/aws_accounts.py +5 -5
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +5 -5
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +5 -5
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
- reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
- reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_worker_fleets.py +9 -8
- reconcile/jira_permissions_validator.py +2 -2
- reconcile/ldap_groups/integration.py +1 -1
- reconcile/ocm/types.py +35 -57
- reconcile/ocm_aws_infrastructure_access.py +1 -1
- reconcile/ocm_clusters.py +4 -4
- reconcile/ocm_labels/integration.py +3 -2
- reconcile/ocm_machine_pools.py +33 -27
- reconcile/openshift_base.py +113 -4
- reconcile/openshift_cluster_bots.py +1 -1
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +6 -2
- reconcile/openshift_rhcs_certs.py +27 -29
- reconcile/openshift_rolebindings.py +7 -11
- reconcile/openshift_saas_deploy.py +4 -5
- reconcile/openshift_saas_deploy_change_tester.py +9 -7
- reconcile/openshift_serviceaccount_tokens.py +2 -2
- reconcile/openshift_upgrade_watcher.py +1 -1
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/prometheus_rules_tester/integration.py +3 -3
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +6 -0
- reconcile/rhidp/common.py +3 -5
- reconcile/rhidp/sso_client/base.py +16 -5
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +31 -11
- reconcile/status_board.py +6 -6
- reconcile/statuspage/atlassian.py +7 -7
- reconcile/statuspage/page.py +4 -9
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +2 -2
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +5 -5
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +2 -2
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +6 -6
- reconcile/terraform_tgw_attachments.py +20 -18
- reconcile/terraform_vpc_resources/integration.py +3 -1
- 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 +11 -11
- reconcile/typed_queries/status_board.py +2 -2
- reconcile/unleash_feature_toggles/integration.py +4 -2
- reconcile/utils/acs/base.py +6 -3
- reconcile/utils/acs/policies.py +2 -2
- reconcile/utils/aws_api.py +51 -20
- reconcile/utils/aws_api_typed/organization.py +4 -2
- reconcile/utils/binary.py +7 -12
- reconcile/utils/deadmanssnitch_api.py +1 -1
- reconcile/utils/early_exit_cache.py +8 -10
- reconcile/utils/gitlab_api.py +7 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gql.py +4 -7
- reconcile/utils/instrumented_wrappers.py +1 -1
- reconcile/utils/internal_groups/client.py +2 -2
- reconcile/utils/internal_groups/models.py +8 -17
- reconcile/utils/jinja2/utils.py +2 -5
- reconcile/utils/jobcontroller/controller.py +2 -2
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +43 -1
- reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
- reconcile/utils/membershipsources/models.py +16 -23
- reconcile/utils/membershipsources/resolver.py +4 -2
- reconcile/utils/merge_request_manager/merge_request_manager.py +1 -1
- reconcile/utils/merge_request_manager/parser.py +4 -4
- reconcile/utils/metrics.py +5 -5
- reconcile/utils/models.py +304 -82
- reconcile/utils/mr/notificator.py +1 -1
- reconcile/utils/mr/user_maintenance.py +3 -2
- reconcile/utils/oc.py +246 -201
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +17 -20
- reconcile/utils/ocm/cluster_groups.py +1 -1
- reconcile/utils/ocm/identity_providers.py +2 -2
- reconcile/utils/ocm/labels.py +1 -1
- reconcile/utils/ocm/products.py +8 -8
- reconcile/utils/ocm/service_log.py +1 -1
- reconcile/utils/ocm/sre_capability_labels.py +20 -13
- reconcile/utils/openshift_resource.py +5 -0
- reconcile/utils/pagerduty_api.py +5 -2
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/raw_github_api.py +1 -1
- reconcile/utils/rhcsv2_certs.py +1 -4
- reconcile/utils/rosa/session.py +16 -0
- reconcile/utils/runtime/integration.py +1 -1
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +23 -20
- reconcile/utils/saasherder/saasherder.py +46 -24
- reconcile/utils/slack_api.py +2 -2
- reconcile/utils/structs.py +1 -1
- reconcile/utils/terraform_client.py +1 -1
- reconcile/utils/terrascript_aws_client.py +47 -43
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +5 -12
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +1 -1
- tools/cli_commands/cost_report/cost_management_api.py +3 -3
- tools/cli_commands/cost_report/view.py +7 -6
- tools/cli_commands/erv2.py +1 -1
- tools/qontract_cli.py +6 -5
- tools/template_validation.py +3 -1
- {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev427.dist-info}/entry_points.txt +0 -0
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
import
|
|
2
|
+
from collections import defaultdict
|
|
3
3
|
from collections.abc import (
|
|
4
4
|
Callable,
|
|
5
5
|
Iterable,
|
|
6
|
-
Mapping,
|
|
7
6
|
Sequence,
|
|
8
7
|
)
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from enum import StrEnum
|
|
9
10
|
from typing import Any
|
|
10
11
|
|
|
11
12
|
from sretoolbox.utils import threaded
|
|
12
13
|
|
|
13
14
|
import reconcile.openshift_base as ob
|
|
14
15
|
from reconcile.gql_definitions.common.namespaces_minimal import NamespaceV1
|
|
15
|
-
from reconcile.status import ExitCodes
|
|
16
16
|
from reconcile.typed_queries.app_interface_vault_settings import (
|
|
17
17
|
get_app_interface_vault_settings,
|
|
18
18
|
)
|
|
19
19
|
from reconcile.typed_queries.namespaces_minimal import get_namespaces_minimal
|
|
20
20
|
from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
|
|
21
21
|
from reconcile.utils.defer import defer
|
|
22
|
-
from reconcile.utils.oc_filters import
|
|
22
|
+
from reconcile.utils.oc_filters import (
|
|
23
|
+
filter_namespaces_by_cluster_and_namespace,
|
|
24
|
+
)
|
|
23
25
|
from reconcile.utils.oc_map import (
|
|
24
26
|
OCLogMsg,
|
|
25
27
|
OCMap,
|
|
@@ -30,113 +32,112 @@ from reconcile.utils.sharding import is_in_shard
|
|
|
30
32
|
|
|
31
33
|
QONTRACT_INTEGRATION = "openshift-namespaces"
|
|
32
34
|
|
|
33
|
-
NS_STATE_PRESENT = "present"
|
|
34
|
-
NS_STATE_ABSENT = "absent"
|
|
35
|
-
|
|
36
|
-
NS_ACTION_CREATE = "create"
|
|
37
|
-
NS_ACTION_DELETE = "delete"
|
|
38
35
|
|
|
36
|
+
class Action(StrEnum):
|
|
37
|
+
CREATE = "create"
|
|
38
|
+
DELETE = "delete"
|
|
39
39
|
|
|
40
|
-
DUPLICATES_LOG_MSG = "Found multiple definitions for the namespace {key}"
|
|
41
40
|
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class DesiredState:
|
|
43
|
+
cluster: str
|
|
44
|
+
namespace: str
|
|
45
|
+
delete: bool
|
|
42
46
|
|
|
43
|
-
def get_desired_state(namespaces: Iterable[NamespaceV1]) -> list[dict[str, str]]:
|
|
44
|
-
desired_state: list[dict[str, str]] = []
|
|
45
|
-
for ns in namespaces:
|
|
46
|
-
state = NS_STATE_PRESENT
|
|
47
|
-
if ns.delete:
|
|
48
|
-
state = NS_STATE_ABSENT
|
|
49
47
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"namespace": ns.name,
|
|
53
|
-
"desired_state": state,
|
|
54
|
-
})
|
|
48
|
+
class NamespaceDuplicateError(Exception):
|
|
49
|
+
pass
|
|
55
50
|
|
|
56
|
-
return desired_state
|
|
57
51
|
|
|
52
|
+
def get_namespaces(
|
|
53
|
+
cluster_name: Sequence[str] | None,
|
|
54
|
+
namespace_name: Sequence[str] | None,
|
|
55
|
+
) -> tuple[list[NamespaceV1], list[NamespaceDuplicateError]]:
|
|
56
|
+
all_namespaces = get_namespaces_minimal()
|
|
58
57
|
|
|
59
|
-
|
|
60
|
-
namespaces: Iterable[NamespaceV1],
|
|
61
|
-
) -> tuple[list[NamespaceV1], bool]:
|
|
62
|
-
# Structure holding duplicates by namespace key
|
|
63
|
-
duplicates: dict[str, list[NamespaceV1]] = {}
|
|
64
|
-
# namespace filtered list without duplicates
|
|
65
|
-
filtered_ns: dict[str, NamespaceV1] = {}
|
|
66
|
-
|
|
67
|
-
err = False
|
|
68
|
-
for ns in namespaces:
|
|
69
|
-
key = f"{ns.cluster.name}/{ns.name}"
|
|
58
|
+
namespaces_by_shard_key = defaultdict(list)
|
|
70
59
|
|
|
60
|
+
for namespace in all_namespaces:
|
|
61
|
+
key = f"{namespace.cluster.name}/{namespace.name}"
|
|
71
62
|
if is_in_shard(key):
|
|
72
|
-
|
|
73
|
-
filtered_ns[key] = ns
|
|
74
|
-
else:
|
|
75
|
-
# Duplicated NS
|
|
76
|
-
dupe_list_by_key = duplicates.setdefault(key, [])
|
|
77
|
-
dupe_list_by_key.append(ns)
|
|
78
|
-
|
|
79
|
-
for key, dupe_list in duplicates.items():
|
|
80
|
-
dupe_list.append(filtered_ns[key])
|
|
81
|
-
delete_flags = (
|
|
82
|
-
[ns.delete for ns in dupe_list_by_key] if dupe_list_by_key else []
|
|
83
|
-
)
|
|
63
|
+
namespaces_by_shard_key[key].append(namespace)
|
|
84
64
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
65
|
+
managed_namespaces = []
|
|
66
|
+
duplicate_errors = []
|
|
67
|
+
|
|
68
|
+
for key, namespaces in namespaces_by_shard_key.items():
|
|
69
|
+
if len(namespaces) == 1:
|
|
70
|
+
namespace = namespaces[0]
|
|
71
|
+
if not namespace.managed_by_external:
|
|
72
|
+
managed_namespaces.append(namespace)
|
|
92
73
|
else:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
logging.
|
|
74
|
+
msg = f"Found multiple definitions for the namespace {key}"
|
|
75
|
+
duplicate_errors.append(NamespaceDuplicateError(msg))
|
|
76
|
+
logging.error(msg)
|
|
77
|
+
|
|
78
|
+
namespaces = filter_namespaces_by_cluster_and_namespace(
|
|
79
|
+
namespaces=managed_namespaces,
|
|
80
|
+
cluster_names=cluster_name,
|
|
81
|
+
namespace_names=namespace_name,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
return namespaces, duplicate_errors
|
|
85
|
+
|
|
96
86
|
|
|
97
|
-
|
|
87
|
+
def build_desired_state(
|
|
88
|
+
namespaces: Iterable[NamespaceV1],
|
|
89
|
+
) -> list[DesiredState]:
|
|
90
|
+
return [
|
|
91
|
+
DesiredState(
|
|
92
|
+
cluster=namespace.cluster.name,
|
|
93
|
+
namespace=namespace.name,
|
|
94
|
+
delete=namespace.delete or False,
|
|
95
|
+
)
|
|
96
|
+
for namespace in namespaces
|
|
97
|
+
]
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
def
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
def manage_namespace(
|
|
101
|
+
desired_state: DesiredState,
|
|
102
|
+
oc_map: OCMap,
|
|
103
|
+
dry_run: bool,
|
|
104
|
+
) -> None:
|
|
105
|
+
namespace = desired_state.namespace
|
|
104
106
|
|
|
105
|
-
oc = oc_map.get(cluster)
|
|
107
|
+
oc = oc_map.get(desired_state.cluster)
|
|
106
108
|
if isinstance(oc, OCLogMsg):
|
|
107
109
|
logging.log(level=oc.log_level, msg=oc.message)
|
|
108
|
-
return
|
|
110
|
+
return
|
|
109
111
|
|
|
110
|
-
|
|
112
|
+
current_delete = not oc.project_exists(namespace)
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if not exists and desired_state == NS_STATE_PRESENT:
|
|
115
|
-
if namespace.startswith("openshift-"):
|
|
116
|
-
raise ValueError('cannot request a project starting with "openshift-"')
|
|
117
|
-
action = NS_ACTION_CREATE
|
|
118
|
-
elif exists and desired_state == NS_STATE_ABSENT:
|
|
119
|
-
action = NS_ACTION_DELETE
|
|
114
|
+
if desired_state.delete == current_delete:
|
|
115
|
+
return
|
|
120
116
|
|
|
121
|
-
if
|
|
122
|
-
logging.info([action, cluster, namespace])
|
|
123
|
-
if not dry_run:
|
|
124
|
-
act[action](namespace)
|
|
117
|
+
action = Action.DELETE if desired_state.delete else Action.CREATE
|
|
125
118
|
|
|
119
|
+
if namespace.startswith("openshift-"):
|
|
120
|
+
raise ValueError(f'cannot {action} a project starting with "openshift-"')
|
|
126
121
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
122
|
+
logging.info([str(action), desired_state.cluster, namespace])
|
|
123
|
+
if not dry_run:
|
|
124
|
+
match action:
|
|
125
|
+
case Action.CREATE:
|
|
126
|
+
oc.new_project(namespace)
|
|
127
|
+
case Action.DELETE:
|
|
128
|
+
oc.delete_project(namespace)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def build_runtime_errors(
|
|
132
|
+
desired_state: Iterable[DesiredState],
|
|
133
|
+
results: Iterable[Any],
|
|
134
|
+
) -> list[Exception]:
|
|
135
|
+
exceptions = []
|
|
131
136
|
for s, e in zip(desired_state, results, strict=False):
|
|
132
137
|
if isinstance(e, Exception):
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
f"exception: {e!s}"
|
|
137
|
-
)
|
|
138
|
-
logging.error(msg)
|
|
139
|
-
return err
|
|
138
|
+
e.add_note(f"cluster: {s.cluster}, namespace: {s.namespace}")
|
|
139
|
+
exceptions.append(e)
|
|
140
|
+
return exceptions
|
|
140
141
|
|
|
141
142
|
|
|
142
143
|
@defer
|
|
@@ -149,15 +150,8 @@ def run(
|
|
|
149
150
|
namespace_name: Sequence[str] | None = None,
|
|
150
151
|
defer: Callable | None = None,
|
|
151
152
|
) -> None:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
namespaces = filter_namespaces_by_cluster_and_namespace(
|
|
155
|
-
namespaces=shard_namespaces,
|
|
156
|
-
cluster_names=cluster_name,
|
|
157
|
-
namespace_names=namespace_name,
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
desired_state = get_desired_state(namespaces)
|
|
153
|
+
namespaces, duplicate_errors = get_namespaces(cluster_name, namespace_name)
|
|
154
|
+
desired_state = build_desired_state(namespaces)
|
|
161
155
|
|
|
162
156
|
vault_settings = get_app_interface_vault_settings()
|
|
163
157
|
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
|
@@ -171,16 +165,17 @@ def run(
|
|
|
171
165
|
thread_pool_size=thread_pool_size,
|
|
172
166
|
init_projects=True,
|
|
173
167
|
)
|
|
174
|
-
|
|
175
168
|
if defer:
|
|
176
169
|
defer(oc_map.cleanup)
|
|
177
170
|
|
|
178
171
|
ob.publish_cluster_desired_metrics_from_state(
|
|
179
|
-
desired_state,
|
|
172
|
+
state=({"cluster": s.cluster} for s in desired_state),
|
|
173
|
+
integration=QONTRACT_INTEGRATION,
|
|
174
|
+
kind="Namespace",
|
|
180
175
|
)
|
|
181
176
|
|
|
182
177
|
results = threaded.run(
|
|
183
|
-
|
|
178
|
+
manage_namespace,
|
|
184
179
|
desired_state,
|
|
185
180
|
thread_pool_size,
|
|
186
181
|
return_exceptions=True,
|
|
@@ -188,6 +183,7 @@ def run(
|
|
|
188
183
|
oc_map=oc_map,
|
|
189
184
|
)
|
|
190
185
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
186
|
+
runtime_errors = build_runtime_errors(desired_state, results)
|
|
187
|
+
errors = runtime_errors + duplicate_errors
|
|
188
|
+
if errors:
|
|
189
|
+
raise ExceptionGroup("Reconcile errors occurred", errors)
|
|
@@ -806,7 +806,11 @@ def fetch_data(
|
|
|
806
806
|
init_api_resources=init_api_resources,
|
|
807
807
|
)
|
|
808
808
|
state_specs = ob.init_specs_to_fetch(
|
|
809
|
-
ri,
|
|
809
|
+
ri,
|
|
810
|
+
oc_map,
|
|
811
|
+
namespaces=namespaces,
|
|
812
|
+
override_managed_types=overrides,
|
|
813
|
+
cluster_scope_resource_validation=True,
|
|
810
814
|
)
|
|
811
815
|
threaded.run(fetch_states, state_specs, thread_pool_size, ri=ri, settings=settings)
|
|
812
816
|
|
|
@@ -861,7 +865,7 @@ def canonicalize_namespaces(
|
|
|
861
865
|
elif providers[0] == "route":
|
|
862
866
|
override = ["Route"]
|
|
863
867
|
elif providers[0] == "prometheus-rule":
|
|
864
|
-
override = ["PrometheusRule"]
|
|
868
|
+
override = ["PrometheusRule.monitoring.coreos.com"]
|
|
865
869
|
|
|
866
870
|
namespace_info["openshiftResources"] = ors
|
|
867
871
|
canonicalized_namespaces.append(namespace_info)
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
import sys
|
|
3
3
|
import time
|
|
4
4
|
from collections.abc import Callable, Iterable, Mapping
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
7
|
import reconcile.openshift_base as ob
|
|
8
8
|
import reconcile.openshift_resources_base as orb
|
|
@@ -10,8 +10,8 @@ from reconcile.gql_definitions.common.rhcs_provider_settings import (
|
|
|
10
10
|
RhcsProviderSettingsV1,
|
|
11
11
|
)
|
|
12
12
|
from reconcile.gql_definitions.rhcs.certs import (
|
|
13
|
-
NamespaceOpenshiftResourceRhcsCertV1,
|
|
14
13
|
NamespaceV1,
|
|
14
|
+
OpenshiftResourceRhcsCert,
|
|
15
15
|
)
|
|
16
16
|
from reconcile.gql_definitions.rhcs.certs import (
|
|
17
17
|
query as rhcs_certs_query,
|
|
@@ -40,7 +40,6 @@ from reconcile.utils.vault import SecretNotFoundError, VaultClient
|
|
|
40
40
|
|
|
41
41
|
QONTRACT_INTEGRATION = "openshift-rhcs-certs"
|
|
42
42
|
QONTRACT_INTEGRATION_VERSION = make_semver(1, 9, 3)
|
|
43
|
-
PROVIDERS = ["rhcs-cert"]
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
def desired_state_shard_config() -> DesiredStateShardConfig:
|
|
@@ -67,22 +66,18 @@ class OpenshiftRhcsCertExpiration(GaugeMetric):
|
|
|
67
66
|
return "qontract_reconcile_rhcs_cert_expiration_timestamp"
|
|
68
67
|
|
|
69
68
|
|
|
70
|
-
def _is_rhcs_cert(obj: Any) -> bool:
|
|
71
|
-
return getattr(obj, "provider", None) == "rhcs-cert"
|
|
72
|
-
|
|
73
|
-
|
|
74
69
|
def get_namespaces_with_rhcs_certs(
|
|
75
70
|
query_func: Callable,
|
|
76
71
|
cluster_name: Iterable[str] | None = None,
|
|
77
72
|
) -> list[NamespaceV1]:
|
|
78
73
|
result: list[NamespaceV1] = []
|
|
79
74
|
for ns in rhcs_certs_query(query_func=query_func).namespaces or []:
|
|
80
|
-
ob.aggregate_shared_resources_typed(
|
|
75
|
+
ob.aggregate_shared_resources_typed(ns)
|
|
81
76
|
if (
|
|
82
77
|
integration_is_enabled(QONTRACT_INTEGRATION, ns.cluster)
|
|
83
78
|
and not bool(ns.delete)
|
|
84
79
|
and (not cluster_name or ns.cluster.name in cluster_name)
|
|
85
|
-
and
|
|
80
|
+
and ns.openshift_resources
|
|
86
81
|
):
|
|
87
82
|
result.append(ns)
|
|
88
83
|
return result
|
|
@@ -105,7 +100,7 @@ def construct_rhcs_cert_oc_secret(
|
|
|
105
100
|
|
|
106
101
|
def cert_expires_within_threshold(
|
|
107
102
|
ns: NamespaceV1,
|
|
108
|
-
cert_resource:
|
|
103
|
+
cert_resource: OpenshiftResourceRhcsCert,
|
|
109
104
|
vault_cert_secret: Mapping[str, Any],
|
|
110
105
|
) -> bool:
|
|
111
106
|
auto_renew_threshold_days = cert_resource.auto_renew_threshold_days or 7
|
|
@@ -121,7 +116,7 @@ def cert_expires_within_threshold(
|
|
|
121
116
|
|
|
122
117
|
def get_vault_cert_secret(
|
|
123
118
|
ns: NamespaceV1,
|
|
124
|
-
cert_resource:
|
|
119
|
+
cert_resource: OpenshiftResourceRhcsCert,
|
|
125
120
|
vault: VaultClient,
|
|
126
121
|
vault_base_path: str,
|
|
127
122
|
) -> dict | None:
|
|
@@ -140,7 +135,7 @@ def get_vault_cert_secret(
|
|
|
140
135
|
def generate_vault_cert_secret(
|
|
141
136
|
dry_run: bool,
|
|
142
137
|
ns: NamespaceV1,
|
|
143
|
-
cert_resource:
|
|
138
|
+
cert_resource: OpenshiftResourceRhcsCert,
|
|
144
139
|
vault: VaultClient,
|
|
145
140
|
vault_base_path: str,
|
|
146
141
|
issuer_url: str,
|
|
@@ -149,7 +144,7 @@ def generate_vault_cert_secret(
|
|
|
149
144
|
logging.info(
|
|
150
145
|
f"Creating cert with service account credentials for '{cert_resource.service_account_name}'. cluster='{ns.cluster.name}', namespace='{ns.name}', secret='{cert_resource.secret_name}'"
|
|
151
146
|
)
|
|
152
|
-
sa_password = vault.read(cert_resource.service_account_password.
|
|
147
|
+
sa_password = vault.read(cert_resource.service_account_password.model_dump())
|
|
153
148
|
if dry_run:
|
|
154
149
|
rhcs_cert = RhcsV2Cert(
|
|
155
150
|
certificate="PLACEHOLDER_CERT",
|
|
@@ -171,18 +166,18 @@ def generate_vault_cert_secret(
|
|
|
171
166
|
)
|
|
172
167
|
vault.write(
|
|
173
168
|
secret={
|
|
174
|
-
"data": rhcs_cert.
|
|
169
|
+
"data": rhcs_cert.model_dump(by_alias=True),
|
|
175
170
|
"path": f"{vault_base_path}/{ns.cluster.name}/{ns.name}/{cert_resource.secret_name}",
|
|
176
171
|
},
|
|
177
172
|
decode_base64=False,
|
|
178
173
|
)
|
|
179
|
-
return rhcs_cert.
|
|
174
|
+
return rhcs_cert.model_dump(by_alias=True)
|
|
180
175
|
|
|
181
176
|
|
|
182
177
|
def fetch_openshift_resource_for_cert_resource(
|
|
183
178
|
dry_run: bool,
|
|
184
179
|
ns: NamespaceV1,
|
|
185
|
-
cert_resource:
|
|
180
|
+
cert_resource: OpenshiftResourceRhcsCert,
|
|
186
181
|
vault: VaultClient,
|
|
187
182
|
rhcs_settings: RhcsProviderSettingsV1,
|
|
188
183
|
) -> OR:
|
|
@@ -231,18 +226,13 @@ def fetch_desired_state(
|
|
|
231
226
|
cert_provider = get_rhcs_provider_settings(query_func=query_func)
|
|
232
227
|
for ns in namespaces:
|
|
233
228
|
for cert_resource in ns.openshift_resources or []:
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
cast("NamespaceOpenshiftResourceRhcsCertV1", cert_resource),
|
|
242
|
-
vault,
|
|
243
|
-
cert_provider,
|
|
244
|
-
),
|
|
245
|
-
)
|
|
229
|
+
ri.add_desired_resource(
|
|
230
|
+
cluster=ns.cluster.name,
|
|
231
|
+
namespace=ns.name,
|
|
232
|
+
resource=fetch_openshift_resource_for_cert_resource(
|
|
233
|
+
dry_run, ns, cert_resource, vault, cert_provider
|
|
234
|
+
),
|
|
235
|
+
)
|
|
246
236
|
|
|
247
237
|
|
|
248
238
|
@defer
|
|
@@ -277,7 +267,7 @@ def run(
|
|
|
277
267
|
state_specs = ob.init_specs_to_fetch(
|
|
278
268
|
ri,
|
|
279
269
|
oc_map,
|
|
280
|
-
namespaces=[ns.
|
|
270
|
+
namespaces=[ns.model_dump(by_alias=True) for ns in namespaces],
|
|
281
271
|
override_managed_types=["Secret"],
|
|
282
272
|
)
|
|
283
273
|
for spec in state_specs:
|
|
@@ -295,3 +285,11 @@ def run(
|
|
|
295
285
|
ob.publish_metrics(ri, QONTRACT_INTEGRATION)
|
|
296
286
|
if ri.has_error_registered():
|
|
297
287
|
sys.exit(1)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
|
|
291
|
+
if not (query_func := kwargs.get("query_func")):
|
|
292
|
+
query_func = gql.get_api().query
|
|
293
|
+
|
|
294
|
+
cluster_name = kwargs.get("cluster_name")
|
|
295
|
+
return {"namespace": get_namespaces_with_rhcs_certs(query_func, cluster_name)}
|
|
@@ -33,14 +33,11 @@ QONTRACT_INTEGRATION = "openshift-rolebindings"
|
|
|
33
33
|
QONTRACT_INTEGRATION_VERSION = make_semver(0, 3, 0)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class OCResource(BaseModel):
|
|
36
|
+
class OCResource(BaseModel, arbitrary_types_allowed=True):
|
|
37
37
|
resource: OR
|
|
38
38
|
resource_name: str
|
|
39
39
|
privileged: bool
|
|
40
40
|
|
|
41
|
-
class Config:
|
|
42
|
-
arbitrary_types_allowed = True
|
|
43
|
-
|
|
44
41
|
|
|
45
42
|
@dataclass
|
|
46
43
|
class ServiceAccountSpec:
|
|
@@ -61,7 +58,7 @@ class ServiceAccountSpec:
|
|
|
61
58
|
]
|
|
62
59
|
|
|
63
60
|
|
|
64
|
-
class RoleBindingSpec(BaseModel):
|
|
61
|
+
class RoleBindingSpec(BaseModel, validate_by_alias=True, arbitrary_types_allowed=True):
|
|
65
62
|
role_name: str
|
|
66
63
|
role_kind: str
|
|
67
64
|
namespace: NamespaceV1
|
|
@@ -70,9 +67,6 @@ class RoleBindingSpec(BaseModel):
|
|
|
70
67
|
usernames: set[str]
|
|
71
68
|
openshift_service_accounts: list[ServiceAccountSpec]
|
|
72
69
|
|
|
73
|
-
class Config:
|
|
74
|
-
arbitrary_types_allowed = True
|
|
75
|
-
|
|
76
70
|
def get_users_desired_state(self) -> list[dict[str, str]]:
|
|
77
71
|
return [
|
|
78
72
|
{"cluster": self.cluster.name, "user": username}
|
|
@@ -93,7 +87,9 @@ class RoleBindingSpec(BaseModel):
|
|
|
93
87
|
if not (access.role or access.cluster_role):
|
|
94
88
|
return None
|
|
95
89
|
privileged = access.namespace.cluster_admin or False
|
|
96
|
-
auth_dict = [
|
|
90
|
+
auth_dict = [
|
|
91
|
+
auth.model_dump(by_alias=True) for auth in access.namespace.cluster.auth
|
|
92
|
+
]
|
|
97
93
|
usernames = RoleBindingSpec.get_usernames_from_users(
|
|
98
94
|
users,
|
|
99
95
|
ob.determine_user_keys_for_access(
|
|
@@ -290,7 +286,7 @@ def is_valid_namespace(namespace: NamespaceV1 | CommonNamespaceV1) -> bool:
|
|
|
290
286
|
return (
|
|
291
287
|
bool(namespace.managed_roles)
|
|
292
288
|
and is_in_shard(f"{namespace.cluster.name}/{namespace.name}")
|
|
293
|
-
and not ob.is_namespace_deleted(namespace.
|
|
289
|
+
and not ob.is_namespace_deleted(namespace.model_dump(by_alias=True))
|
|
294
290
|
)
|
|
295
291
|
|
|
296
292
|
|
|
@@ -304,7 +300,7 @@ def run(
|
|
|
304
300
|
defer: Callable | None = None,
|
|
305
301
|
) -> None:
|
|
306
302
|
namespaces = [
|
|
307
|
-
namespace.
|
|
303
|
+
namespace.model_dump(by_alias=True, exclude={"openshift_resources"})
|
|
308
304
|
for namespace in get_namespaces()
|
|
309
305
|
if is_valid_namespace(namespace)
|
|
310
306
|
]
|
|
@@ -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])
|
|
@@ -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
|
|
@@ -177,7 +177,7 @@ def canonicalize_namespaces(namespaces: Iterable[NamespaceV1]) -> list[Namespace
|
|
|
177
177
|
key = f"{sat.namespace.cluster.name}/{sat.namespace.name}"
|
|
178
178
|
if key not in canonicalized_namespaces:
|
|
179
179
|
canonicalized_namespaces[key] = NamespaceV1(
|
|
180
|
-
**sat.namespace.
|
|
180
|
+
**sat.namespace.model_dump(by_alias=True),
|
|
181
181
|
sharedResources=None,
|
|
182
182
|
openshiftServiceAccountTokens=None,
|
|
183
183
|
)
|
|
@@ -217,7 +217,7 @@ def run(
|
|
|
217
217
|
get_namespaces_with_serviceaccount_tokens(gql_api.query)
|
|
218
218
|
)
|
|
219
219
|
ri, oc_map = ob.fetch_current_state(
|
|
220
|
-
namespaces=[ns.
|
|
220
|
+
namespaces=[ns.model_dump(by_alias=True) for ns in namespaces],
|
|
221
221
|
thread_pool_size=thread_pool_size,
|
|
222
222
|
integration=QONTRACT_INTEGRATION,
|
|
223
223
|
integration_version=QONTRACT_INTEGRATION_VERSION,
|
|
@@ -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/oum/labelset.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
|
+
from typing import Annotated
|
|
2
3
|
|
|
3
4
|
from pydantic import BaseModel
|
|
4
5
|
|
|
@@ -22,9 +23,10 @@ class _GroupMappingLabelset(BaseModel):
|
|
|
22
23
|
the sre-capabilities.user-mgmt.$provider prefix.
|
|
23
24
|
"""
|
|
24
25
|
|
|
25
|
-
authz_roles:
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
authz_roles: Annotated[
|
|
27
|
+
dict[str, CSV] | None,
|
|
28
|
+
sre_capability_labels.labelset_groupfield(group_prefix="authz."),
|
|
29
|
+
]
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
def build_cluster_config_from_labels(
|
reconcile/oum/models.py
CHANGED
|
@@ -56,7 +56,7 @@ class ClusterUserManagementSpec(BaseModel):
|
|
|
56
56
|
errors: list[ClusterError] = Field(default_factory=list)
|
|
57
57
|
|
|
58
58
|
|
|
59
|
-
class ClusterRoleReconcileResult(BaseModel):
|
|
59
|
+
class ClusterRoleReconcileResult(BaseModel, arbitrary_types_allowed=True):
|
|
60
60
|
"""
|
|
61
61
|
Holds the result of a cluster role reconciliation.
|
|
62
62
|
"""
|
|
@@ -64,6 +64,3 @@ class ClusterRoleReconcileResult(BaseModel):
|
|
|
64
64
|
users_added: int = 0
|
|
65
65
|
users_removed: int = 0
|
|
66
66
|
error: Exception | None = None
|
|
67
|
-
|
|
68
|
-
class Config:
|
|
69
|
-
arbitrary_types_allowed = True
|
|
@@ -56,7 +56,7 @@ class Test(BaseModel):
|
|
|
56
56
|
rule_path: str
|
|
57
57
|
rule: dict
|
|
58
58
|
rule_length: int
|
|
59
|
-
tests: list[TestContent] | None
|
|
59
|
+
tests: list[TestContent] | None = None
|
|
60
60
|
result: CommandExecutionResult | None = None
|
|
61
61
|
promtool_version: str
|
|
62
62
|
|
|
@@ -76,7 +76,7 @@ def fetch_rule_and_tests(
|
|
|
76
76
|
openshift_resource = orb.fetch_openshift_resource(
|
|
77
77
|
resource=rule.resource,
|
|
78
78
|
parent=rule.namespace,
|
|
79
|
-
settings=vault_settings.
|
|
79
|
+
settings=vault_settings.model_dump(by_alias=True),
|
|
80
80
|
)
|
|
81
81
|
|
|
82
82
|
rule_body = openshift_resource.body
|
|
@@ -96,7 +96,7 @@ def fetch_rule_and_tests(
|
|
|
96
96
|
test_raw_yaml = process_extracurlyjinja2_template(
|
|
97
97
|
body=test_raw_yaml,
|
|
98
98
|
vars=variables,
|
|
99
|
-
settings=vault_settings.
|
|
99
|
+
settings=vault_settings.model_dump(by_alias=True),
|
|
100
100
|
)
|
|
101
101
|
|
|
102
102
|
test_yaml_spec = yaml.safe_load(test_raw_yaml)
|