This is an automated email from the ASF dual-hosted git repository.
yufei 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 b1f7c68b Policy Store: Add PolicyEntity and PolicyTypes (#1133)
b1f7c68b is described below
commit b1f7c68b1cb29dfdce6b401c0c12b5bf0305a6a5
Author: Honah (Jonas) J. <[email protected]>
AuthorDate: Tue Mar 18 11:38:34 2025 -0700
Policy Store: Add PolicyEntity and PolicyTypes (#1133)
---
.../polaris/core/entity/PolarisEntityType.java | 3 +-
.../apache/polaris/core/policy/PolicyEntity.java | 129 +++++++++++++++++++++
.../org/apache/polaris/core/policy/PolicyType.java | 84 ++++++++++++++
.../polaris/core/policy/PredefinedPolicyTypes.java | 108 +++++++++++++++++
.../polaris/core/persistence/ResolverTest.java | 16 +++
.../polaris/core/policy/PolicyEntityTest.java | 65 +++++++++++
.../apache/polaris/core/policy/PolicyTypeTest.java | 56 +++++++++
.../persistence/PolarisTestMetaStoreManager.java | 105 ++++++++++++++++-
8 files changed, 562 insertions(+), 4 deletions(-)
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java
b/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java
index af50eed6..4a3eada3 100644
---
a/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java
+++
b/polaris-core/src/main/java/org/apache/polaris/core/entity/PolarisEntityType.java
@@ -34,7 +34,8 @@ public enum PolarisEntityType {
// generic table is either a view or a real table
TABLE_LIKE(7, NAMESPACE, false, false),
TASK(8, ROOT, false, false),
- FILE(9, TABLE_LIKE, false, false);
+ FILE(9, TABLE_LIKE, false, false),
+ POLICY(10, NAMESPACE, false, false);
// to efficiently map a code to its corresponding entity type, use a reverse
array which
// is initialized below
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyEntity.java
b/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyEntity.java
new file mode 100644
index 00000000..470822bb
--- /dev/null
+++
b/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyEntity.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.policy;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.common.base.Preconditions;
+import org.apache.iceberg.catalog.Namespace;
+import org.apache.iceberg.rest.RESTUtil;
+import org.apache.polaris.core.entity.NamespaceEntity;
+import org.apache.polaris.core.entity.PolarisBaseEntity;
+import org.apache.polaris.core.entity.PolarisEntity;
+import org.apache.polaris.core.entity.PolarisEntityType;
+
+public class PolicyEntity extends PolarisEntity {
+
+ public static final String POLICY_TYPE_CODE_KEY = "policy-type-code";
+ public static final String POLICY_DESCRIPTION_KEY = "policy-description";
+ public static final String POLICY_VERSION_KEY = "policy-version";
+ public static final String POLICY_CONTENT_KEY = "policy-content";
+
+ PolicyEntity(PolarisBaseEntity sourceEntity) {
+ super(sourceEntity);
+ }
+
+ public static PolicyEntity of(PolarisBaseEntity sourceEntity) {
+ if (sourceEntity != null) {
+ return new PolicyEntity(sourceEntity);
+ }
+
+ return null;
+ }
+
+ @JsonIgnore
+ public PolicyType getPolicyType() {
+ return PolicyType.fromCode(getPolicyTypeCode());
+ }
+
+ @JsonIgnore
+ public int getPolicyTypeCode() {
+ Preconditions.checkArgument(
+ getPropertiesAsMap().containsKey(POLICY_TYPE_CODE_KEY),
+ "Invalid policy entity: policy type must exist");
+ String policyTypeCode = getPropertiesAsMap().get(POLICY_TYPE_CODE_KEY);
+ return Integer.parseInt(policyTypeCode);
+ }
+
+ @JsonIgnore
+ public String getDescription() {
+ return getPropertiesAsMap().get(POLICY_DESCRIPTION_KEY);
+ }
+
+ @JsonIgnore
+ public String getContent() {
+ return getPropertiesAsMap().get(POLICY_CONTENT_KEY);
+ }
+
+ @JsonIgnore
+ public int getPolicyVersion() {
+ return Integer.parseInt(getPropertiesAsMap().get(POLICY_VERSION_KEY));
+ }
+
+ public static class Builder extends PolarisEntity.BaseBuilder<PolicyEntity,
Builder> {
+ public Builder(Namespace namespace, String policyName, PolicyType
policyType) {
+ super();
+ setType(PolarisEntityType.POLICY);
+ setParentNamespace(namespace);
+ setName(policyName);
+ setPolicyType(policyType);
+ setPolicyVersion(0);
+ }
+
+ public Builder(PolicyEntity original) {
+ super(original);
+ }
+
+ @Override
+ public PolicyEntity build() {
+ Preconditions.checkArgument(
+ properties.containsKey(POLICY_TYPE_CODE_KEY), "Policy type must be
specified");
+
+ return new PolicyEntity(buildBase());
+ }
+
+ public Builder setParentNamespace(Namespace namespace) {
+ if (namespace != null && !namespace.isEmpty()) {
+ internalProperties.put(
+ NamespaceEntity.PARENT_NAMESPACE_KEY,
RESTUtil.encodeNamespace(namespace));
+ }
+ return this;
+ }
+
+ public Builder setPolicyType(PolicyType policyType) {
+ Preconditions.checkArgument(policyType != null, "Policy type must be
specified");
+ properties.put(POLICY_TYPE_CODE_KEY,
Integer.toString(policyType.getCode()));
+ return this;
+ }
+
+ public Builder setDescription(String description) {
+ properties.put(POLICY_DESCRIPTION_KEY, description);
+ return this;
+ }
+
+ public Builder setPolicyVersion(int version) {
+ properties.put(POLICY_VERSION_KEY, Integer.toString(version));
+ return this;
+ }
+
+ public Builder setContent(String content) {
+ properties.put(POLICY_CONTENT_KEY, content);
+ return this;
+ }
+ }
+}
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyType.java
b/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyType.java
new file mode 100644
index 00000000..029d5c37
--- /dev/null
+++ b/polaris-core/src/main/java/org/apache/polaris/core/policy/PolicyType.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.policy;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import jakarta.annotation.Nullable;
+
+/**
+ * Represents a policy type in Polaris. A policy type defines a category of
policies that may be
+ * either predefined or custom (user-defined).
+ *
+ * <p>A policy type can be either inheritable or non-inheritable. Inheritable
policies are passed
+ * down to lower-level entities (e.g., from a namespace to a table).
+ */
+public interface PolicyType {
+
+ /**
+ * Retrieves the unique type code associated with this policy type.
+ *
+ * @return the type code of the policy type
+ */
+ @JsonValue
+ int getCode();
+
+ /**
+ * Retrieves the human-readable name of this policy type.
+ *
+ * @return the name of the policy type
+ */
+ String getName();
+
+ /**
+ * Determines whether this policy type is inheritable.
+ *
+ * @return {@code true} if the policy type is inheritable, otherwise {@code
false}
+ */
+ boolean isInheritable();
+
+ /**
+ * Retrieves a {@link PolicyType} instance corresponding to the given type
code.
+ *
+ * <p>This method searches for the policy type in predefined policy types.
If a custom policy type
+ * storage mechanism is implemented in the future, it may also check
registered custom policy
+ * types.
+ *
+ * @param code the type code of the policy type
+ * @return the corresponding {@link PolicyType}, or {@code null} if no
matching type is found
+ */
+ @JsonCreator
+ static @Nullable PolicyType fromCode(int code) {
+ return PredefinedPolicyTypes.fromCode(code);
+ }
+
+ /**
+ * Retrieves a {@link PolicyType} instance corresponding to the given policy
name.
+ *
+ * <p>This method searches for the policy type in predefined policy types.
If a custom policy type
+ * storage mechanism is implemented in the future, it may also check
registered custom policy
+ * types.
+ *
+ * @param name the name of the policy type
+ * @return the corresponding {@link PolicyType}, or {@code null} if no
matching type is found
+ */
+ static @Nullable PolicyType fromName(String name) {
+ return PredefinedPolicyTypes.fromName(name);
+ }
+}
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/policy/PredefinedPolicyTypes.java
b/polaris-core/src/main/java/org/apache/polaris/core/policy/PredefinedPolicyTypes.java
new file mode 100644
index 00000000..babe1ac7
--- /dev/null
+++
b/polaris-core/src/main/java/org/apache/polaris/core/policy/PredefinedPolicyTypes.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.policy;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.google.common.collect.ImmutableMap;
+import jakarta.annotation.Nullable;
+
+/* Represents all predefined policy types in Polaris */
+public enum PredefinedPolicyTypes implements PolicyType {
+ DATA_COMPACTION(0, "system.data-compaction", true),
+ METADATA_COMPACTION(1, "system.metadata-compaction", true),
+ ORPHAN_FILE_REMOVAL(2, "system.orphan-file-removal", true),
+ SNAPSHOT_RETENTION(3, "system.snapshot-retention", true);
+
+ private final int code;
+ private final String name;
+ private final boolean isInheritable;
+ private static final PredefinedPolicyTypes[] REVERSE_CODE_MAPPING_ARRAY;
+ private static final ImmutableMap<String, PredefinedPolicyTypes>
REVERSE_NAME_MAPPING_ARRAY;
+
+ static {
+ int maxId = 0;
+ for (PredefinedPolicyTypes policyType : PredefinedPolicyTypes.values()) {
+ if (maxId < policyType.code) {
+ maxId = policyType.code;
+ }
+ }
+
+ REVERSE_CODE_MAPPING_ARRAY = new PredefinedPolicyTypes[maxId + 1];
+ ImmutableMap.Builder<String, PredefinedPolicyTypes> builder =
ImmutableMap.builder();
+ // populate both
+ for (PredefinedPolicyTypes policyType : PredefinedPolicyTypes.values()) {
+ REVERSE_CODE_MAPPING_ARRAY[policyType.code] = policyType;
+ builder.put(policyType.name, policyType);
+ }
+ REVERSE_NAME_MAPPING_ARRAY = builder.build();
+ }
+
+ PredefinedPolicyTypes(int code, String name, boolean isInheritable) {
+ this.code = code;
+ this.name = name;
+ this.isInheritable = isInheritable;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @JsonValue
+ public int getCode() {
+ return code;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean isInheritable() {
+ return isInheritable;
+ }
+
+ /**
+ * Retrieves a {@link PredefinedPolicyTypes} instance corresponding to the
given type code.
+ *
+ * @param code the type code of the predefined policy type
+ * @return the corresponding {@link PredefinedPolicyTypes}, or {@code null}
if no matching type is
+ * found
+ */
+ @JsonCreator
+ public static @Nullable PredefinedPolicyTypes fromCode(int code) {
+ if (code >= REVERSE_CODE_MAPPING_ARRAY.length) {
+ return null;
+ }
+
+ return REVERSE_CODE_MAPPING_ARRAY[code];
+ }
+
+ /**
+ * Retrieves a {@link PredefinedPolicyTypes} instance corresponding to the
given policy name.
+ *
+ * @param name the name of the predefined policy type
+ * @return the corresponding {@link PredefinedPolicyTypes}, or {@code null}
if no matching type is
+ * found
+ */
+ public static @Nullable PredefinedPolicyTypes fromName(String name) {
+ return REVERSE_NAME_MAPPING_ARRAY.get(name);
+ }
+}
diff --git
a/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java
b/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java
index fbcb2f9c..dd21a16f 100644
---
a/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java
+++
b/polaris-core/src/test/java/org/apache/polaris/core/persistence/ResolverTest.java
@@ -105,6 +105,9 @@ public class ResolverTest {
* - (N1/N4)
* - N5/N6/T5
* - N5/N6/T6
+ * - N7/N8/POL1
+ * - N7/N8/POL2
+ * - N7/POL3
* - R1(TABLE_READ on N1/N2, VIEW_CREATE on C, TABLE_LIST on N2, TABLE_DROP
on N5/N6/T5)
* - R2(TABLE_WRITE_DATA on N5, VIEW_LIST on C)
* - PR1(R1, R2)
@@ -230,6 +233,19 @@ public class ResolverTest {
new ResolverPath(List.of("N5", "N6", "T5"),
PolarisEntityType.TABLE_LIKE);
this.resolveDriver(this.cache, "test", N5_N6_T5, null, null);
+ // N7/N8 which exists
+ ResolverPath N7_N8 = new ResolverPath(List.of("N7", "N8"),
PolarisEntityType.NAMESPACE);
+ this.resolveDriver(this.cache, "test", N7_N8, null, null);
+
+ // N7/N8/POL1 which exists
+ ResolverPath N7_N8_POL1 =
+ new ResolverPath(List.of("N7", "N8", "POL1"),
PolarisEntityType.POLICY);
+ this.resolveDriver(this.cache, "test", N7_N8_POL1, null, null);
+
+ // N7/POL3 which exists
+ ResolverPath N7_POL3 = new ResolverPath(List.of("N7", "POL3"),
PolarisEntityType.POLICY);
+ this.resolveDriver(this.cache, "test", N7_POL3, null, null);
+
// Error scenarios: N5/N6/T8 which does not exists
ResolverPath N5_N6_T8 =
new ResolverPath(List.of("N5", "N6", "T8"),
PolarisEntityType.TABLE_LIKE);
diff --git
a/polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyEntityTest.java
b/polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyEntityTest.java
new file mode 100644
index 00000000..68be34bb
--- /dev/null
+++
b/polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyEntityTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.policy;
+
+import java.util.stream.Stream;
+import org.apache.iceberg.catalog.Namespace;
+import org.apache.polaris.core.entity.PolarisEntityType;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class PolicyEntityTest {
+
+ static Stream<Arguments> policyTypes() {
+ return Stream.of(
+ Arguments.of(PredefinedPolicyTypes.DATA_COMPACTION),
+ Arguments.of(PredefinedPolicyTypes.METADATA_COMPACTION),
+ Arguments.of(PredefinedPolicyTypes.ORPHAN_FILE_REMOVAL),
+ Arguments.of(PredefinedPolicyTypes.METADATA_COMPACTION));
+ }
+
+ @ParameterizedTest
+ @MethodSource("policyTypes")
+ public void testPolicyEntity(PolicyType policyType) {
+ PolicyEntity entity =
+ new PolicyEntity.Builder(Namespace.of("NS1"), "testPolicy", policyType)
+ .setContent("test_content")
+ .setPolicyVersion(0)
+ .build();
+
Assertions.assertThat(entity.getType()).isEqualTo(PolarisEntityType.POLICY);
+ Assertions.assertThat(entity.getPolicyType()).isEqualTo(policyType);
+
Assertions.assertThat(entity.getPolicyTypeCode()).isEqualTo(policyType.getCode());
+ Assertions.assertThat(entity.getContent()).isEqualTo("test_content");
+ }
+
+ @Test
+ public void testBuildPolicyEntityWithoutPolicyTye() {
+ Assertions.assertThatThrownBy(
+ () ->
+ new PolicyEntity.Builder(Namespace.of("NS1"), "testPolicy",
null)
+ .setContent("test_content")
+ .setPolicyVersion(0)
+ .build())
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Policy type must be specified");
+ }
+}
diff --git
a/polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyTypeTest.java
b/polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyTypeTest.java
new file mode 100644
index 00000000..a690cfd0
--- /dev/null
+++
b/polaris-core/src/test/java/org/apache/polaris/core/policy/PolicyTypeTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.polaris.core.policy;
+
+import java.util.stream.Stream;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+public class PolicyTypeTest {
+
+ static Stream<Arguments> predefinedPolicyTypes() {
+ return Stream.of(
+ Arguments.of(0, "system.data-compaction", true),
+ Arguments.of(1, "system.metadata-compaction", true),
+ Arguments.of(2, "system.orphan-file-removal", true),
+ Arguments.of(3, "system.snapshot-retention", true));
+ }
+
+ @ParameterizedTest
+ @MethodSource("predefinedPolicyTypes")
+ public void testPredefinedPolicyTypeFromCode(int code, String name, boolean
isInheritable) {
+ PolicyType policyType = PolicyType.fromCode(code);
+ Assertions.assertThat(policyType).isNotNull();
+ Assertions.assertThat(policyType.getCode()).isEqualTo(code);
+ Assertions.assertThat(policyType.getName()).isEqualTo(name);
+ Assertions.assertThat(policyType.isInheritable()).isEqualTo(isInheritable);
+ }
+
+ @ParameterizedTest
+ @MethodSource("predefinedPolicyTypes")
+ public void testPredefinedPolicyTypeFromName(int code, String name, boolean
isInheritable) {
+ PolicyType policyType = PolicyType.fromName(name);
+ Assertions.assertThat(policyType).isNotNull();
+ Assertions.assertThat(policyType.getCode()).isEqualTo(code);
+ Assertions.assertThat(policyType.getName()).isEqualTo(name);
+ Assertions.assertThat(policyType.isInheritable()).isEqualTo(isInheritable);
+ }
+}
diff --git
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
index 9c1d6a30..4d1927a4 100644
---
a/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
+++
b/polaris-core/src/testFixtures/java/org/apache/polaris/core/persistence/PolarisTestMetaStoreManager.java
@@ -49,6 +49,9 @@ import
org.apache.polaris.core.persistence.dao.entity.DropEntityResult;
import org.apache.polaris.core.persistence.dao.entity.EntityResult;
import org.apache.polaris.core.persistence.dao.entity.LoadGrantsResult;
import org.apache.polaris.core.persistence.dao.entity.ResolvedEntityResult;
+import org.apache.polaris.core.policy.PolicyEntity;
+import org.apache.polaris.core.policy.PolicyType;
+import org.apache.polaris.core.policy.PredefinedPolicyTypes;
import org.assertj.core.api.Assertions;
/** Test the Polaris persistence layer */
@@ -579,12 +582,22 @@ public class PolarisTestMetaStoreManager {
PolarisEntityType entityType,
PolarisEntitySubType entitySubType,
String name) {
+ return createEntity(catalogPath, entityType, entitySubType, name, null);
+ }
+
+ public PolarisBaseEntity createEntity(
+ List<PolarisEntityCore> catalogPath,
+ PolarisEntityType entityType,
+ PolarisEntitySubType entitySubType,
+ String name,
+ Map<String, String> properties) {
return createEntity(
catalogPath,
entityType,
entitySubType,
name,
-
polarisMetaStoreManager.generateNewEntityId(this.polarisCallContext).getId());
+
polarisMetaStoreManager.generateNewEntityId(this.polarisCallContext).getId(),
+ properties);
}
PolarisBaseEntity createEntity(
@@ -593,6 +606,16 @@ public class PolarisTestMetaStoreManager {
PolarisEntitySubType entitySubType,
String name,
long entityId) {
+ return createEntity(catalogPath, entityType, entitySubType, name,
entityId, null);
+ }
+
+ PolarisBaseEntity createEntity(
+ List<PolarisEntityCore> catalogPath,
+ PolarisEntityType entityType,
+ PolarisEntitySubType entitySubType,
+ String name,
+ long entityId,
+ Map<String, String> properties) {
long parentId;
long catalogId;
if (catalogPath != null) {
@@ -604,6 +627,7 @@ public class PolarisTestMetaStoreManager {
}
PolarisBaseEntity newEntity =
new PolarisBaseEntity(catalogId, entityId, entityType, entitySubType,
parentId, name);
+ newEntity.setPropertiesAsMap(properties);
PolarisBaseEntity entity =
polarisMetaStoreManager
.createEntityIfNotExists(this.polarisCallContext, catalogPath,
newEntity)
@@ -646,6 +670,26 @@ public class PolarisTestMetaStoreManager {
return createEntity(catalogPath, entityType,
PolarisEntitySubType.NULL_SUBTYPE, name);
}
+ PolarisBaseEntity createEntity(
+ List<PolarisEntityCore> catalogPath,
+ PolarisEntityType entityType,
+ String name,
+ Map<String, String> properties) {
+ return createEntity(
+ catalogPath, entityType, PolarisEntitySubType.NULL_SUBTYPE, name,
properties);
+ }
+
+ /** Create a policy entity */
+ PolicyEntity createPolicy(
+ List<PolarisEntityCore> catalogPath, String name, PolicyType policyType)
{
+ return PolicyEntity.of(
+ createEntity(
+ catalogPath,
+ PolarisEntityType.POLICY,
+ name,
+ Map.of("policy-type-code",
Integer.toString(policyType.getCode()))));
+ }
+
/** Drop the entity if it exists. */
void dropEntity(List<PolarisEntityCore> catalogPath, PolarisBaseEntity
entityToDrop) {
// see if the entity exists
@@ -914,7 +958,7 @@ public class PolarisTestMetaStoreManager {
/**
* Create a test catalog. This is a new catalog which will have the
following objects (N is for a
- * namespace, T for a table, V for a view, R for a role, P for a principal):
+ * namespace, T for a table, V for a view, R for a role, P for a principal,
POL for a policy):
*
* <pre>
* - C
@@ -927,6 +971,9 @@ public class PolarisTestMetaStoreManager {
* - (N1/N4)
* - N5/N6/T5
* - N5/N6/T6
+ * - N7/N8/POL1
+ * - N7/N8/POL2
+ * - N7/POL3
* - R1(TABLE_READ on N1/N2, VIEW_CREATE on C, TABLE_LIST on N1/N2,
TABLE_DROP on N5/N6/T5)
* - R2(TABLE_WRITE_DATA on N5, VIEW_LIST on C)
* - PR1(R1, R2)
@@ -993,6 +1040,14 @@ public class PolarisTestMetaStoreManager {
PolarisEntitySubType.TABLE,
"T6");
+ PolarisBaseEntity N7 = this.createEntity(List.of(catalog),
PolarisEntityType.NAMESPACE, "N7");
+ PolarisBaseEntity N7_N8 =
+ this.createEntity(List.of(catalog, N7), PolarisEntityType.NAMESPACE,
"N8");
+ this.createPolicy(List.of(catalog, N7, N7_N8), "POL1",
PredefinedPolicyTypes.DATA_COMPACTION);
+ this.createPolicy(
+ List.of(catalog, N7, N7_N8), "POL2",
PredefinedPolicyTypes.METADATA_COMPACTION);
+ this.createPolicy(List.of(catalog, N7), "POL3",
PredefinedPolicyTypes.SNAPSHOT_RETENTION);
+
// the two catalog roles
PolarisBaseEntity R1 =
this.createEntity(List.of(catalog), PolarisEntityType.CATALOG_ROLE,
"R1");
@@ -1659,6 +1714,17 @@ public class PolarisTestMetaStoreManager {
PolarisEntityType.TABLE_LIKE,
PolarisEntitySubType.TABLE,
"T6");
+ PolarisBaseEntity N7 =
+ this.ensureExistsByName(List.of(catalog), PolarisEntityType.NAMESPACE,
"N7");
+ PolarisBaseEntity N7_N8 =
+ this.ensureExistsByName(
+ List.of(catalog, N7),
+ PolarisEntityType.NAMESPACE,
+ PolarisEntitySubType.ANY_SUBTYPE,
+ "N8");
+ this.ensureExistsByName(List.of(catalog, N7, N7_N8),
PolarisEntityType.POLICY, "POL1");
+ this.ensureExistsByName(List.of(catalog, N7, N7_N8),
PolarisEntityType.POLICY, "POL2");
+ this.ensureExistsByName(List.of(catalog, N7), PolarisEntityType.POLICY,
"POL3");
PolarisBaseEntity R1 =
this.ensureExistsByName(List.of(catalog),
PolarisEntityType.CATALOG_ROLE, "R1");
PolarisBaseEntity R2 =
@@ -1692,7 +1758,8 @@ public class PolarisTestMetaStoreManager {
PolarisEntityType.NAMESPACE,
List.of(
ImmutablePair.of("N1", PolarisEntitySubType.NULL_SUBTYPE),
- ImmutablePair.of("N5", PolarisEntitySubType.NULL_SUBTYPE)));
+ ImmutablePair.of("N5", PolarisEntitySubType.NULL_SUBTYPE),
+ ImmutablePair.of("N7", PolarisEntitySubType.NULL_SUBTYPE)));
// should see 3 top-level catalog roles including the admin one
this.validateListReturn(
@@ -1793,6 +1860,18 @@ public class PolarisTestMetaStoreManager {
PolarisEntitySubType.NULL_SUBTYPE),
ImmutablePair.of("PR1", PolarisEntitySubType.NULL_SUBTYPE),
ImmutablePair.of("PR2", PolarisEntitySubType.NULL_SUBTYPE)));
+
+ // list 2 policies under N7_N8
+ PolarisBaseEntity N7 =
+ this.ensureExistsByName(List.of(catalog), PolarisEntityType.NAMESPACE,
"N7");
+ PolarisBaseEntity N7_N8 =
+ this.ensureExistsByName(List.of(catalog, N7),
PolarisEntityType.NAMESPACE, "N8");
+ this.validateListReturn(
+ List.of(catalog, N7, N7_N8),
+ PolarisEntityType.POLICY,
+ List.of(
+ ImmutablePair.of("POL1", PolarisEntitySubType.NULL_SUBTYPE),
+ ImmutablePair.of("POL2", PolarisEntitySubType.NULL_SUBTYPE)));
}
/** Test that entity updates works well */
@@ -1961,6 +2040,26 @@ public class PolarisTestMetaStoreManager {
this.dropEntity(List.of(catalog, N5), N5_N6);
this.dropEntity(List.of(catalog), N5);
+ PolarisBaseEntity N7 =
+ this.ensureExistsByName(List.of(catalog), PolarisEntityType.NAMESPACE,
"N7");
+ PolarisBaseEntity N7_N8 =
+ this.ensureExistsByName(
+ List.of(catalog, N7),
+ PolarisEntityType.NAMESPACE,
+ PolarisEntitySubType.ANY_SUBTYPE,
+ "N8");
+ PolarisBaseEntity POL1 =
+ this.ensureExistsByName(List.of(catalog, N7, N7_N8),
PolarisEntityType.POLICY, "POL1");
+ PolarisBaseEntity POL2 =
+ this.ensureExistsByName(List.of(catalog, N7, N7_N8),
PolarisEntityType.POLICY, "POL2");
+ PolarisBaseEntity POL3 =
+ this.ensureExistsByName(List.of(catalog, N7),
PolarisEntityType.POLICY, "POL3");
+ this.dropEntity(List.of(catalog, N7, N7_N8), POL1);
+ this.dropEntity(List.of(catalog, N7, N7_N8), POL2);
+ this.dropEntity(List.of(catalog, N7), POL3);
+ this.dropEntity(List.of(catalog, N7), N7_N8);
+ this.dropEntity(List.of(catalog), N7);
+
// attempt to drop the catalog again, should fail because of role R1
this.dropEntity(null, catalog);