You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polaris.apache.org by di...@apache.org on 2026/08/11 21:11:23 UTC
(polaris) branch main updated: Preserve setup entity properties in exports (#5265)
This is an automated email from the ASF dual-hosted git repository.
dimas-b pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git
The following commit(s) were added to refs/heads/main by this push:
new 1301f89938 Preserve setup entity properties in exports (#5265)
1301f89938 is described below
commit 1301f89938b1037e8937831f4579e0ed23949b98
Author: Matt Faltyn <76...@users.noreply.github.com>
AuthorDate: Tue Aug 11 23:11:17 2026 +0200
Preserve setup entity properties in exports (#5265)
Keep principal and catalog-role properties in setup exports so backup and migration round trips do not drop user-defined metadata.
Fixes #5264
---
CHANGELOG.md | 2 +
client/python/apache_polaris/cli/command/setup.py | 4 ++
client/python/tests/test_setup_command.py | 79 +++++++++++++++++++++-
.../assets/polaris/reference-setup-config.yaml | 7 +-
.../unreleased/getting-started/setup-tools.md | 3 +-
5 files changed, 91 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b3e942a7eb..38abee8da9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -46,6 +46,8 @@ request adding CHANGELOG notes for breaking (!) changes and possibly other secti
### Fixes
+- Python CLI `setup export` now preserves user-defined properties on principals and catalog roles,
+ so exported configurations restore that metadata during `setup apply`.
- Python CLI `setup apply` no longer double-encodes policy content emitted by `setup export`, so
exported configurations containing policies can be restored.
- Python CLI `setup export` now includes nested namespaces and policy definitions from those
diff --git a/client/python/apache_polaris/cli/command/setup.py b/client/python/apache_polaris/cli/command/setup.py
index 50522979a0..03a8528eab 100644
--- a/client/python/apache_polaris/cli/command/setup.py
+++ b/client/python/apache_polaris/cli/command/setup.py
@@ -171,6 +171,8 @@ class SetupCommand(Command):
principals = sorted(api.list_principals().principals, key=lambda p: p.name)
for p in principals:
principal_info: Dict[str, Any] = {"type": PrincipalType.SERVICE.value}
+ if p.properties:
+ principal_info["properties"] = p.properties
try:
assigned_roles = api.list_principal_roles_assigned(p.name).roles
if assigned_roles:
@@ -396,6 +398,8 @@ class SetupCommand(Command):
)
for r in roles:
role_info: Dict[str, Any] = {}
+ if r.properties:
+ role_info["properties"] = r.properties
# Assignments
assigned_roles_resp = (
api.list_assignee_principal_roles_for_catalog_role(
diff --git a/client/python/tests/test_setup_command.py b/client/python/tests/test_setup_command.py
index fe894fb40f..adb75c6623 100644
--- a/client/python/tests/test_setup_command.py
+++ b/client/python/tests/test_setup_command.py
@@ -306,6 +306,84 @@ class TestSetupCommand(CLITestBase):
mock_client.list_catalog_roles.assert_called_with("my_catalog")
mock_client.get_catalog.assert_called_with("my_catalog")
+ def test_setup_exported_entity_properties_round_trip_through_apply(self) -> None:
+ principal_properties = {"owner": "data-platform"}
+ catalog_role_properties = {"purpose": "migration"}
+ export_client = self.build_mock_client()
+ export_client.list_principals.return_value = SimpleNamespace(
+ principals=[
+ SimpleNamespace(
+ name="service-user",
+ properties=principal_properties,
+ )
+ ]
+ )
+ export_client.list_principal_roles_assigned.return_value = SimpleNamespace(
+ roles=[]
+ )
+ export_client.list_catalog_roles.return_value = SimpleNamespace(
+ roles=[
+ SimpleNamespace(
+ name="catalog-reader",
+ properties=catalog_role_properties,
+ )
+ ]
+ )
+ export_client.list_assignee_principal_roles_for_catalog_role.return_value = (
+ SimpleNamespace(roles=[])
+ )
+ export_client.list_grants_for_catalog_role.return_value = SimpleNamespace(
+ grants=[]
+ )
+ export_command = SetupCommand(setup_subcommand=Subcommands.EXPORT)
+
+ exported = {
+ "principals": export_command._export_principals(export_client),
+ "catalog_roles": export_command._export_catalog_roles_for_catalog(
+ export_client, "catalog"
+ ),
+ }
+ loaded = yaml.safe_load(yaml.safe_dump(exported))
+
+ self.assertEqual(
+ loaded["principals"]["service-user"]["properties"],
+ principal_properties,
+ )
+ self.assertEqual(
+ loaded["catalog_roles"]["catalog-reader"]["properties"],
+ catalog_role_properties,
+ )
+
+ apply_client = self.build_mock_client()
+ apply_client.list_principals.return_value = SimpleNamespace(principals=[])
+ apply_client.list_catalog_roles.return_value = SimpleNamespace(roles=[])
+ apply_client.create_principal.return_value = SimpleNamespace(
+ credentials=SimpleNamespace(
+ client_id="client-id",
+ client_secret=SimpleNamespace(get_secret_value=lambda: "secret"),
+ )
+ )
+ apply_command = SetupCommand(setup_subcommand=Subcommands.APPLY)
+
+ with patch("sys.stdout", new_callable=io.StringIO):
+ apply_command._create_principals(apply_client, loaded["principals"])
+ apply_command._create_catalog_roles(
+ apply_client,
+ "catalog",
+ loaded["catalog_roles"],
+ )
+
+ principal_request = apply_client.create_principal.call_args.args[0]
+ catalog_role_request = apply_client.create_catalog_role.call_args.args[1]
+ self.assertEqual(
+ principal_request.principal.properties,
+ principal_properties,
+ )
+ self.assertEqual(
+ catalog_role_request.catalog_role.properties,
+ catalog_role_properties,
+ )
+
@patch("apache_polaris.cli.command.setup.os.path.isfile")
def test_setup_apply_treats_null_type_as_internal(
self, mock_isfile: MagicMock
@@ -603,4 +681,3 @@ class TestSetupCommand(CLITestBase):
self.assertEqual(
created.storage_config_info.sts_endpoint, "https://sts.amazonaws.com"
)
-
diff --git a/site/content/guides/assets/polaris/reference-setup-config.yaml b/site/content/guides/assets/polaris/reference-setup-config.yaml
index 8bcf8a76cb..fe5c0c6243 100644
--- a/site/content/guides/assets/polaris/reference-setup-config.yaml
+++ b/site/content/guides/assets/polaris/reference-setup-config.yaml
@@ -33,6 +33,9 @@ principals:
# A principal for a quickstart user
quickstart_user:
type: service
+ # Optional properties persisted with the principal.
+ properties:
+ owner: data-platform
roles:
- quickstart_user_role
# A principal for a readonly user
@@ -75,6 +78,9 @@ catalogs:
# Catalog roles are scoped to this specific catalog.
roles:
quickstart_catalog_role:
+ # Optional properties persisted with the catalog role.
+ properties:
+ purpose: catalog-administration
# Assigns this catalog role to one or more principal roles.
assign_to:
- quickstart_user_role
@@ -227,4 +233,3 @@ catalogs:
# service_account: "quickstart-service-account@gcs-project.iam.gserviceaccount.com"
# properties:
# catalog: quickstart_catalog_gcs
-
diff --git a/site/content/in-dev/unreleased/getting-started/setup-tools.md b/site/content/in-dev/unreleased/getting-started/setup-tools.md
index c96e8eb050..2d5a509a84 100644
--- a/site/content/in-dev/unreleased/getting-started/setup-tools.md
+++ b/site/content/in-dev/unreleased/getting-started/setup-tools.md
@@ -40,7 +40,7 @@ If you already have an Apache Polaris environment, you can export its current st
polaris setup export --client-id ${CLIENT_ID} --client-secret ${CLIENT_SECRET} > polaris_bootstrap.yaml
```
-This generates a readable YAML file containing principals, principal roles, catalogs, and their associated namespaces and catalog roles.
+This generates a readable YAML file containing principals, principal roles, catalogs, and their associated namespaces and catalog roles. User-defined properties on principals and catalog roles are preserved in the exported configuration.
## Applying a Configuration
@@ -104,4 +104,3 @@ The current implementation focuses on simplifying initial setup, with a few limi
- **Policy attachment export**: Policy attachments are not included in `setup export` due to performance considerations. However, they can still be defined in YAML and applied during `setup apply`.
- **External catalog testing**: Support for external catalogs (e.g., Hive Metastore) exists, but full end-to-end testing has not yet been completed. It is recommended to validate configurations in a non-production environment first.
-