qontract-reconcile 0.10.2.dev394__py3-none-any.whl → 0.10.2.dev414__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.dev414.dist-info}/METADATA +4 -3
- {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/RECORD +308 -308
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +15 -12
- reconcile/aus/base.py +9 -13
- reconcile/aus/cluster_version_data.py +15 -5
- reconcile/aus/models.py +1 -1
- reconcile/automated_actions/config/integration.py +15 -3
- 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/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 +19 -7
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +6 -6
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +2 -2
- reconcile/external_resources/state.py +56 -14
- 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 +5 -5
- 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 +23 -23
- reconcile/openshift_base.py +53 -2
- 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 +5 -5
- 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 +1 -1
- 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/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 +1 -1
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +39 -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 +112 -92
- 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/runtime/integration.py +1 -1
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +23 -20
- reconcile/utils/saasherder/saasherder.py +26 -17
- 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 +4 -11
- 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 +3 -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.dev414.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev394.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/entry_points.txt +0 -0
|
@@ -7,12 +7,7 @@ from enum import StrEnum
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
9
|
import semver
|
|
10
|
-
from pydantic import
|
|
11
|
-
BaseModel,
|
|
12
|
-
ValidationError,
|
|
13
|
-
root_validator,
|
|
14
|
-
validator,
|
|
15
|
-
)
|
|
10
|
+
from pydantic import BaseModel, ValidationError, field_validator, model_validator
|
|
16
11
|
|
|
17
12
|
from reconcile.aws_version_sync.merge_request_manager.merge_request import (
|
|
18
13
|
Renderer,
|
|
@@ -81,7 +76,7 @@ class SupportedResourceProvider(StrEnum):
|
|
|
81
76
|
ELASTICACHE = "elasticache"
|
|
82
77
|
|
|
83
78
|
|
|
84
|
-
class ExternalResource(BaseModel):
|
|
79
|
+
class ExternalResource(BaseModel, arbitrary_types_allowed=True):
|
|
85
80
|
namespace_file: str | None = None
|
|
86
81
|
provider: str = "aws"
|
|
87
82
|
provisioner: ExternalResourceProvisioner
|
|
@@ -94,9 +89,6 @@ class ExternalResource(BaseModel):
|
|
|
94
89
|
# used to map AWS cache name to resource_identifier
|
|
95
90
|
redis_replication_group_id: str | None = None
|
|
96
91
|
|
|
97
|
-
class Config:
|
|
98
|
-
arbitrary_types_allowed = True
|
|
99
|
-
|
|
100
92
|
@property
|
|
101
93
|
def key(self) -> tuple:
|
|
102
94
|
return (
|
|
@@ -106,7 +98,8 @@ class ExternalResource(BaseModel):
|
|
|
106
98
|
self.resource_identifier,
|
|
107
99
|
)
|
|
108
100
|
|
|
109
|
-
@
|
|
101
|
+
@field_validator("resource_engine_version", mode="before")
|
|
102
|
+
@classmethod
|
|
110
103
|
def parse_resource_engine_version(
|
|
111
104
|
cls, v: str | semver.VersionInfo
|
|
112
105
|
) -> semver.VersionInfo:
|
|
@@ -114,7 +107,8 @@ class ExternalResource(BaseModel):
|
|
|
114
107
|
return v
|
|
115
108
|
return parse_semver(str(v), optional_minor_and_patch=True)
|
|
116
109
|
|
|
117
|
-
@
|
|
110
|
+
@model_validator(mode="before")
|
|
111
|
+
@classmethod
|
|
118
112
|
def set_resource_engine_version_format(cls, values: dict) -> dict:
|
|
119
113
|
resource_engine_version, resource_engine_version_format = (
|
|
120
114
|
str(values.get("resource_engine_version")),
|
|
@@ -62,8 +62,8 @@ class QontractServerDatafileDiff(BaseModel):
|
|
|
62
62
|
|
|
63
63
|
datafilepath: str
|
|
64
64
|
datafileschema: str
|
|
65
|
-
old: dict[str, Any] | None
|
|
66
|
-
new: dict[str, Any] | None
|
|
65
|
+
old: dict[str, Any] | None = None
|
|
66
|
+
new: dict[str, Any] | None = None
|
|
67
67
|
|
|
68
68
|
@property
|
|
69
69
|
def old_datafilepath(self) -> str | None:
|
|
@@ -119,7 +119,7 @@ class QontractServerResourcefileDiffState(BaseModel):
|
|
|
119
119
|
content: str
|
|
120
120
|
resourcefileschema: str | None = Field(..., alias="$schema")
|
|
121
121
|
sha256sum: str
|
|
122
|
-
backrefs: list[QontractServerResourcefileBackref] | None
|
|
122
|
+
backrefs: list[QontractServerResourcefileBackref] | None = None
|
|
123
123
|
|
|
124
124
|
|
|
125
125
|
class QontractServerResourcefileDiff(BaseModel):
|
|
@@ -155,7 +155,8 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
|
|
|
155
155
|
changes = aggregate_resource_changes(
|
|
156
156
|
bundle_changes=aggregate_file_moves(parse_bundle_changes(diff)),
|
|
157
157
|
content_store={
|
|
158
|
-
c.path: c.
|
|
158
|
+
c.path: c.model_dump(by_alias=True)
|
|
159
|
+
for c in namespaces + jenkins_configs
|
|
159
160
|
},
|
|
160
161
|
supported_schemas={
|
|
161
162
|
"/openshift/namespace-1.yml",
|
|
@@ -239,4 +240,4 @@ class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationPara
|
|
|
239
240
|
change_log.items, key=lambda i: i.merged_at, reverse=True
|
|
240
241
|
)
|
|
241
242
|
if not dry_run:
|
|
242
|
-
integration_state.add(BUNDLE_DIFFS_OBJ, change_log.
|
|
243
|
+
integration_state.add(BUNDLE_DIFFS_OBJ, change_log.model_dump(), force=True)
|
|
@@ -140,7 +140,7 @@ def write_coverage_report_to_mr(
|
|
|
140
140
|
approver_reachability = set()
|
|
141
141
|
for d in change_decisions:
|
|
142
142
|
approvers = [
|
|
143
|
-
f"{cr.context} - {' '.join([f'@{a.org_username}' if a.tag_on_merge_requests else a.org_username for a in cr.approvers])}"
|
|
143
|
+
f"{cr.context} - {' '.join([f'@{a.org_username}' if (a.tag_on_merge_requests or len(cr.approvers) == 1) else a.org_username for a in cr.approvers])}"
|
|
144
144
|
for cr in d.change_responsibles
|
|
145
145
|
]
|
|
146
146
|
if d.coverable_by_fragment_decisions:
|
reconcile/dashdotdb_dora.py
CHANGED
reconcile/dashdotdb_slo.py
CHANGED
|
@@ -61,20 +61,19 @@ def get_database_access_namespaces(
|
|
|
61
61
|
return query(query_func).namespaces_v1 or []
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
class DatabaseConnectionParameters(
|
|
64
|
+
class DatabaseConnectionParameters(
|
|
65
|
+
BaseModel, validate_by_name=True, validate_by_alias=True
|
|
66
|
+
):
|
|
65
67
|
host: str = Field(..., alias="db.host")
|
|
66
68
|
port: str = Field(..., alias="db.port")
|
|
67
69
|
user: str = Field(..., alias="db.user")
|
|
68
70
|
password: str = Field(..., alias="db.password")
|
|
69
71
|
database: str = Field(..., alias="db.name")
|
|
70
72
|
|
|
71
|
-
class Config:
|
|
72
|
-
allow_population_by_field_name = True
|
|
73
|
-
|
|
74
73
|
|
|
75
74
|
class PSQLScriptGenerator(BaseModel):
|
|
76
75
|
db_access: DatabaseAccessV1
|
|
77
|
-
current_db_access: DatabaseAccessV1 | None
|
|
76
|
+
current_db_access: DatabaseAccessV1 | None = None
|
|
78
77
|
connection_parameter: DatabaseConnectionParameters
|
|
79
78
|
admin_connection_parameter: DatabaseConnectionParameters
|
|
80
79
|
engine: str
|
|
@@ -597,7 +596,7 @@ def _process_db_access(
|
|
|
597
596
|
current_db_access: DatabaseAccessV1 | None = None
|
|
598
597
|
if state.exists(state_key):
|
|
599
598
|
current_state = state.get(state_key)
|
|
600
|
-
if current_state == db_access.
|
|
599
|
+
if current_state == db_access.model_dump(by_alias=True):
|
|
601
600
|
return
|
|
602
601
|
current_db_access = DatabaseAccessV1(**current_state)
|
|
603
602
|
if current_db_access.database != db_access.database:
|
|
@@ -610,7 +609,7 @@ def _process_db_access(
|
|
|
610
609
|
|
|
611
610
|
resource_prefix = f"dbam-{state_key.replace('/', '-')}"
|
|
612
611
|
with OC_Map(
|
|
613
|
-
clusters=[namespace.cluster.
|
|
612
|
+
clusters=[namespace.cluster.model_dump(by_alias=True)],
|
|
614
613
|
integration=QONTRACT_INTEGRATION,
|
|
615
614
|
settings=settings,
|
|
616
615
|
) as oc_map:
|
|
@@ -677,7 +676,7 @@ def _process_db_access(
|
|
|
677
676
|
if not dry_run and not db_access.delete:
|
|
678
677
|
secret = {
|
|
679
678
|
"path": f"{vault_output_path}/{QONTRACT_INTEGRATION}/{state_key}",
|
|
680
|
-
"data": connections["user"].
|
|
679
|
+
"data": connections["user"].model_dump(by_alias=True),
|
|
681
680
|
}
|
|
682
681
|
vault_client.write(secret, decode_base64=False)
|
|
683
682
|
logging.debug("job completed, cleaning up")
|
|
@@ -693,7 +692,7 @@ def _process_db_access(
|
|
|
693
692
|
)
|
|
694
693
|
state.add(
|
|
695
694
|
state_key,
|
|
696
|
-
value=db_access.
|
|
695
|
+
value=db_access.model_dump(by_alias=True),
|
|
697
696
|
force=True,
|
|
698
697
|
)
|
|
699
698
|
else:
|
|
@@ -82,7 +82,7 @@ class DynatraceTokenProviderIntegration(QontractReconcileIntegration[NoParams]):
|
|
|
82
82
|
return {
|
|
83
83
|
"version": QONTRACT_INTEGRATION_VERSION,
|
|
84
84
|
"specs": {
|
|
85
|
-
spec.name: spec.
|
|
85
|
+
spec.name: spec.model_dump()
|
|
86
86
|
for spec in get_dynatrace_token_provider_token_specs()
|
|
87
87
|
},
|
|
88
88
|
}
|
|
@@ -150,7 +150,10 @@ class EndpointsDiscoveryIntegration(
|
|
|
150
150
|
return []
|
|
151
151
|
|
|
152
152
|
routes = defaultdict(list)
|
|
153
|
-
for item in oc.get_items(
|
|
153
|
+
for item in oc.get_items(
|
|
154
|
+
kind="Route.route.openshift.io",
|
|
155
|
+
namespace=namespace.name,
|
|
156
|
+
):
|
|
154
157
|
tls = bool(item["spec"].get("tls"))
|
|
155
158
|
host = item["spec"]["host"]
|
|
156
159
|
# group all routes with the same hostname/tls
|
|
@@ -89,7 +89,7 @@ class Renderer:
|
|
|
89
89
|
|
|
90
90
|
def render_description(self, hash: str) -> str:
|
|
91
91
|
"""Render the description for a merge request."""
|
|
92
|
-
return DESC.safe_substitute(EPDInfo(hash=hash).
|
|
92
|
+
return DESC.safe_substitute(EPDInfo(hash=hash).model_dump())
|
|
93
93
|
|
|
94
94
|
def render_title(self) -> str:
|
|
95
95
|
"""Render the title for a merge request."""
|
|
@@ -45,7 +45,7 @@ from reconcile.utils.secret_reader import SecretReaderBase, create_secret_reader
|
|
|
45
45
|
def fetch_current_state(
|
|
46
46
|
ri: ResourceInventory, oc: OCCli, cluster: str, namespace: str
|
|
47
47
|
) -> None:
|
|
48
|
-
for item in oc.get_items("Job", namespace=namespace):
|
|
48
|
+
for item in oc.get_items("Job.batch", namespace=namespace):
|
|
49
49
|
r = OpenshiftResource(item, QONTRACT_INTEGRATION, QONTRACT_INTEGRATION_VERSION)
|
|
50
50
|
ri.add_current(cluster, namespace, "Job", r.name, r)
|
|
51
51
|
|
|
@@ -45,6 +45,7 @@ from reconcile.utils.datetime_util import utc_now
|
|
|
45
45
|
from reconcile.utils.external_resource_spec import (
|
|
46
46
|
ExternalResourceSpec,
|
|
47
47
|
)
|
|
48
|
+
from reconcile.utils.json import json_dumps
|
|
48
49
|
from reconcile.utils.secret_reader import SecretReaderBase
|
|
49
50
|
|
|
50
51
|
|
|
@@ -244,7 +245,7 @@ class ExternalResourcesManager:
|
|
|
244
245
|
reconciliation = Reconciliation(
|
|
245
246
|
key=key,
|
|
246
247
|
resource_hash=resource.hash(),
|
|
247
|
-
input=resource
|
|
248
|
+
input=json_dumps(resource),
|
|
248
249
|
action=Action.APPLY,
|
|
249
250
|
module_configuration=module_conf,
|
|
250
251
|
linked_resources=self._find_linked_resources(spec),
|
|
@@ -252,11 +253,15 @@ class ExternalResourcesManager:
|
|
|
252
253
|
r.add(reconciliation)
|
|
253
254
|
return r
|
|
254
255
|
|
|
255
|
-
def _get_deleted_objects_reconciliations(
|
|
256
|
+
def _get_deleted_objects_reconciliations(
|
|
257
|
+
self, enable_migration: bool = False
|
|
258
|
+
) -> set[Reconciliation]:
|
|
256
259
|
to_reconcile: set[Reconciliation] = set()
|
|
257
260
|
deleted_keys = (k for k, v in self.er_inventory.items() if v.marked_to_delete)
|
|
258
261
|
for key in deleted_keys:
|
|
259
|
-
state = self.state_mgr.get_external_resource_state(
|
|
262
|
+
state = self.state_mgr.get_external_resource_state(
|
|
263
|
+
key, enable_migration=enable_migration
|
|
264
|
+
)
|
|
260
265
|
if state.resource_status == ResourceStatus.NOT_EXISTS:
|
|
261
266
|
logging.debug("Resource has already been removed. key: %s", key)
|
|
262
267
|
continue
|
|
@@ -349,7 +354,9 @@ class ExternalResourcesManager:
|
|
|
349
354
|
|
|
350
355
|
if r.linked_resources:
|
|
351
356
|
for lr in r.linked_resources:
|
|
352
|
-
lrs = self.state_mgr.get_external_resource_state(
|
|
357
|
+
lrs = self.state_mgr.get_external_resource_state(
|
|
358
|
+
lr, enable_migration=True
|
|
359
|
+
)
|
|
353
360
|
if not lrs.resource_status.is_in_progress:
|
|
354
361
|
lrs.resource_status = ResourceStatus.RECONCILIATION_REQUESTED
|
|
355
362
|
self.state_mgr.set_external_resource_state(lrs)
|
|
@@ -416,10 +423,12 @@ class ExternalResourcesManager:
|
|
|
416
423
|
|
|
417
424
|
def handle_resources(self) -> None:
|
|
418
425
|
desired_r = self._get_desired_objects_reconciliations()
|
|
419
|
-
deleted_r = self._get_deleted_objects_reconciliations()
|
|
426
|
+
deleted_r = self._get_deleted_objects_reconciliations(enable_migration=True)
|
|
420
427
|
to_sync_keys: set[ExternalResourceKey] = set()
|
|
421
428
|
for r in desired_r.union(deleted_r):
|
|
422
|
-
state = self.state_mgr.get_external_resource_state(
|
|
429
|
+
state = self.state_mgr.get_external_resource_state(
|
|
430
|
+
r.key, enable_migration=True
|
|
431
|
+
)
|
|
423
432
|
reconciliation_status = self._get_reconciliation_status(r, state)
|
|
424
433
|
self._update_resource_state(r, state, reconciliation_status)
|
|
425
434
|
|
|
@@ -450,7 +459,10 @@ class ExternalResourcesManager:
|
|
|
450
459
|
r
|
|
451
460
|
for r in desired_r.union(deleted_r)
|
|
452
461
|
if self._reconciliation_needs_dry_run_run(
|
|
453
|
-
r,
|
|
462
|
+
r,
|
|
463
|
+
self.state_mgr.get_external_resource_state(
|
|
464
|
+
key=r.key, enable_migration=False
|
|
465
|
+
),
|
|
454
466
|
)
|
|
455
467
|
}
|
|
456
468
|
|
|
@@ -13,7 +13,7 @@ from reconcile.utils.metrics import (
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class ExternalResourcesBaseMetric(BaseModel):
|
|
16
|
-
integration = normalize_integration_name(QONTRACT_INTEGRATION)
|
|
16
|
+
integration: str = normalize_integration_name(QONTRACT_INTEGRATION)
|
|
17
17
|
app: str
|
|
18
18
|
environment: str
|
|
19
19
|
provision_provider: str
|
|
@@ -89,7 +89,7 @@ class ExternalResourceKey(BaseModel, frozen=True):
|
|
|
89
89
|
)
|
|
90
90
|
|
|
91
91
|
def hash(self) -> str:
|
|
92
|
-
return hashlib.md5(json_dumps(self.
|
|
92
|
+
return hashlib.md5(json_dumps(self.model_dump()).encode("utf-8")).hexdigest()
|
|
93
93
|
|
|
94
94
|
@property
|
|
95
95
|
def state_path(self) -> str:
|
|
@@ -138,15 +138,15 @@ class ExternalResourcesInventory(MutableMapping):
|
|
|
138
138
|
) -> ExternalResourceSpec:
|
|
139
139
|
spec = ExternalResourceSpec(
|
|
140
140
|
provision_provider=provider.provider,
|
|
141
|
-
provisioner=provider.provisioner.
|
|
142
|
-
resource=resource.
|
|
141
|
+
provisioner=provider.provisioner.model_dump(),
|
|
142
|
+
resource=resource.model_dump(
|
|
143
143
|
exclude={
|
|
144
144
|
FLAG_RESOURCE_MANAGED_BY_ERV2,
|
|
145
145
|
FLAG_DELETE_RESOURCE,
|
|
146
146
|
MODULE_OVERRIDES,
|
|
147
147
|
}
|
|
148
148
|
),
|
|
149
|
-
namespace=namespace.
|
|
149
|
+
namespace=namespace.model_dump(by_alias=True),
|
|
150
150
|
)
|
|
151
151
|
spec.metadata[FLAG_DELETE_RESOURCE] = resource.delete or namespace.delete
|
|
152
152
|
spec.metadata[MODULE_OVERRIDES] = resource.module_overrides
|
|
@@ -387,7 +387,7 @@ class Reconciliation(BaseModel, frozen=True):
|
|
|
387
387
|
)
|
|
388
388
|
# linked_resources store dependants resources. They will get reconciled
|
|
389
389
|
# every time the parent resource reconciliation finishes.
|
|
390
|
-
linked_resources: frozenset[ExternalResourceKey] | None
|
|
390
|
+
linked_resources: frozenset[ExternalResourceKey] | None = None
|
|
391
391
|
|
|
392
392
|
|
|
393
393
|
class ReconcileAction(StrEnum):
|
|
@@ -440,4 +440,4 @@ class ExternalResource(BaseModel):
|
|
|
440
440
|
provision: ExternalResourceProvision
|
|
441
441
|
|
|
442
442
|
def hash(self) -> str:
|
|
443
|
-
return hashlib.
|
|
443
|
+
return hashlib.sha256(json_dumps(self.data).encode("utf-8")).hexdigest()
|
|
@@ -70,10 +70,13 @@ class ReconciliationK8sJob(K8sJob, BaseModel, frozen=True):
|
|
|
70
70
|
dry_run_suffix: str = ""
|
|
71
71
|
|
|
72
72
|
def name_prefix(self) -> str:
|
|
73
|
+
identifier = (
|
|
74
|
+
f"{self.reconciliation.key.provider}-{self.reconciliation.key.identifier}"
|
|
75
|
+
)
|
|
73
76
|
if self.is_dry_run:
|
|
74
|
-
return f"er-dry-run-mr-{self.dry_run_suffix}"
|
|
77
|
+
return f"er-dry-run-mr-{self.dry_run_suffix}-{identifier}"
|
|
75
78
|
else:
|
|
76
|
-
return "er"
|
|
79
|
+
return f"er-{identifier}"
|
|
77
80
|
|
|
78
81
|
def unit_of_work_identity(self) -> Any:
|
|
79
82
|
return self.reconciliation.key
|
|
@@ -96,10 +99,10 @@ class ReconciliationK8sJob(K8sJob, BaseModel, frozen=True):
|
|
|
96
99
|
image=self.reconciliation.module_configuration.image_version,
|
|
97
100
|
image_pull_policy="Always",
|
|
98
101
|
resources=V1ResourceRequirements(
|
|
99
|
-
requests=self.reconciliation.module_configuration.resources.requests.
|
|
102
|
+
requests=self.reconciliation.module_configuration.resources.requests.model_dump(
|
|
100
103
|
exclude_none=True
|
|
101
104
|
),
|
|
102
|
-
limits=self.reconciliation.module_configuration.resources.limits.
|
|
105
|
+
limits=self.reconciliation.module_configuration.resources.limits.model_dump(
|
|
103
106
|
exclude_none=True
|
|
104
107
|
),
|
|
105
108
|
),
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
from collections.abc import Mapping
|
|
3
4
|
from datetime import datetime
|
|
4
5
|
from enum import StrEnum
|
|
6
|
+
from hashlib import sha256
|
|
5
7
|
from typing import Any
|
|
6
8
|
|
|
7
9
|
from pydantic import BaseModel
|
|
@@ -17,6 +19,7 @@ from reconcile.external_resources.model import (
|
|
|
17
19
|
)
|
|
18
20
|
from reconcile.utils.aws_api_typed.api import AWSApi
|
|
19
21
|
from reconcile.utils.datetime_util import to_utc_microseconds_iso_format, utc_now
|
|
22
|
+
from reconcile.utils.json import json_dumps
|
|
20
23
|
|
|
21
24
|
DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
|
|
22
25
|
|
|
@@ -170,7 +173,7 @@ class DynamoDBStateAdapter:
|
|
|
170
173
|
|
|
171
174
|
def serialize(self, state: ExternalResourceState) -> dict[str, Any]:
|
|
172
175
|
return {
|
|
173
|
-
self.ER_KEY_HASH: {"S": state.key.
|
|
176
|
+
self.ER_KEY_HASH: {"S": state.key.state_path},
|
|
174
177
|
self.TIMESTAMP: {"S": to_utc_microseconds_iso_format(state.ts)},
|
|
175
178
|
self.RESOURCE_STATUS: {"S": state.resource_status.value},
|
|
176
179
|
self.ER_KEY: {
|
|
@@ -259,24 +262,63 @@ class ExternalResourcesStateDynamoDB:
|
|
|
259
262
|
self._table = table_name
|
|
260
263
|
self.partial_resources = self._get_partial_resources()
|
|
261
264
|
|
|
265
|
+
def _new_sha256_hash(self, item: dict) -> str:
|
|
266
|
+
resource_json = item[self.adapter.RECONC]["M"][self.adapter.RECONC_INPUT]["S"]
|
|
267
|
+
resource_dict = json.loads(resource_json)
|
|
268
|
+
data = resource_dict["data"]
|
|
269
|
+
return sha256(json_dumps(data).encode("utf-8")).hexdigest()
|
|
270
|
+
|
|
262
271
|
def get_external_resource_state(
|
|
263
|
-
self,
|
|
272
|
+
self,
|
|
273
|
+
key: ExternalResourceKey,
|
|
274
|
+
enable_migration: bool = False,
|
|
264
275
|
) -> ExternalResourceState:
|
|
265
276
|
data = self.aws_api.dynamodb.boto3_client.get_item(
|
|
266
277
|
TableName=self._table,
|
|
267
278
|
ConsistentRead=True,
|
|
268
|
-
Key={self.adapter.ER_KEY_HASH: {"S": key.
|
|
279
|
+
Key={self.adapter.ER_KEY_HASH: {"S": key.state_path}},
|
|
269
280
|
)
|
|
270
|
-
|
|
281
|
+
item = data.get("Item")
|
|
282
|
+
if item:
|
|
271
283
|
return self.adapter.deserialize(data["Item"])
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
284
|
+
|
|
285
|
+
old_data = self.aws_api.dynamodb.boto3_client.get_item(
|
|
286
|
+
TableName=self._table,
|
|
287
|
+
ConsistentRead=True,
|
|
288
|
+
Key={self.adapter.ER_KEY_HASH: {"S": key.hash()}},
|
|
289
|
+
)
|
|
290
|
+
old_item = old_data.get("Item")
|
|
291
|
+
if old_item:
|
|
292
|
+
old_item[self.adapter.ER_KEY_HASH]["S"] = key.state_path
|
|
293
|
+
old_item[self.adapter.RECONC]["M"][self.adapter.RECONC_RESOURCE_HASH][
|
|
294
|
+
"S"
|
|
295
|
+
] = self._new_sha256_hash(old_item)
|
|
296
|
+
if enable_migration:
|
|
297
|
+
self.aws_api.dynamodb.boto3_client.transact_write_items(
|
|
298
|
+
TransactItems=[
|
|
299
|
+
{
|
|
300
|
+
"Put": {
|
|
301
|
+
"TableName": self._table,
|
|
302
|
+
"Item": old_item,
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"Delete": {
|
|
307
|
+
"TableName": self._table,
|
|
308
|
+
"Key": {self.adapter.ER_KEY_HASH: {"S": key.hash()}},
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
]
|
|
312
|
+
)
|
|
313
|
+
return self.adapter.deserialize(old_item)
|
|
314
|
+
|
|
315
|
+
return ExternalResourceState(
|
|
316
|
+
key=key,
|
|
317
|
+
ts=utc_now(),
|
|
318
|
+
resource_status=ResourceStatus.NOT_EXISTS,
|
|
319
|
+
reconciliation=Reconciliation(key=key),
|
|
320
|
+
reconciliation_errors=0,
|
|
321
|
+
)
|
|
280
322
|
|
|
281
323
|
def set_external_resource_state(
|
|
282
324
|
self,
|
|
@@ -289,7 +331,7 @@ class ExternalResourcesStateDynamoDB:
|
|
|
289
331
|
def del_external_resource_state(self, key: ExternalResourceKey) -> None:
|
|
290
332
|
self.aws_api.dynamodb.boto3_client.delete_item(
|
|
291
333
|
TableName=self._table,
|
|
292
|
-
Key={self.adapter.ER_KEY_HASH: {"S": key.
|
|
334
|
+
Key={self.adapter.ER_KEY_HASH: {"S": key.state_path}},
|
|
293
335
|
)
|
|
294
336
|
|
|
295
337
|
def _get_partial_resources(
|
|
@@ -331,7 +373,7 @@ class ExternalResourcesStateDynamoDB:
|
|
|
331
373
|
) -> None:
|
|
332
374
|
self.aws_api.dynamodb.boto3_client.update_item(
|
|
333
375
|
TableName=self._table,
|
|
334
|
-
Key={self.adapter.ER_KEY_HASH: {"S": key.
|
|
376
|
+
Key={self.adapter.ER_KEY_HASH: {"S": key.state_path}},
|
|
335
377
|
UpdateExpression="set resource_status=:new_value",
|
|
336
378
|
ExpressionAttributeValues={":new_value": {"S": status.value}},
|
|
337
379
|
ReturnValues="UPDATED_NEW",
|
|
@@ -58,7 +58,7 @@ class FleetLabelerIntegration(QontractReconcileIntegration[NoParams]):
|
|
|
58
58
|
"""Return the desired state for early exit."""
|
|
59
59
|
return {
|
|
60
60
|
"version": QONTRACT_INTEGRATION_VERSION,
|
|
61
|
-
"specs": {spec.name: spec.
|
|
61
|
+
"specs": {spec.name: spec.model_dump() for spec in get_fleet_label_specs()},
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
def run(self, dry_run: bool) -> None:
|
reconcile/gcp_image_mirror.py
CHANGED
|
@@ -132,7 +132,7 @@ class QuayMirror:
|
|
|
132
132
|
mirror_creds = None
|
|
133
133
|
pull_credentials = item.mirror.pull_credentials
|
|
134
134
|
if pull_credentials:
|
|
135
|
-
raw_data = self.secret_reader.read_all(pull_credentials.
|
|
135
|
+
raw_data = self.secret_reader.read_all(pull_credentials.model_dump())
|
|
136
136
|
username = raw_data["user"]
|
|
137
137
|
password = raw_data["token"]
|
|
138
138
|
mirror_creds = f"{username}:{password}"
|
|
@@ -226,7 +226,7 @@ class QuayMirror:
|
|
|
226
226
|
return False
|
|
227
227
|
|
|
228
228
|
def _decode_push_secret(self, secret: VaultSecret) -> str:
|
|
229
|
-
raw_data = self.secret_reader.read_all(secret.
|
|
229
|
+
raw_data = self.secret_reader.read_all(secret.model_dump())
|
|
230
230
|
token = base64.b64decode(raw_data["token"]).decode()
|
|
231
231
|
return f"{raw_data['user']}:{token}"
|
|
232
232
|
|
reconcile/github_org.py
CHANGED
reconcile/github_owners.py
CHANGED
|
@@ -2,6 +2,7 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
|
|
4
4
|
import github
|
|
5
|
+
import github.NamedUser
|
|
5
6
|
from github import Github
|
|
6
7
|
from sretoolbox.utils import retry
|
|
7
8
|
|
|
@@ -100,4 +101,7 @@ def run(dry_run: bool) -> None:
|
|
|
100
101
|
|
|
101
102
|
if not dry_run:
|
|
102
103
|
gh_user = gh.get_user(github_username)
|
|
104
|
+
assert isinstance(
|
|
105
|
+
gh_user, github.NamedUser.NamedUser
|
|
106
|
+
) # make mypy happy
|
|
103
107
|
gh_org.add_to_members(gh_user, "admin")
|
reconcile/gitlab_members.py
CHANGED
|
@@ -44,19 +44,13 @@ class GitlabUser(BaseModel):
|
|
|
44
44
|
access_level: int
|
|
45
45
|
|
|
46
46
|
|
|
47
|
-
class CurrentStateSpec(BaseModel):
|
|
47
|
+
class CurrentStateSpec(BaseModel, arbitrary_types_allowed=True):
|
|
48
48
|
members: dict[str, GroupMember]
|
|
49
49
|
|
|
50
|
-
class Config:
|
|
51
|
-
arbitrary_types_allowed = True
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
class DesiredStateSpec(BaseModel):
|
|
51
|
+
class DesiredStateSpec(BaseModel, arbitrary_types_allowed=True):
|
|
55
52
|
members: dict[str, GitlabUser]
|
|
56
53
|
|
|
57
|
-
class Config:
|
|
58
|
-
arbitrary_types_allowed = True
|
|
59
|
-
|
|
60
54
|
|
|
61
55
|
CurrentState = dict[str, CurrentStateSpec]
|
|
62
56
|
DesiredState = dict[str, DesiredStateSpec]
|
|
@@ -122,8 +116,8 @@ def build_desired_state_spec(
|
|
|
122
116
|
pagerduty_map,
|
|
123
117
|
get_username_method=lambda u: u.org_username,
|
|
124
118
|
)
|
|
125
|
-
for
|
|
126
|
-
gu = GitlabUser(user=
|
|
119
|
+
for pu in usernames_from_pagerduty:
|
|
120
|
+
gu = GitlabUser(user=pu, access_level=p_access_level)
|
|
127
121
|
add_or_update_user(desired_state_spec, gu)
|
|
128
122
|
return desired_state_spec
|
|
129
123
|
|
|
@@ -239,6 +233,6 @@ def reconcile_gitlab_members(
|
|
|
239
233
|
def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
|
|
240
234
|
gqlapi = gql.get_api()
|
|
241
235
|
return {
|
|
242
|
-
"instance": get_gitlab_instance(gqlapi.query).
|
|
243
|
-
"permissions": [p.
|
|
236
|
+
"instance": get_gitlab_instance(gqlapi.query).model_dump(),
|
|
237
|
+
"permissions": [p.model_dump() for p in get_permissions(gqlapi.query)],
|
|
244
238
|
}
|
reconcile/gitlab_permissions.py
CHANGED
|
@@ -94,14 +94,6 @@ class GroupPermissionHandler:
|
|
|
94
94
|
desired_state: dict[str, GroupSpec],
|
|
95
95
|
current_state: dict[str, GroupSpec],
|
|
96
96
|
) -> None:
|
|
97
|
-
# gather list of app-interface managed repos
|
|
98
|
-
instance = queries.get_gitlab_instance()
|
|
99
|
-
managed_repos = {
|
|
100
|
-
f"{instance['url']}/{project_request['group']}/{r}"
|
|
101
|
-
for project_request in instance.get("projectRequests", [])
|
|
102
|
-
for r in project_request.get("projects", [])
|
|
103
|
-
}
|
|
104
|
-
|
|
105
97
|
# get the diff data
|
|
106
98
|
diff_data = diff_mappings(
|
|
107
99
|
current=current_state,
|
|
@@ -112,11 +104,10 @@ class GroupPermissionHandler:
|
|
|
112
104
|
errors: list[Exception] = []
|
|
113
105
|
for repo in diff_data.add:
|
|
114
106
|
project = self.gl.get_project(repo)
|
|
115
|
-
if not project
|
|
116
|
-
logging.info(
|
|
117
|
-
f"New app-interface managed repository {repo} hasn't been created yet - skipping"
|
|
118
|
-
)
|
|
107
|
+
if not project:
|
|
108
|
+
logging.info(f"{repo} hasn't been created yet - skipping")
|
|
119
109
|
continue
|
|
110
|
+
|
|
120
111
|
if not self.can_share_project(project):
|
|
121
112
|
errors.append(
|
|
122
113
|
GroupAccessLevelError(
|
|
@@ -136,8 +127,13 @@ class GroupPermissionHandler:
|
|
|
136
127
|
group_id=self.group.id,
|
|
137
128
|
access_level=self.access_level,
|
|
138
129
|
)
|
|
130
|
+
|
|
139
131
|
for repo in diff_data.change:
|
|
140
132
|
project = self.gl.get_project(repo)
|
|
133
|
+
if not project:
|
|
134
|
+
logging.info(f"{repo} hasn't been created yet - skipping")
|
|
135
|
+
continue
|
|
136
|
+
|
|
141
137
|
if not self.can_share_project(project):
|
|
142
138
|
errors.append(
|
|
143
139
|
GroupAccessLevelError(
|