|
16 | 16 | # under the License. |
17 | 17 |
|
18 | 18 | services: |
| 19 | + |
| 20 | + rustfs: |
| 21 | + image: rustfs/rustfs:1.0.0-alpha.81 |
| 22 | + networks: |
| 23 | + iceberg_net: |
| 24 | + ports: |
| 25 | + # API port |
| 26 | + - "9000:9000" |
| 27 | + # UI port |
| 28 | + - "9001:9001" |
| 29 | + environment: |
| 30 | + RUSTFS_ACCESS_KEY: polaris_root |
| 31 | + RUSTFS_SECRET_KEY: polaris_pass |
| 32 | + RUSTFS_VOLUMES: /data |
| 33 | + RUSTFS_ADDRESS: ":9000" |
| 34 | + RUSTFS_CONSOLE_ENABLE: "true" |
| 35 | + RUSTFS_CONSOLE_ADDRESS: ":9001" |
| 36 | + healthcheck: |
| 37 | + test: ["CMD-SHELL", "curl --fail http://127.0.0.1:9000/health && curl --fail http://127.0.0.1:9001/rustfs/console/health"] |
| 38 | + interval: 10s |
| 39 | + timeout: 10s |
| 40 | + retries: 3 |
| 41 | + start_period: 40s |
| 42 | + |
19 | 43 | polaris: |
20 | 44 | image: apache/polaris:latest |
21 | 45 | container_name: pyiceberg-polaris |
22 | 46 | networks: |
23 | 47 | iceberg_net: |
24 | 48 | ports: |
25 | | - - 8181:8181 |
26 | | - - 8182:8182 |
| 49 | + # API port |
| 50 | + - "8181:8181" |
| 51 | + # Management port (metrics and health checks) |
| 52 | + - "8182:8182" |
| 53 | + # Optional, allows attaching a debugger to the Polaris JVM |
| 54 | + - "5005:5005" |
| 55 | + depends_on: |
| 56 | + rustfs: |
| 57 | + condition: service_healthy |
| 58 | + bucket-setup: |
| 59 | + condition: service_completed_successfully |
27 | 60 | environment: |
28 | | - - POLARIS_BOOTSTRAP_CREDENTIALS=POLARIS,root,s3cr3t |
29 | | - - polaris.features."ALLOW_INSECURE_STORAGE_TYPES"=true |
30 | | - - polaris.features."SUPPORTED_CATALOG_STORAGE_TYPES"=["FILE","S3"] |
31 | | - - polaris.features."ALLOW_OVERLAPPING_CATALOG_URLS"=true |
32 | | - - polaris.readiness.ignore-severe-issues=true |
33 | | - - AWS_ACCESS_KEY_ID=admin |
34 | | - - AWS_SECRET_ACCESS_KEY=password |
35 | | - - AWS_REGION=us-east-1 |
| 61 | + JAVA_DEBUG: true |
| 62 | + JAVA_DEBUG_PORT: "*:5005" |
| 63 | + AWS_REGION: us-west-2 |
| 64 | + AWS_ACCESS_KEY_ID: polaris_root |
| 65 | + AWS_SECRET_ACCESS_KEY: polaris_pass |
| 66 | + POLARIS_BOOTSTRAP_CREDENTIALS: POLARIS,root,s3cr3t |
| 67 | + polaris.realm-context.realms: POLARIS |
| 68 | + quarkus.otel.sdk.disabled: "true" |
| 69 | + polaris.features."ALLOW_INSECURE_STORAGE_TYPES": "true" |
| 70 | + polaris.features."SUPPORTED_CATALOG_STORAGE_TYPES": '["FILE","S3"]' |
| 71 | + polaris.features."ALLOW_OVERLAPPING_CATALOG_URLS": "true" |
| 72 | + polaris.readiness.ignore-severe-issues: "true" |
36 | 73 | healthcheck: |
37 | | - test: ["CMD", "curl", "http://localhost:8182/q/health"] |
38 | | - interval: 10s |
| 74 | + test: ["CMD", "curl", "--fail", "http://localhost:8182/q/health"] |
| 75 | + interval: 2s |
39 | 76 | timeout: 10s |
40 | | - retries: 5 |
41 | | - minio: |
42 | | - image: minio/minio |
43 | | - container_name: pyiceberg-polaris-minio |
| 77 | + retries: 10 |
| 78 | + start_period: 10s |
| 79 | + |
| 80 | + bucket-setup: |
| 81 | + image: amazon/aws-cli:2.34.19 |
44 | 82 | networks: |
45 | 83 | iceberg_net: |
46 | | - aliases: |
47 | | - - warehouse.minio |
48 | | - ports: |
49 | | - - 9001:9001 |
50 | | - - 9000:9000 |
| 84 | + depends_on: |
| 85 | + rustfs: |
| 86 | + condition: service_healthy |
51 | 87 | environment: |
52 | | - - MINIO_ROOT_USER=admin |
53 | | - - MINIO_ROOT_PASSWORD=password |
54 | | - - MINIO_DOMAIN=minio |
55 | | - command: ["server", "/data", "--console-address", ":9001"] |
56 | | - mc: |
57 | | - image: minio/mc |
58 | | - container_name: pyiceberg-polaris-mc |
| 88 | + AWS_ACCESS_KEY_ID: polaris_root |
| 89 | + AWS_SECRET_ACCESS_KEY: polaris_pass |
| 90 | + AWS_ENDPOINT_URL: http://rustfs:9000 |
| 91 | + entrypoint: "/bin/sh" |
| 92 | + command: |
| 93 | + - "-c" |
| 94 | + - >- |
| 95 | + echo Creating RustFS bucket... && |
| 96 | + aws s3 mb s3://bucket123 && |
| 97 | + aws s3 ls && |
| 98 | + echo Bucket setup complete. |
| 99 | +
|
| 100 | + polaris-setup: |
| 101 | + image: alpine/curl:8.17.0 |
59 | 102 | networks: |
60 | 103 | iceberg_net: |
61 | 104 | depends_on: |
62 | | - - minio |
| 105 | + polaris: |
| 106 | + condition: service_healthy |
63 | 107 | environment: |
64 | | - - AWS_ACCESS_KEY_ID=admin |
65 | | - - AWS_SECRET_ACCESS_KEY=password |
66 | | - - AWS_REGION=us-east-1 |
67 | | - entrypoint: > |
68 | | - /bin/sh -c " |
69 | | - until (/usr/bin/mc alias set minio http://minio:9000 admin password) do echo '...waiting...' && sleep 1; done; |
70 | | - /usr/bin/mc mb minio/warehouse; |
71 | | - /usr/bin/mc policy set public minio/warehouse; |
72 | | - tail -f /dev/null |
73 | | - " |
| 108 | + - CLIENT_ID=root |
| 109 | + - CLIENT_SECRET=s3cr3t |
| 110 | + - CATALOG_NAME=polaris |
| 111 | + - REALM=POLARIS |
| 112 | + entrypoint: /bin/sh |
| 113 | + command: |
| 114 | + - -c |
| 115 | + - | |
| 116 | + set -e |
| 117 | + apk add --no-cache jq |
| 118 | +
|
| 119 | + echo "Obtaining root access token..." |
| 120 | + TOKEN_RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/catalog/v1/oauth/tokens \ |
| 121 | + -H 'Content-Type: application/x-www-form-urlencoded' \ |
| 122 | + -d "grant_type=client_credentials&client_id=$${CLIENT_ID}&client_secret=$${CLIENT_SECRET}&scope=PRINCIPAL_ROLE:ALL" 2>&1) || { |
| 123 | + echo "❌ Failed to obtain access token" |
| 124 | + echo "$$TOKEN_RESPONSE" >&2 |
| 125 | + exit 1 |
| 126 | + } |
| 127 | +
|
| 128 | + TOKEN=$$(echo $$TOKEN_RESPONSE | jq -r '.access_token') |
| 129 | + if [ -z "$$TOKEN" ] || [ "$$TOKEN" = "null" ]; then |
| 130 | + echo "❌ Failed to parse access token from response" |
| 131 | + echo "$$TOKEN_RESPONSE" |
| 132 | + exit 1 |
| 133 | + fi |
| 134 | + echo "✅ Obtained access token" |
| 135 | +
|
| 136 | + echo "Creating catalog '$$CATALOG_NAME' in realm $$REALM..." |
| 137 | + PAYLOAD='{ |
| 138 | + "catalog": { |
| 139 | + "name": "'$$CATALOG_NAME'", |
| 140 | + "type": "INTERNAL", |
| 141 | + "readOnly": false, |
| 142 | + "properties": { |
| 143 | + "default-base-location": "s3://bucket123", |
| 144 | + "polaris.config.drop-with-purge.enabled": "true" |
| 145 | + }, |
| 146 | + "storageConfigInfo": { |
| 147 | + "storageType": "S3", |
| 148 | + "allowedLocations": ["s3://bucket123"], |
| 149 | + "endpoint": "http://localhost:9000", |
| 150 | + "endpointInternal": "http://rustfs:9000", |
| 151 | + "pathStyleAccess": true |
| 152 | + } |
| 153 | + } |
| 154 | + }' |
| 155 | +
|
| 156 | + RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/management/v1/catalogs \ |
| 157 | + -H "Authorization: Bearer $$TOKEN" \ |
| 158 | + -H "Accept: application/json" \ |
| 159 | + -H "Content-Type: application/json" \ |
| 160 | + -H "Polaris-Realm: $$REALM" \ |
| 161 | + -d "$$PAYLOAD" 2>&1) && echo -n "" || { |
| 162 | + echo "❌ Failed to create catalog" |
| 163 | + echo "$$RESPONSE" >&2 |
| 164 | + exit 1 |
| 165 | + } |
| 166 | + echo "✅ Catalog created" |
| 167 | +
|
| 168 | + echo "" |
| 169 | + echo "Creating principal 'quickstart_user'..." |
| 170 | + PRINCIPAL_RESPONSE=$$(curl --fail-with-body -s -X POST http://polaris:8181/api/management/v1/principals \ |
| 171 | + -H "Authorization: Bearer $$TOKEN" \ |
| 172 | + -H "Polaris-Realm: $$REALM" \ |
| 173 | + -H "Content-Type: application/json" \ |
| 174 | + -d '{"principal": {"name": "quickstart_user", "properties": {}}}' 2>&1) || { |
| 175 | + echo "❌ Failed to create principal" |
| 176 | + echo "$$PRINCIPAL_RESPONSE" >&2 |
| 177 | + exit 1 |
| 178 | + } |
| 179 | +
|
| 180 | + USER_CLIENT_ID=$$(echo $$PRINCIPAL_RESPONSE | jq -r '.credentials.clientId') |
| 181 | + USER_CLIENT_SECRET=$$(echo $$PRINCIPAL_RESPONSE | jq -r '.credentials.clientSecret') |
| 182 | + if [ -z "$$USER_CLIENT_ID" ] || [ "$$USER_CLIENT_ID" = "null" ] || [ -z "$$USER_CLIENT_SECRET" ] || [ "$$USER_CLIENT_SECRET" = "null" ]; then |
| 183 | + echo "❌ Failed to parse user credentials from response" |
| 184 | + echo "$$PRINCIPAL_RESPONSE" |
| 185 | + exit 1 |
| 186 | + fi |
| 187 | + echo "✅ Principal created with clientId: $$USER_CLIENT_ID" |
| 188 | +
|
| 189 | + echo "Creating principal role 'quickstart_user_role'..." |
| 190 | + RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/management/v1/principal-roles \ |
| 191 | + -H "Authorization: Bearer $$TOKEN" \ |
| 192 | + -H "Polaris-Realm: $$REALM" \ |
| 193 | + -H "Content-Type: application/json" \ |
| 194 | + -d '{"principalRole": {"name": "quickstart_user_role", "properties": {}}}' 2>&1) && echo -n "" || { |
| 195 | + echo "❌ Failed to create principal role" |
| 196 | + echo "$$RESPONSE" >&2 |
| 197 | + exit 1 |
| 198 | + } |
| 199 | + echo "✅ Principal role created" |
| 200 | +
|
| 201 | + echo "Creating catalog role 'quickstart_catalog_role'..." |
| 202 | + RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/management/v1/catalogs/$$CATALOG_NAME/catalog-roles \ |
| 203 | + -H "Authorization: Bearer $$TOKEN" \ |
| 204 | + -H "Polaris-Realm: $$REALM" \ |
| 205 | + -H "Content-Type: application/json" \ |
| 206 | + -d '{"catalogRole": {"name": "quickstart_catalog_role", "properties": {}}}' 2>&1) && echo -n "" || { |
| 207 | + echo "❌ Failed to create catalog role" |
| 208 | + echo "$$RESPONSE" >&2 |
| 209 | + exit 1 |
| 210 | + } |
| 211 | + echo "✅ Catalog role created" |
| 212 | +
|
| 213 | + echo "Assigning principal role to principal..." |
| 214 | + RESPONSE=$$(curl --fail-with-body -s -S -X PUT http://polaris:8181/api/management/v1/principals/quickstart_user/principal-roles \ |
| 215 | + -H "Authorization: Bearer $$TOKEN" \ |
| 216 | + -H "Polaris-Realm: $$REALM" \ |
| 217 | + -H "Content-Type: application/json" \ |
| 218 | + -d '{"principalRole": {"name": "quickstart_user_role"}}' 2>&1) && echo -n "" || { |
| 219 | + echo "❌ Failed to assign principal role" |
| 220 | + echo "$$RESPONSE" >&2 |
| 221 | + exit 1 |
| 222 | + } |
| 223 | + echo "✅ Principal role assigned" |
| 224 | +
|
| 225 | + echo "Assigning catalog role to principal role..." |
| 226 | + RESPONSE=$$(curl --fail-with-body -s -S -X PUT http://polaris:8181/api/management/v1/principal-roles/quickstart_user_role/catalog-roles/$$CATALOG_NAME \ |
| 227 | + -H "Authorization: Bearer $$TOKEN" \ |
| 228 | + -H "Polaris-Realm: $$REALM" \ |
| 229 | + -H "Content-Type: application/json" \ |
| 230 | + -d '{"catalogRole": {"name": "quickstart_catalog_role"}}' 2>&1) && echo -n "" || { |
| 231 | + echo "❌ Failed to assign catalog role" |
| 232 | + echo "$$RESPONSE" >&2 |
| 233 | + exit 1 |
| 234 | + } |
| 235 | + echo "✅ Catalog role assigned" |
| 236 | +
|
| 237 | + echo "Granting CATALOG_MANAGE_CONTENT privilege..." |
| 238 | + RESPONSE=$$(curl --fail-with-body -s -S -X PUT http://polaris:8181/api/management/v1/catalogs/$$CATALOG_NAME/catalog-roles/quickstart_catalog_role/grants \ |
| 239 | + -H "Authorization: Bearer $$TOKEN" \ |
| 240 | + -H "Polaris-Realm: $$REALM" \ |
| 241 | + -H "Content-Type: application/json" \ |
| 242 | + -d '{"type": "catalog", "privilege": "CATALOG_MANAGE_CONTENT"}' 2>&1) && echo -n "" || { |
| 243 | + echo "❌ Failed to grant privileges" |
| 244 | + echo "$$RESPONSE" >&2 |
| 245 | + exit 1 |
| 246 | + } |
| 247 | + echo "✅ Privileges granted" |
| 248 | +
|
| 249 | + echo "CLIENT_ID=$$USER_CLIENT_ID" > /tmp/polaris_creds.env |
| 250 | + echo "CLIENT_SECRET=$$USER_CLIENT_SECRET" >> /tmp/polaris_creds.env |
| 251 | +
|
| 252 | + touch /tmp/polaris-setup-done |
| 253 | + tail -f /dev/null |
| 254 | + healthcheck: |
| 255 | + interval: 1s |
| 256 | + timeout: 10s |
| 257 | + retries: 240 |
| 258 | + test: ["CMD", "test", "-f", "/tmp/polaris-setup-done"] |
74 | 259 |
|
75 | 260 | networks: |
76 | 261 | iceberg_net: |
0 commit comments