1
+ #! /bin/bash
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ # This test creates an INTERNAL catalog and an EXTERNAL catalog with passthrough facade
22
+ # to demonstrate true catalog federation.
23
+
24
+ set -e
25
+
26
+
27
+ SPARK_BEARER_TOKEN=" ${REGTEST_ROOT_BEARER_TOKEN} "
28
+
29
+ echo " === Setting up Catalog Federation Test ==="
30
+
31
+ # Step 1: Create a new principal
32
+ echo " Creating new principal..."
33
+ PRINCIPAL_RESPONSE=$( curl -s -X POST -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Content-Type: application/json' \
34
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/principals \
35
+ -d ' {
36
+ "principal": {
37
+ "name": "new-user"
38
+ }
39
+ }' )
40
+
41
+ NEW_CLIENT_ID=$( echo " $PRINCIPAL_RESPONSE " | jq -r ' .credentials.clientId' )
42
+ NEW_CLIENT_SECRET=$( echo " $PRINCIPAL_RESPONSE " | jq -r ' .credentials.clientSecret' )
43
+
44
+ # Step 2: Create local catalog
45
+ echo " Creating local catalog..."
46
+ RESPONSE_CODE=$( curl -s -X POST -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Content-Type: application/json' \
47
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/catalogs \
48
+ -d ' {
49
+ "type": "INTERNAL",
50
+ "name": "test-catalog-local",
51
+ "properties": {
52
+ "default-base-location": "file:///tmp/warehouse"
53
+ },
54
+ "storageConfigInfo": {
55
+ "storageType": "FILE",
56
+ "allowedLocations": ["file:///tmp/warehouse"]
57
+ }
58
+ }' \
59
+ --write-out " %{http_code}" )
60
+ echo " Create local catalog response code: $RESPONSE_CODE "
61
+
62
+
63
+
64
+ # Step 3: Grant permissions
65
+ echo " Setting up permissions..."
66
+
67
+ # Grant TABLE_WRITE_DATA privilege to catalog_admin for local catalog
68
+ RESPONSE_CODE=$( curl -s -X PUT -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
69
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/catalogs/test-catalog-local/catalog-roles/catalog_admin/grants \
70
+ -d ' {"type": "catalog", "privilege": "TABLE_WRITE_DATA"}' \
71
+ --write-out " %{http_code}" )
72
+ echo " Grant TABLE_WRITE_DATA to catalog_admin response code: $RESPONSE_CODE "
73
+
74
+ # Assign catalog_admin to service_admin
75
+ RESPONSE_CODE=$( curl -s -X PUT -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
76
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/principal-roles/service_admin/catalog-roles/test-catalog-local \
77
+ -d ' {"name": "catalog_admin"}' \
78
+ --write-out " %{http_code}" )
79
+ echo " Assign catalog_admin to service_admin response code: $RESPONSE_CODE "
80
+
81
+ # Assign service_admin to new-user
82
+ RESPONSE_CODE=$( curl -s -X PUT -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
83
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/principals/new-user/principal-roles \
84
+ -d ' {"name": "service_admin"}' \
85
+ --write-out " %{http_code}" )
86
+ echo " Assign service_admin to new-user response code: $RESPONSE_CODE "
87
+
88
+ # Step 4: Create external catalog
89
+ echo " Creating external catalog (passthrough facade)..."
90
+ RESPONSE_CODE=$( curl -s -X POST -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Content-Type: application/json' \
91
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/catalogs \
92
+ -d " {
93
+ \" type\" : \" EXTERNAL\" ,
94
+ \" name\" : \" test-catalog-external\" ,
95
+ \" connectionConfigInfo\" : {
96
+ \" connectionType\" : \" ICEBERG_REST\" ,
97
+ \" uri\" : \" http://${POLARIS_HOST:- localhost} :8181/api/catalog\" ,
98
+ \" remoteCatalogName\" : \" test-catalog-local\" ,
99
+ \" authenticationParameters\" : {
100
+ \" authenticationType\" : \" OAUTH\" ,
101
+ \" tokenUri\" : \" http://${POLARIS_HOST:- localhost} :8181/api/catalog/v1/oauth/tokens\" ,
102
+ \" clientId\" : \" ${NEW_CLIENT_ID} \" ,
103
+ \" clientSecret\" : \" ${NEW_CLIENT_SECRET} \" ,
104
+ \" scopes\" : [\" PRINCIPAL_ROLE:ALL\" ]
105
+ }
106
+ },
107
+ \" properties\" : {
108
+ \" default-base-location\" : \" file:///tmp/warehouse\"
109
+ },
110
+ \" storageConfigInfo\" : {
111
+ \" storageType\" : \" FILE\" ,
112
+ \" allowedLocations\" : [\" file:///tmp/warehouse\" ]
113
+ }
114
+ }" \
115
+ --write-out " %{http_code}" )
116
+ echo " Create external catalog response code: $RESPONSE_CODE "
117
+
118
+ # Step 5: Grant permissions for external catalog
119
+ echo " Setting up permissions for external catalog..."
120
+
121
+ # Grant TABLE_WRITE_DATA privilege to catalog_admin role for test-catalog-external
122
+ RESPONSE_CODE=$( curl -s -X PUT -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
123
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/catalogs/test-catalog-external/catalog-roles/catalog_admin/grants \
124
+ -d ' {"type": "catalog", "privilege": "TABLE_WRITE_DATA"}' \
125
+ --write-out " %{http_code}" )
126
+ echo " Grant TABLE_WRITE_DATA to external catalog_admin response code: $RESPONSE_CODE "
127
+
128
+ # Assign catalog_admin role to service_admin principal-role for test-catalog-external
129
+ RESPONSE_CODE=$( curl -s -X PUT -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
130
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/principal-roles/service_admin/catalog-roles/test-catalog-external \
131
+ -d ' {"name": "catalog_admin"}' \
132
+ --write-out " %{http_code}" )
133
+ echo " Assign catalog_admin to service_admin for external catalog response code: $RESPONSE_CODE "
134
+
135
+ echo " Catalogs created successfully"
136
+
137
+ echo " "
138
+ echo " === Starting federation test ==="
139
+
140
+ # Test data operations via local catalog
141
+ echo " === Creating data via LOCAL catalog ==="
142
+ cat << EOF | ${SPARK_HOME} /bin/spark-sql -S --conf spark.sql.catalog.polaris.token="${SPARK_BEARER_TOKEN} " --conf spark.sql.catalog.polaris.warehouse=test-catalog-local --conf spark.sql.defaultCatalog=polaris --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
143
+ use polaris;
144
+ create namespace if not exists ns1;
145
+ create table if not exists ns1.test_table (id int, name string);
146
+ insert into ns1.test_table values (1, 'Alice');
147
+ insert into ns1.test_table values (2, 'Bob');
148
+ create namespace if not exists ns2;
149
+ create table if not exists ns2.test_table (id int, name string);
150
+ insert into ns2.test_table values (1, 'Apache Spark');
151
+ insert into ns2.test_table values (2, 'Apache Iceberg');
152
+ EOF
153
+
154
+ echo " "
155
+ echo " === Accessing data via EXTERNAL catalog ==="
156
+ cat << EOF | ${SPARK_HOME} /bin/spark-sql -S --conf spark.sql.catalog.polaris.token="${SPARK_BEARER_TOKEN} " --conf spark.sql.catalog.polaris.warehouse=test-catalog-external --conf spark.sql.defaultCatalog=polaris --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
157
+ use polaris;
158
+ show namespaces;
159
+ select * from ns1.test_table order by id;
160
+ insert into ns1.test_table values (3, 'Charlie');
161
+ select * from ns2.test_table order by id;
162
+ insert into ns2.test_table values (3, 'Apache Polaris');
163
+ EOF
164
+
165
+ echo " "
166
+ echo " === Verifying federation via LOCAL catalog ==="
167
+ cat << EOF | ${SPARK_HOME} /bin/spark-sql -S --conf spark.sql.catalog.polaris.token="${SPARK_BEARER_TOKEN} " --conf spark.sql.catalog.polaris.warehouse=test-catalog-local --conf spark.sql.defaultCatalog=polaris --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions
168
+ use polaris;
169
+ select * from ns1.test_table order by id;
170
+ select * from ns2.test_table order by id;
171
+ drop table ns1.test_table;
172
+ drop table ns2.test_table;
173
+ drop namespace ns1;
174
+ drop namespace ns2;
175
+ EOF
176
+
177
+ echo " "
178
+ echo " === Cleaning up catalogs and principal ==="
179
+ # Clean up catalogs
180
+ RESPONSE_CODE=$( curl -X DELETE -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
181
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/catalogs/test-catalog-external \
182
+ --write-out " %{http_code}" )
183
+ echo " Delete external catalog response code: $RESPONSE_CODE "
184
+
185
+ RESPONSE_CODE=$( curl -X DELETE -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
186
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/catalogs/test-catalog-local \
187
+ --write-out " %{http_code}" )
188
+ echo " Delete local catalog response code: $RESPONSE_CODE "
189
+
190
+ # Clean up principal
191
+ RESPONSE_CODE=$( curl -X DELETE -H " Authorization: Bearer ${SPARK_BEARER_TOKEN} " -H ' Accept: application/json' -H ' Content-Type: application/json' \
192
+ http://${POLARIS_HOST:- localhost} :8181/api/management/v1/principals/new-user \
193
+ --write-out " %{http_code}" )
194
+ echo " Delete principal response code: $RESPONSE_CODE "
195
+
196
+ echo " Catalog federation test completed successfully!"
0 commit comments