# # 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. # services: rustfs: image: rustfs/rustfs:1.0.0-alpha.81 ports: # API port - "9000:9000" # UI port - "9001:9001" environment: RUSTFS_ACCESS_KEY: polaris_root RUSTFS_SECRET_KEY: polaris_pass RUSTFS_VOLUMES: /data RUSTFS_ADDRESS: ":9000" RUSTFS_CONSOLE_ENABLE: "true" RUSTFS_CONSOLE_ADDRESS: ":9001" healthcheck: test: ["CMD-SHELL", "curl --fail http://127.0.0.1:9000/health && curl --fail http://127.0.0.1:9001/rustfs/console/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s polaris: image: apache/polaris:latest ports: # API port - "8181:8181" # Management port (metrics and health checks) - "8182:8182" # Optional, allows attaching a debugger to the Polaris JVM - "5005:5005" depends_on: rustfs: condition: service_healthy bucket-setup: condition: service_completed_successfully environment: JAVA_DEBUG: true JAVA_DEBUG_PORT: "*:5005" AWS_REGION: us-west-2 AWS_ACCESS_KEY_ID: polaris_root AWS_SECRET_ACCESS_KEY: polaris_pass POLARIS_BOOTSTRAP_CREDENTIALS: POLARIS,${ROOT_CLIENT_ID:-root},${ROOT_CLIENT_SECRET:-s3cr3t} polaris.realm-context.realms: ${POLARIS_REALM:-POLARIS} quarkus.otel.sdk.disabled: "true" healthcheck: test: ["CMD", "curl", "--fail", "http://localhost:8182/q/health"] interval: 2s timeout: 10s retries: 10 start_period: 10s bucket-setup: image: amazon/aws-cli:2.34.29 depends_on: rustfs: condition: service_healthy environment: AWS_ACCESS_KEY_ID: polaris_root AWS_SECRET_ACCESS_KEY: polaris_pass AWS_ENDPOINT_URL: http://rustfs:9000 entrypoint: "/bin/sh" command: - "-c" - >- echo Creating RustFS bucket... && aws s3 mb s3://bucket123 && aws s3 ls && echo Bucket setup complete. polaris-setup: image: alpine/curl:8.17.0 depends_on: polaris: condition: service_healthy environment: - CLIENT_ID=${ROOT_CLIENT_ID:-root} - CLIENT_SECRET=${ROOT_CLIENT_SECRET:-s3cr3t} - CATALOG_NAME=${CATALOG_NAME:-quickstart_catalog} - REALM=${POLARIS_REALM:-POLARIS} entrypoint: /bin/sh command: - -c - | set -e apk add --no-cache jq echo "Obtaining root access token..." TOKEN_RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/catalog/v1/oauth/tokens \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d "grant_type=client_credentials&client_id=$${CLIENT_ID}&client_secret=$${CLIENT_SECRET}&scope=PRINCIPAL_ROLE:ALL" 2>&1) || { echo "❌ Failed to obtain access token" echo "$$TOKEN_RESPONSE" >&2 exit 1 } TOKEN=$$(echo $$TOKEN_RESPONSE | jq -r '.access_token') if [ -z "$$TOKEN" ] || [ "$$TOKEN" = "null" ]; then echo "❌ Failed to parse access token from response" echo "$$TOKEN_RESPONSE" exit 1 fi echo "✅ Obtained access token" echo "Creating catalog '$$CATALOG_NAME' in realm $$REALM..." PAYLOAD='{ "catalog": { "name": "'$$CATALOG_NAME'", "type": "INTERNAL", "readOnly": false, "properties": { "default-base-location": "s3://bucket123" }, "storageConfigInfo": { "storageType": "S3", "allowedLocations": ["s3://bucket123"], "endpoint": "http://localhost:9000", "endpointInternal": "http://rustfs:9000", "pathStyleAccess": true } } }' RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/management/v1/catalogs \ -H "Authorization: Bearer $$TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -H "Polaris-Realm: $$REALM" \ -d "$$PAYLOAD" 2>&1) && echo -n "" || { echo "❌ Failed to create catalog" echo "$$RESPONSE" >&2 exit 1 } echo "✅ Catalog created" echo "" echo "Creating principal 'quickstart_user'..." PRINCIPAL_RESPONSE=$$(curl --fail-with-body -s -X POST http://polaris:8181/api/management/v1/principals \ -H "Authorization: Bearer $$TOKEN" \ -H "Polaris-Realm: $$REALM" \ -H "Content-Type: application/json" \ -d '{"principal": {"name": "quickstart_user", "properties": {}}}' 2>&1) || { echo "❌ Failed to create principal" echo "$$PRINCIPAL_RESPONSE" >&2 exit 1 } USER_CLIENT_ID=$$(echo $$PRINCIPAL_RESPONSE | jq -r '.credentials.clientId') USER_CLIENT_SECRET=$$(echo $$PRINCIPAL_RESPONSE | jq -r '.credentials.clientSecret') if [ -z "$$USER_CLIENT_ID" ] || [ "$$USER_CLIENT_ID" = "null" ] || [ -z "$$USER_CLIENT_SECRET" ] || [ "$$USER_CLIENT_SECRET" = "null" ]; then echo "❌ Failed to parse user credentials from response" echo "$$PRINCIPAL_RESPONSE" exit 1 fi echo "✅ Principal created with clientId: $$USER_CLIENT_ID" echo "Creating principal role 'quickstart_user_role'..." RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/management/v1/principal-roles \ -H "Authorization: Bearer $$TOKEN" \ -H "Polaris-Realm: $$REALM" \ -H "Content-Type: application/json" \ -d '{"principalRole": {"name": "quickstart_user_role", "properties": {}}}' 2>&1) && echo -n "" || { echo "❌ Failed to create principal role" echo "$$RESPONSE" >&2 exit 1 } echo "✅ Principal role created" echo "Creating catalog role 'quickstart_catalog_role'..." RESPONSE=$$(curl --fail-with-body -s -S -X POST http://polaris:8181/api/management/v1/catalogs/$$CATALOG_NAME/catalog-roles \ -H "Authorization: Bearer $$TOKEN" \ -H "Polaris-Realm: $$REALM" \ -H "Content-Type: application/json" \ -d '{"catalogRole": {"name": "quickstart_catalog_role", "properties": {}}}' 2>&1) && echo -n "" || { echo "❌ Failed to create catalog role" echo "$$RESPONSE" >&2 exit 1 } echo "✅ Catalog role created" echo "Assigning principal role to principal..." RESPONSE=$$(curl --fail-with-body -s -S -X PUT http://polaris:8181/api/management/v1/principals/quickstart_user/principal-roles \ -H "Authorization: Bearer $$TOKEN" \ -H "Polaris-Realm: $$REALM" \ -H "Content-Type: application/json" \ -d '{"principalRole": {"name": "quickstart_user_role"}}' 2>&1) && echo -n "" || { echo "❌ Failed to assign principal role" echo "$$RESPONSE" >&2 exit 1 } echo "✅ Principal role assigned" echo "Assigning catalog role to principal role..." RESPONSE=$$(curl --fail-with-body -s -S -X PUT http://polaris:8181/api/management/v1/principal-roles/quickstart_user_role/catalog-roles/$$CATALOG_NAME \ -H "Authorization: Bearer $$TOKEN" \ -H "Polaris-Realm: $$REALM" \ -H "Content-Type: application/json" \ -d '{"catalogRole": {"name": "quickstart_catalog_role"}}' 2>&1) && echo -n "" || { echo "❌ Failed to assign catalog role" echo "$$RESPONSE" >&2 exit 1 } echo "✅ Catalog role assigned" echo "Granting CATALOG_MANAGE_CONTENT privilege..." RESPONSE=$$(curl --fail-with-body -s -S -X PUT http://polaris:8181/api/management/v1/catalogs/$$CATALOG_NAME/catalog-roles/quickstart_catalog_role/grants \ -H "Authorization: Bearer $$TOKEN" \ -H "Polaris-Realm: $$REALM" \ -H "Content-Type: application/json" \ -d '{"type": "catalog", "privilege": "CATALOG_MANAGE_CONTENT"}' 2>&1) && echo -n "" || { echo "❌ Failed to grant privileges" echo "$$RESPONSE" >&2 exit 1 } echo "✅ Privileges granted" echo "" echo "==========================================" echo "🎉 Polaris Quickstart Setup Complete!" echo "==========================================" echo "" echo "Catalog: $$CATALOG_NAME" echo " Storage: S3 (RustFS)" echo " Location: s3://bucket123" echo " RustFS UI: http://localhost:9001" echo "" echo "Root credentials:" echo " Client ID: $$CLIENT_ID" echo " Client Secret: $$CLIENT_SECRET" echo "" echo "User credentials:" echo " Client ID: $$USER_CLIENT_ID" echo " Client Secret: $$USER_CLIENT_SECRET" echo "" echo "Polaris main APIs:" echo " - Iceberg REST: http://localhost:8181/api/catalog/v1" echo " - Management: http://localhost:8181/api/management/v1" echo " - Generic Tables: http://localhost:8181/api/polaris/v1" echo "" echo "Polaris admin APIs:" echo " - Health check: http://localhost:8182/q/health" echo " - Metrics: http://localhost:8182/q/metrics" echo "" echo "To get started with Spark:" echo " spark-sql \\" echo " --packages org.apache.iceberg:iceberg-spark-runtime-3.5_2.12:1.10.1,org.apache.iceberg:iceberg-aws-bundle:1.10.1 \\" echo " --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \\" echo " --conf spark.sql.catalog.polaris=org.apache.iceberg.spark.SparkCatalog \\" echo " --conf spark.sql.catalog.polaris.type=rest \\" echo " --conf spark.sql.catalog.polaris.warehouse=$$CATALOG_NAME \\" echo " --conf spark.sql.catalog.polaris.uri=http://localhost:8181/api/catalog \\" echo " --conf spark.sql.catalog.polaris.credential=$$USER_CLIENT_ID:$$USER_CLIENT_SECRET \\" echo " --conf spark.sql.catalog.polaris.scope=PRINCIPAL_ROLE:ALL \\" echo " --conf spark.sql.catalog.polaris.s3.endpoint=http://localhost:9000 \\" echo " --conf spark.sql.catalog.polaris.s3.path-style-access=true \\" echo " --conf spark.sql.catalog.polaris.s3.access-key-id=polaris_root \\" echo " --conf spark.sql.catalog.polaris.s3.secret-access-key=polaris_pass \\" echo " --conf spark.sql.catalog.polaris.client.region=irrelevant \\" echo " --conf spark.sql.defaultCatalog=polaris" echo "" echo "To get started with REST API:" echo " # Get a token" echo " export TOKEN=\$$(curl -s -X POST http://localhost:8181/api/catalog/v1/oauth/tokens \\" echo " -d 'grant_type=client_credentials' \\" echo " -d 'client_id=$$USER_CLIENT_ID' \\" echo " -d 'client_secret=$$USER_CLIENT_SECRET' \\" echo " -d 'scope=PRINCIPAL_ROLE:ALL' \\" echo " | jq -r '.access_token')" echo "" echo " # Create a namespace" echo " curl -X POST http://localhost:8181/api/catalog/v1/$$CATALOG_NAME/namespaces \\" echo " -H \"Authorization: Bearer \$$TOKEN\" \\" echo " -H 'Content-Type: application/json' \\" echo " -d '{\"namespace\": [\"my_namespace\"], \"properties\": {}}'" echo "" echo " # List namespaces" echo " curl -X GET http://localhost:8181/api/catalog/v1/$$CATALOG_NAME/namespaces \\" echo " -H \"Authorization: Bearer \$$TOKEN\"" echo "" echo "==========================================" touch /tmp/polaris-setup-done tail -f /dev/null healthcheck: interval: 1s timeout: 10s retries: 240 test: ["CMD", "test", "-f", "/tmp/polaris-setup-done"]