This is an automated email from the ASF dual-hosted git repository.
adutra 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 66ec47f2 Introduce Polaris Admin Tool (with bootstrap and purge
commands) (#605)
66ec47f2 is described below
commit 66ec47f2bdabb3779338781a50c676e8e48d58cf
Author: Alexandre Dutra <[email protected]>
AuthorDate: Tue Jan 14 14:19:15 2025 +0100
Introduce Polaris Admin Tool (with bootstrap and purge commands) (#605)
---
LICENSE-BINARY-DIST | 2 +
.../EclipseLinkPolarisMetaStoreManagerFactory.java | 5 +-
gradle/projects.main.properties | 1 +
.../LocalPolarisMetaStoreManagerFactory.java | 46 ++++++-------
.../core/persistence/MetaStoreManagerFactory.java | 3 +-
.../persistence/PolarisCredentialsBootstrap.java | 60 ++++++++--------
.../PolarisCredentialsBootstrapTest.java | 22 ++++++
quarkus/admin/README.md | 27 ++++++++
quarkus/{server => admin}/build.gradle.kts | 45 ++++++++----
.../admin/src/main/docker/Dockerfile.jvm | 42 +++++++-----
.../polaris/service/quarkus/admin/BaseCommand.java | 54 +++++++++++++++
.../service/quarkus/admin/BootstrapCommand.java | 80 ++++++++++++++++++++++
.../service/quarkus/admin/PolarisAdminTool.java | 54 +++++++++++++++
.../quarkus/admin/PolarisVersionProvider.java | 30 ++++++++
.../service/quarkus/admin/PurgeCommand.java | 49 +++++++++++++
.../src/main/resources/application.properties | 5 +-
.../quarkus/admin/BootstrapCommandTest.java | 47 +++++++++++++
.../service/quarkus/admin/PurgeCommandTest.java | 36 ++++++++++
quarkus/server/README.md | 12 +++-
quarkus/server/build.gradle.kts | 17 +++++
.../src/main/resources/application.properties | 1 +
.../quarkus/catalog/BasePolarisCatalogTest.java | 4 +-
.../test/PolarisIntegrationTestFixture.java | 4 +-
.../InMemoryPolarisMetaStoreManagerFactory.java | 11 ++-
24 files changed, 567 insertions(+), 90 deletions(-)
diff --git a/LICENSE-BINARY-DIST b/LICENSE-BINARY-DIST
index 1165f96e..205a3eed 100644
--- a/LICENSE-BINARY-DIST
+++ b/LICENSE-BINARY-DIST
@@ -280,6 +280,7 @@ commons-io:commons-io
commons-logging:commons-logging
commons-net:commons-net
dev.failsafe:failsafe
+info.picocli:picocli
io.airlift:aircompressor
io.grpc:grpc-alts
io.grpc:grpc-api
@@ -400,6 +401,7 @@ io.quarkus:quarkus-micrometer-registry-prometheus
io.quarkus:quarkus-mutiny
io.quarkus:quarkus-netty
io.quarkus:quarkus-opentelemetry
+io.quarkus:quarkus-picocli
io.quarkus:quarkus-reactive-routes
io.quarkus:quarkus-rest
io.quarkus:quarkus-rest-common
diff --git
a/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/EclipseLinkPolarisMetaStoreManagerFactory.java
b/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/EclipseLinkPolarisMetaStoreManagerFactory.java
index ade392be..5e27dddc 100644
---
a/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/EclipseLinkPolarisMetaStoreManagerFactory.java
+++
b/extension/persistence/eclipselink/src/main/java/org/apache/polaris/extension/persistence/impl/eclipselink/EclipseLinkPolarisMetaStoreManagerFactory.java
@@ -20,6 +20,7 @@ package
org.apache.polaris.extension.persistence.impl.eclipselink;
import io.smallrye.common.annotation.Identifier;
import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.nio.file.Path;
@@ -28,6 +29,7 @@ import org.apache.polaris.core.PolarisConfigurationStore;
import org.apache.polaris.core.PolarisDiagnostics;
import org.apache.polaris.core.context.RealmContext;
import org.apache.polaris.core.persistence.LocalPolarisMetaStoreManagerFactory;
+import org.apache.polaris.core.persistence.PolarisCredentialsBootstrap;
import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisMetaStoreSession;
import org.apache.polaris.core.storage.PolarisStorageIntegrationProvider;
@@ -70,6 +72,7 @@ public class EclipseLinkPolarisMetaStoreManagerFactory
protected PolarisMetaStoreSession createMetaStoreSession(
@Nonnull PolarisEclipseLinkStore store,
@Nonnull RealmContext realmContext,
+ @Nullable PolarisCredentialsBootstrap credentialsBootstrap,
@Nonnull PolarisDiagnostics diagnostics) {
return new PolarisEclipseLinkMetaStoreSessionImpl(
store,
@@ -77,7 +80,7 @@ public class EclipseLinkPolarisMetaStoreManagerFactory
realmContext,
configurationFile(),
persistenceUnitName(),
- secretsGenerator(realmContext),
+ secretsGenerator(realmContext, credentialsBootstrap),
diagnostics);
}
diff --git a/gradle/projects.main.properties b/gradle/projects.main.properties
index a6158793..193d7670 100644
--- a/gradle/projects.main.properties
+++ b/gradle/projects.main.properties
@@ -25,6 +25,7 @@ polaris-api-management-service=api/management-service
polaris-service-common=service/common
polaris-quarkus-service=quarkus/service
polaris-quarkus-server=quarkus/server
+polaris-quarkus-admin=quarkus/admin
polaris-eclipselink=extension/persistence/eclipselink
polaris-jpa-model=extension/persistence/jpa-model
polaris-tests=integration-tests
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
index bdea45ed..59d326dd 100644
---
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
+++
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/LocalPolarisMetaStoreManagerFactory.java
@@ -19,6 +19,7 @@
package org.apache.polaris.core.persistence;
import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
import java.time.Clock;
import java.util.HashMap;
import java.util.List;
@@ -58,8 +59,6 @@ public abstract class
LocalPolarisMetaStoreManagerFactory<StoreType>
private final PolarisDiagnostics diagnostics;
private final Clock clock;
- private boolean bootstrap;
-
protected LocalPolarisMetaStoreManagerFactory(
PolarisConfigurationStore configurationStore, PolarisDiagnostics
diagnostics, Clock clock) {
this.configurationStore = configurationStore;
@@ -72,21 +71,26 @@ public abstract class
LocalPolarisMetaStoreManagerFactory<StoreType>
protected abstract PolarisMetaStoreSession createMetaStoreSession(
@Nonnull StoreType store,
@Nonnull RealmContext realmContext,
+ @Nullable PolarisCredentialsBootstrap credentialsBootstrap,
@Nonnull PolarisDiagnostics diagnostics);
- protected PrincipalSecretsGenerator secretsGenerator(RealmContext
realmContext) {
- if (bootstrap) {
- return
PrincipalSecretsGenerator.bootstrap(realmContext.getRealmIdentifier());
+ protected PrincipalSecretsGenerator secretsGenerator(
+ RealmContext realmContext, @Nullable PolarisCredentialsBootstrap
credentialsBootstrap) {
+ if (credentialsBootstrap != null) {
+ return PrincipalSecretsGenerator.bootstrap(
+ realmContext.getRealmIdentifier(), credentialsBootstrap);
} else {
return PrincipalSecretsGenerator.RANDOM_SECRETS;
}
}
- private void initializeForRealm(RealmContext realmContext) {
+ private void initializeForRealm(
+ RealmContext realmContext, PolarisCredentialsBootstrap
credentialsBootstrap) {
final StoreType backingStore = createBackingStore(diagnostics);
sessionSupplierMap.put(
realmContext.getRealmIdentifier(),
- () -> createMetaStoreSession(backingStore, realmContext, diagnostics));
+ () ->
+ createMetaStoreSession(backingStore, realmContext,
credentialsBootstrap, diagnostics));
PolarisMetaStoreManager metaStoreManager =
new PolarisMetaStoreManagerImpl(realmContext, diagnostics,
configurationStore, clock);
@@ -94,23 +98,19 @@ public abstract class
LocalPolarisMetaStoreManagerFactory<StoreType>
}
@Override
- public synchronized Map<String, PrincipalSecretsResult>
bootstrapRealms(List<String> realms) {
+ public synchronized Map<String, PrincipalSecretsResult> bootstrapRealms(
+ List<String> realms, PolarisCredentialsBootstrap credentialsBootstrap) {
Map<String, PrincipalSecretsResult> results = new HashMap<>();
- bootstrap = true;
- try {
- for (String realm : realms) {
- RealmContext realmContext = () -> realm;
- if
(!metaStoreManagerMap.containsKey(realmContext.getRealmIdentifier())) {
- initializeForRealm(realmContext);
- PrincipalSecretsResult secretsResult =
- bootstrapServiceAndCreatePolarisPrincipalForRealm(
- realmContext,
metaStoreManagerMap.get(realmContext.getRealmIdentifier()));
- results.put(realmContext.getRealmIdentifier(), secretsResult);
- }
+ for (String realm : realms) {
+ RealmContext realmContext = () -> realm;
+ if (!metaStoreManagerMap.containsKey(realmContext.getRealmIdentifier()))
{
+ initializeForRealm(realmContext, credentialsBootstrap);
+ PrincipalSecretsResult secretsResult =
+ bootstrapServiceAndCreatePolarisPrincipalForRealm(
+ realmContext,
metaStoreManagerMap.get(realmContext.getRealmIdentifier()));
+ results.put(realmContext.getRealmIdentifier(), secretsResult);
}
- } finally {
- bootstrap = false;
}
return results;
@@ -134,7 +134,7 @@ public abstract class
LocalPolarisMetaStoreManagerFactory<StoreType>
public synchronized PolarisMetaStoreManager getOrCreateMetaStoreManager(
RealmContext realmContext) {
if (!metaStoreManagerMap.containsKey(realmContext.getRealmIdentifier())) {
- initializeForRealm(realmContext);
+ initializeForRealm(realmContext, null);
checkPolarisServiceBootstrappedForRealm(
realmContext,
metaStoreManagerMap.get(realmContext.getRealmIdentifier()));
}
@@ -145,7 +145,7 @@ public abstract class
LocalPolarisMetaStoreManagerFactory<StoreType>
public synchronized Supplier<PolarisMetaStoreSession>
getOrCreateSessionSupplier(
RealmContext realmContext) {
if (!sessionSupplierMap.containsKey(realmContext.getRealmIdentifier())) {
- initializeForRealm(realmContext);
+ initializeForRealm(realmContext, null);
checkPolarisServiceBootstrappedForRealm(
realmContext,
metaStoreManagerMap.get(realmContext.getRealmIdentifier()));
} else {
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/MetaStoreManagerFactory.java
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/MetaStoreManagerFactory.java
index 5d4691a5..4e37f034 100644
---
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/MetaStoreManagerFactory.java
+++
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/MetaStoreManagerFactory.java
@@ -37,7 +37,8 @@ public interface MetaStoreManagerFactory {
EntityCache getOrCreateEntityCache(RealmContext realmContext);
- Map<String, PrincipalSecretsResult> bootstrapRealms(List<String> realms);
+ Map<String, PrincipalSecretsResult> bootstrapRealms(
+ List<String> realms, PolarisCredentialsBootstrap credentialsBootstrap);
/** Purge all metadata for the realms provided */
void purgeRealms(List<String> realms);
diff --git
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrap.java
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrap.java
index fb702812..dc4f5b87 100644
---
a/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrap.java
+++
b/polaris-core/src/main/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrap.java
@@ -35,6 +35,9 @@ import org.apache.polaris.core.entity.PolarisPrincipalSecrets;
*/
public class PolarisCredentialsBootstrap {
+ public static final PolarisCredentialsBootstrap EMPTY =
+ new PolarisCredentialsBootstrap(new HashMap<>());
+
/**
* Parse credentials from the system property {@code
polaris.bootstrap.credentials} or the
* environment variable {@code POLARIS_BOOTSTRAP_CREDENTIALS}, whichever is
set.
@@ -55,35 +58,38 @@ public class PolarisCredentialsBootstrap {
* </pre>
*/
public static PolarisCredentialsBootstrap fromString(@Nullable String
credentialsString) {
+ return credentialsString != null && !credentialsString.isBlank()
+ ?
fromList(Splitter.on(';').trimResults().splitToList(credentialsString))
+ : EMPTY;
+ }
+
+ /**
+ * Parse a list of credentials; each element should be in the format: {@code
+ * realm,principal,clientId,clientSecret}.
+ */
+ public static PolarisCredentialsBootstrap fromList(List<String>
credentialsList) {
Map<String, Map<String, Map.Entry<String, String>>> credentials = new
HashMap<>();
- if (credentialsString != null && !credentialsString.isBlank()) {
- Splitter.on(';')
- .trimResults()
- .splitToList(credentialsString)
- .forEach(
- quadruple -> {
- if (!quadruple.isBlank()) {
- List<String> parts =
Splitter.on(',').trimResults().splitToList(quadruple);
- if (parts.size() != 4) {
- throw new IllegalArgumentException("Invalid credentials
format: " + quadruple);
- }
- String realmName = parts.get(0);
- String principalName = parts.get(1);
- String clientId = parts.get(2);
- String clientSecret = parts.get(3);
- credentials
- .computeIfAbsent(realmName, k -> new HashMap<>())
- .merge(
- principalName,
- new SimpleEntry<>(clientId, clientSecret),
- (a, b) -> {
- throw new IllegalArgumentException(
- "Duplicate principal: " + principalName);
- });
- }
- });
+ for (String quadruple : credentialsList) {
+ if (!quadruple.isBlank()) {
+ List<String> parts =
Splitter.on(',').trimResults().splitToList(quadruple);
+ if (parts.size() != 4) {
+ throw new IllegalArgumentException("Invalid credentials format: " +
quadruple);
+ }
+ String realmName = parts.get(0);
+ String principalName = parts.get(1);
+ String clientId = parts.get(2);
+ String clientSecret = parts.get(3);
+ credentials
+ .computeIfAbsent(realmName, k -> new HashMap<>())
+ .merge(
+ principalName,
+ new SimpleEntry<>(clientId, clientSecret),
+ (a, b) -> {
+ throw new IllegalArgumentException("Duplicate principal: " +
principalName);
+ });
+ }
}
- return new PolarisCredentialsBootstrap(credentials);
+ return credentials.isEmpty() ? EMPTY : new
PolarisCredentialsBootstrap(credentials);
}
@VisibleForTesting final Map<String, Map<String, Map.Entry<String, String>>>
credentials;
diff --git
a/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrapTest.java
b/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrapTest.java
index bd4c57c9..4cba20a7 100644
---
a/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrapTest.java
+++
b/polaris-core/src/test/java/org/apache/polaris/core/persistence/PolarisCredentialsBootstrapTest.java
@@ -22,6 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.Comparator;
+import java.util.List;
import org.apache.polaris.core.entity.PolarisPrincipalSecrets;
import org.junit.jupiter.api.Test;
@@ -87,6 +88,27 @@ class PolarisCredentialsBootstrapTest {
.contains(new PolarisPrincipalSecrets(123, "client2a", "secret2a",
"secret2a"));
}
+ @Test
+ void getSecretsValidList() {
+ PolarisCredentialsBootstrap credentials =
+ PolarisCredentialsBootstrap.fromList(
+ List.of(
+ "realm1,user1a,client1a,secret1a",
+ "realm1,user1b,client1b,secret1b",
+ "realm2,user2a,client2a,secret2a"));
+ assertThat(credentials.getSecrets("realm1", 123, "nonexistent")).isEmpty();
+ assertThat(credentials.getSecrets("nonexistent", 123, "user1a")).isEmpty();
+ assertThat(credentials.getSecrets("realm1", 123, "user1a"))
+ .usingValueComparator(comparator)
+ .contains(new PolarisPrincipalSecrets(123, "client1a", "secret1a",
"secret1a"));
+ assertThat(credentials.getSecrets("realm1", 123, "user1b"))
+ .usingValueComparator(comparator)
+ .contains(new PolarisPrincipalSecrets(123, "client1b", "secret1b",
"secret1b"));
+ assertThat(credentials.getSecrets("realm2", 123, "user2a"))
+ .usingValueComparator(comparator)
+ .contains(new PolarisPrincipalSecrets(123, "client2a", "secret2a",
"secret2a"));
+ }
+
@Test
void getSecretsValidSystemProperty() {
PolarisCredentialsBootstrap credentials =
PolarisCredentialsBootstrap.fromEnvironment();
diff --git a/quarkus/admin/README.md b/quarkus/admin/README.md
new file mode 100644
index 00000000..1058f91f
--- /dev/null
+++ b/quarkus/admin/README.md
@@ -0,0 +1,27 @@
+# Polaris Admin Tool
+
+This module contains a maintenance tool for performing administrative tasks on
the Polaris database.
+It is a Quarkus application that can be used to perform various maintenance
tasks targeting the
+Polaris database directly.
+
+Building this module will create a runnable uber-jar that can be executed from
the command line.
+
+To also build the Docker image, you can use the following command:
+
+```shell
+./gradlew :polaris-quarkus-admin:assemble -Dquarkus.container-image.build=true
+```
+
+## Running the Admin Tool
+
+The admin tool can be run from the command line using the following command:
+
+```shell
+java -jar polaris-quarkus-admin-<version>-runner.jar --help
+```
+
+Using the Docker image, you can run the admin tool with the following command:
+
+```shell
+docker run --rm -it apache/polaris-admin-tool:<version> --help
+```
\ No newline at end of file
diff --git a/quarkus/server/build.gradle.kts b/quarkus/admin/build.gradle.kts
similarity index 59%
copy from quarkus/server/build.gradle.kts
copy to quarkus/admin/build.gradle.kts
index 7f08e41c..f96066c3 100644
--- a/quarkus/server/build.gradle.kts
+++ b/quarkus/admin/build.gradle.kts
@@ -17,40 +17,61 @@
* under the License.
*/
+import io.quarkus.gradle.tasks.QuarkusBuild
+
plugins {
alias(libs.plugins.quarkus)
alias(libs.plugins.openapi.generator)
id("polaris-server")
id("polaris-license-report")
- id("distribution")
}
dependencies {
implementation(project(":polaris-core"))
+ implementation(project(":polaris-version"))
implementation(project(":polaris-api-management-service"))
implementation(project(":polaris-api-iceberg-service"))
implementation(project(":polaris-service-common"))
implementation(project(":polaris-quarkus-service"))
- // enforce the Quarkus _platform_ here, to get a consistent and validated
set of dependencies
implementation(enforcedPlatform(libs.quarkus.bom))
+ implementation("io.quarkus:quarkus-picocli")
implementation("io.quarkus:quarkus-container-image-docker")
+ implementation("org.jboss.slf4j:slf4j-jboss-logmanager")
+
// override dnsjava version in dependencies due to
https://github.com/dnsjava/dnsjava/issues/329
implementation(platform(libs.dnsjava))
-}
-tasks.named("distZip") { dependsOn("quarkusBuild") }
+ testImplementation(enforcedPlatform(libs.quarkus.bom))
+ testImplementation("io.quarkus:quarkus-junit5")
+}
-tasks.named("distTar") { dependsOn("quarkusBuild") }
+quarkus {
+ quarkusBuildProperties.put("quarkus.package.type", "uber-jar")
+ // Pull manifest attributes from the "main" `jar` task to get the
+ // release-information into the jars generated by Quarkus.
+ quarkusBuildProperties.putAll(
+ provider {
+ tasks
+ .named("jar", Jar::class.java)
+ .get()
+ .manifest
+ .attributes
+ .map { e -> "quarkus.package.jar.manifest.attributes.\"${e.key}\"" to
e.value.toString() }
+ .toMap()
+ }
+ )
+}
-distributions {
- main {
- contents {
- from(project.layout.buildDirectory.dir("quarkus-app"))
- from("../../NOTICE")
- from("../../LICENSE-BINARY-DIST").rename("LICENSE-BINARY-DIST",
"LICENSE")
- exclude("lib/main/io.quarkus.quarkus-container-image*")
+publishing {
+ publications {
+ named<MavenPublication>("maven") {
+ val quarkusBuild = tasks.getByName<QuarkusBuild>("quarkusBuild")
+ artifact(quarkusBuild.runnerJar) {
+ classifier = "runner"
+ builtBy(quarkusBuild)
+ }
}
}
}
diff --git a/gradle/projects.main.properties
b/quarkus/admin/src/main/docker/Dockerfile.jvm
similarity index 50%
copy from gradle/projects.main.properties
copy to quarkus/admin/src/main/docker/Dockerfile.jvm
index a6158793..9f992a30 100644
--- a/gradle/projects.main.properties
+++ b/quarkus/admin/src/main/docker/Dockerfile.jvm
@@ -7,7 +7,7 @@
# "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
+# 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
@@ -16,23 +16,27 @@
# specific language governing permissions and limitations
# under the License.
#
-#
+FROM registry.access.redhat.com/ubi9/openjdk-21:1.20-2.1726695192
+
+LABEL org.opencontainers.image.source=https://github.com/apache/polaris
+LABEL org.opencontainers.image.description="Apache Polaris (incubating) Admin
Tool"
+LABEL org.opencontainers.image.licenses=Apache-2.0
+
+ENV LANGUAGE='en_US:en'
+
+USER root
+RUN groupadd --gid 10001 polaris \
+ && useradd --uid 10000 --gid polaris polaris \
+ && chown -R polaris:polaris /opt/jboss/container \
+ && chown -R polaris:polaris /deployments
+
+USER polaris
+WORKDIR /deployments
+ENV USER=polaris
+ENV UID=10000
+ENV HOME=/home/polaris
+ENV PWD=/deployments
-polaris-core=polaris-core
-polaris-api-iceberg-service=api/iceberg-service
-polaris-api-management-model=api/management-model
-polaris-api-management-service=api/management-service
-polaris-service-common=service/common
-polaris-quarkus-service=quarkus/service
-polaris-quarkus-server=quarkus/server
-polaris-eclipselink=extension/persistence/eclipselink
-polaris-jpa-model=extension/persistence/jpa-model
-polaris-tests=integration-tests
-aggregated-license-report=aggregated-license-report
-polaris-immutables=tools/immutables
-polaris-container-spec-helper=tools/container-spec-helper
-polaris-version=tools/version
+COPY --chown=polaris:polaris build/*-runner.jar
/deployments/polaris-server-admin-tool.jar
-polaris-config-docs-annotations=tools/config-docs/annotations
-polaris-config-docs-generator=tools/config-docs/generator
-polaris-config-docs-site=tools/config-docs/site
+ENTRYPOINT [ "java", "-jar", "/deployments/polaris-server-admin-tool.jar" ]
\ No newline at end of file
diff --git
a/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/BaseCommand.java
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/BaseCommand.java
new file mode 100644
index 00000000..6b690c76
--- /dev/null
+++
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/BaseCommand.java
@@ -0,0 +1,54 @@
+/*
+ * 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.service.quarkus.admin;
+
+import jakarta.inject.Inject;
+import java.util.concurrent.Callable;
+import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import
org.apache.polaris.service.quarkus.persistence.QuarkusPersistenceConfiguration;
+import picocli.CommandLine.Model.CommandSpec;
+import picocli.CommandLine.Spec;
+
+public abstract class BaseCommand implements Callable<Integer> {
+
+ public static final Integer EXIT_CODE_BOOTSTRAP_ERROR = 3;
+ public static final Integer EXIT_CODE_PURGE_ERROR = 4;
+
+ @Inject QuarkusPersistenceConfiguration persistenceConfiguration;
+
+ @Inject MetaStoreManagerFactory metaStoreManagerFactory;
+
+ @Spec CommandSpec spec;
+
+ protected void warnOnInMemory() {
+ if (persistenceConfiguration.type().equalsIgnoreCase("in-memory")) {
+ spec.commandLine()
+ .getErr()
+ .println(
+ spec.commandLine()
+ .getColorScheme()
+ .errorText(
+ """
+
*********************************************************************************************
+ ** Running the Admin Tool on a Polaris instance with
in-memory persistence is meaningless! **
+
*********************************************************************************************
+ """));
+ }
+ }
+}
diff --git
a/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/BootstrapCommand.java
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/BootstrapCommand.java
new file mode 100644
index 00000000..5d9f5bec
--- /dev/null
+++
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/BootstrapCommand.java
@@ -0,0 +1,80 @@
+/*
+ * 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.service.quarkus.admin;
+
+import java.util.List;
+import java.util.Map;
+import
org.apache.polaris.core.auth.PolarisSecretsManager.PrincipalSecretsResult;
+import org.apache.polaris.core.persistence.PolarisCredentialsBootstrap;
+import picocli.CommandLine;
+
[email protected](
+ name = "bootstrap",
+ mixinStandardHelpOptions = true,
+ description = "Bootstraps realms and principal credentials.")
+public class BootstrapCommand extends BaseCommand {
+
+ @CommandLine.Option(
+ names = {"-r", "--realm"},
+ required = true,
+ description = "The name of a realm to bootstrap.")
+ List<String> realms;
+
+ @CommandLine.Option(
+ names = {"-c", "--credential"},
+ description =
+ "Principal credentials to bootstrap. Must be of the form
'realm,userName,clientId,clientSecret'.")
+ List<String> credentials;
+
+ @Override
+ public Integer call() {
+ warnOnInMemory();
+
+ PolarisCredentialsBootstrap credentialsBootstrap =
+ credentials == null || credentials.isEmpty()
+ ? PolarisCredentialsBootstrap.EMPTY
+ : PolarisCredentialsBootstrap.fromList(credentials);
+
+ // Execute the bootstrap
+ Map<String, PrincipalSecretsResult> results =
+ metaStoreManagerFactory.bootstrapRealms(realms, credentialsBootstrap);
+
+ // Log any errors:
+ boolean success = true;
+ for (Map.Entry<String, PrincipalSecretsResult> result :
results.entrySet()) {
+ if (!result.getValue().isSuccess()) {
+ String realm = result.getKey();
+ spec.commandLine()
+ .getErr()
+ .printf(
+ "Bootstrapping '%s' failed: %s%n",
+ realm, result.getValue().getReturnStatus().toString());
+ success = false;
+ }
+ }
+
+ if (success) {
+ spec.commandLine().getOut().println("Bootstrap completed successfully.");
+ return 0;
+ } else {
+ spec.commandLine().getErr().println("Bootstrap encountered errors during
operation.");
+ return EXIT_CODE_BOOTSTRAP_ERROR;
+ }
+ }
+}
diff --git
a/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PolarisAdminTool.java
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PolarisAdminTool.java
new file mode 100644
index 00000000..3b332735
--- /dev/null
+++
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PolarisAdminTool.java
@@ -0,0 +1,54 @@
+/*
+ * 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.service.quarkus.admin;
+
+import io.quarkus.picocli.runtime.annotations.TopCommand;
+import java.io.PrintWriter;
+import picocli.CommandLine.Command;
+import picocli.CommandLine.HelpCommand;
+
+@TopCommand
+@Command(
+ name = "polaris-quarkus-admin-runner.jar",
+ mixinStandardHelpOptions = true,
+ versionProvider = PolarisVersionProvider.class,
+ description = "Polaris Admin Tool",
+ subcommands = {
+ HelpCommand.class,
+ BootstrapCommand.class,
+ PurgeCommand.class,
+ })
+public class PolarisAdminTool extends BaseCommand {
+
+ @Override
+ public Integer call() {
+ return info();
+ }
+
+ private int info() {
+ warnOnInMemory();
+
+ PrintWriter out = spec.commandLine().getOut();
+
+ out.println("Polaris administration & maintenance tool.");
+ out.println("Use the 'help' command.");
+ out.println();
+ return 0;
+ }
+}
diff --git
a/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PolarisVersionProvider.java
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PolarisVersionProvider.java
new file mode 100644
index 00000000..8c252113
--- /dev/null
+++
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PolarisVersionProvider.java
@@ -0,0 +1,30 @@
+/*
+ * 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.service.quarkus.admin;
+
+import org.apache.polaris.version.PolarisVersion;
+import picocli.CommandLine.IVersionProvider;
+
+public class PolarisVersionProvider implements IVersionProvider {
+
+ @Override
+ public String[] getVersion() {
+ return new String[] {PolarisVersion.polarisVersionString()};
+ }
+}
diff --git
a/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PurgeCommand.java
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PurgeCommand.java
new file mode 100644
index 00000000..63963c12
--- /dev/null
+++
b/quarkus/admin/src/main/java/org/apache/polaris/service/quarkus/admin/PurgeCommand.java
@@ -0,0 +1,49 @@
+/*
+ * 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.service.quarkus.admin;
+
+import java.util.List;
+import picocli.CommandLine;
+
[email protected](
+ name = "purge",
+ mixinStandardHelpOptions = true,
+ description = "Purge principal credentials.")
+public class PurgeCommand extends BaseCommand {
+
+ @CommandLine.Option(
+ names = {"-r", "--realm"},
+ required = true,
+ description = "The name of a realm to purge.")
+ List<String> realms;
+
+ @Override
+ public Integer call() {
+ warnOnInMemory();
+
+ try {
+ metaStoreManagerFactory.purgeRealms(realms);
+ spec.commandLine().getOut().println("Purge completed successfully.");
+ return 0;
+ } catch (Exception e) {
+ spec.commandLine().getErr().println("Purge encountered errors during
operation.");
+ return EXIT_CODE_PURGE_ERROR;
+ }
+ }
+}
diff --git a/quarkus/server/src/main/resources/application.properties
b/quarkus/admin/src/main/resources/application.properties
similarity index 85%
copy from quarkus/server/src/main/resources/application.properties
copy to quarkus/admin/src/main/resources/application.properties
index 3f5018a7..8f963cc5 100644
--- a/quarkus/server/src/main/resources/application.properties
+++ b/quarkus/admin/src/main/resources/application.properties
@@ -17,10 +17,11 @@
# under the License.
#
-quarkus.application.name=Apache Polaris Server (incubating)
+quarkus.application.name=Apache Polaris Admin Tool (incubating)
quarkus.container-image.build=false
quarkus.container-image.push=false
quarkus.container-image.registry=docker.io
quarkus.container-image.group=apache
-quarkus.container-image.name=polaris
+quarkus.container-image.name=polaris-admin-tool
+quarkus.container-image.additional-tags=latest
diff --git
a/quarkus/admin/src/test/java/org/apache/polaris/service/quarkus/admin/BootstrapCommandTest.java
b/quarkus/admin/src/test/java/org/apache/polaris/service/quarkus/admin/BootstrapCommandTest.java
new file mode 100644
index 00000000..0e964c07
--- /dev/null
+++
b/quarkus/admin/src/test/java/org/apache/polaris/service/quarkus/admin/BootstrapCommandTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.service.quarkus.admin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import io.quarkus.test.junit.main.Launch;
+import io.quarkus.test.junit.main.LaunchResult;
+import io.quarkus.test.junit.main.QuarkusMainTest;
+import org.junit.jupiter.api.Test;
+
+@QuarkusMainTest
+class BootstrapCommandTest {
+
+ @Test
+ @Launch(
+ value = {
+ "bootstrap",
+ "-r",
+ "realm1",
+ "-r",
+ "realm2",
+ "-c",
+ "realm1,root,root,s3cr3t",
+ "-c",
+ "realm2,root,root,s3cr3t"
+ })
+ public void testBootstrap(LaunchResult result) {
+ assertThat(result.getOutput()).contains("Bootstrap completed
successfully.");
+ }
+}
diff --git
a/quarkus/admin/src/test/java/org/apache/polaris/service/quarkus/admin/PurgeCommandTest.java
b/quarkus/admin/src/test/java/org/apache/polaris/service/quarkus/admin/PurgeCommandTest.java
new file mode 100644
index 00000000..902cf8a1
--- /dev/null
+++
b/quarkus/admin/src/test/java/org/apache/polaris/service/quarkus/admin/PurgeCommandTest.java
@@ -0,0 +1,36 @@
+/*
+ * 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.service.quarkus.admin;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import io.quarkus.test.junit.main.Launch;
+import io.quarkus.test.junit.main.LaunchResult;
+import io.quarkus.test.junit.main.QuarkusMainTest;
+import org.junit.jupiter.api.Test;
+
+@QuarkusMainTest
+class PurgeCommandTest {
+
+ @Test
+ @Launch(value = {"purge", "-r", "realm1", "-r", "realm2"})
+ public void testPurge(LaunchResult result) {
+ assertThat(result.getOutput()).contains("Purge completed successfully.");
+ }
+}
diff --git a/quarkus/server/README.md b/quarkus/server/README.md
index 7fb773ec..bac32962 100644
--- a/quarkus/server/README.md
+++ b/quarkus/server/README.md
@@ -8,5 +8,15 @@ To also build the Docker image, you can use the following
command (a running Doc
required):
```shell
-./gradlew :polaris-quarkus-server:build -Dquarkus.container-image.build=true
+./gradlew :polaris-quarkus-server:assemble -Dquarkus.container-image.build=true
```
+
+If you need to customize the Docker image, for example to push to a local
registry, you can use the
+following command:
+
+```shell
+./gradlew :polaris-quarkus-server:build -Dquarkus.container-image.build=true \
+ -Dquarkus.container-image.registry=localhost:5001 \
+ -Dquarkus.container-image.group=apache \
+ -Dquarkus.container-image.name=polaris-local
+```
\ No newline at end of file
diff --git a/quarkus/server/build.gradle.kts b/quarkus/server/build.gradle.kts
index 7f08e41c..83e94435 100644
--- a/quarkus/server/build.gradle.kts
+++ b/quarkus/server/build.gradle.kts
@@ -40,6 +40,23 @@ dependencies {
implementation(platform(libs.dnsjava))
}
+quarkus {
+ quarkusBuildProperties.put("quarkus.package.type", "fast-jar")
+ // Pull manifest attributes from the "main" `jar` task to get the
+ // release-information into the jars generated by Quarkus.
+ quarkusBuildProperties.putAll(
+ provider {
+ tasks
+ .named("jar", Jar::class.java)
+ .get()
+ .manifest
+ .attributes
+ .map { e -> "quarkus.package.jar.manifest.attributes.\"${e.key}\"" to
e.value.toString() }
+ .toMap()
+ }
+ )
+}
+
tasks.named("distZip") { dependsOn("quarkusBuild") }
tasks.named("distTar") { dependsOn("quarkusBuild") }
diff --git a/quarkus/server/src/main/resources/application.properties
b/quarkus/server/src/main/resources/application.properties
index 3f5018a7..3c628e38 100644
--- a/quarkus/server/src/main/resources/application.properties
+++ b/quarkus/server/src/main/resources/application.properties
@@ -24,3 +24,4 @@ quarkus.container-image.push=false
quarkus.container-image.registry=docker.io
quarkus.container-image.group=apache
quarkus.container-image.name=polaris
+quarkus.container-image.additional-tags=latest
diff --git
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/BasePolarisCatalogTest.java
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/BasePolarisCatalogTest.java
index 20d0fd0b..f4c44545 100644
---
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/BasePolarisCatalogTest.java
+++
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/catalog/BasePolarisCatalogTest.java
@@ -81,6 +81,7 @@ import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.entity.PrincipalEntity;
import org.apache.polaris.core.entity.TaskEntity;
import org.apache.polaris.core.persistence.MetaStoreManagerFactory;
+import org.apache.polaris.core.persistence.PolarisCredentialsBootstrap;
import org.apache.polaris.core.persistence.PolarisEntityManager;
import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisMetaStoreSession;
@@ -310,7 +311,8 @@ public class BasePolarisCatalogTest extends
CatalogTests<BasePolarisCatalog> {
}
@Override
- public Map<String, PrincipalSecretsResult> bootstrapRealms(List<String>
realms) {
+ public Map<String, PrincipalSecretsResult> bootstrapRealms(
+ List<String> realms, PolarisCredentialsBootstrap
credentialsBootstrap) {
throw new NotImplementedException("Bootstrapping realms is not
supported");
}
diff --git
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
index 68f32758..b7e38dd4 100644
---
a/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
+++
b/quarkus/service/src/test/java/org/apache/polaris/service/quarkus/test/PolarisIntegrationTestFixture.java
@@ -40,6 +40,7 @@ import org.apache.polaris.core.entity.PolarisEntityConstants;
import org.apache.polaris.core.entity.PolarisEntitySubType;
import org.apache.polaris.core.entity.PolarisEntityType;
import org.apache.polaris.core.entity.PolarisPrincipalSecrets;
+import org.apache.polaris.core.persistence.PolarisCredentialsBootstrap;
import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisMetaStoreSession;
import
org.apache.polaris.service.persistence.InMemoryPolarisMetaStoreManagerFactory;
@@ -95,7 +96,8 @@ public class PolarisIntegrationTestFixture {
private PolarisPrincipalSecrets fetchAdminSecrets() {
if (!(helper.metaStoreManagerFactory instanceof
InMemoryPolarisMetaStoreManagerFactory)) {
- helper.metaStoreManagerFactory.bootstrapRealms(List.of(realm));
+ helper.metaStoreManagerFactory.bootstrapRealms(
+ List.of(realm), PolarisCredentialsBootstrap.fromEnvironment());
}
RealmContext realmContext = () -> realm;
diff --git
a/service/common/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
b/service/common/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
index 0c3cc6ec..995e84b9 100644
---
a/service/common/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
+++
b/service/common/src/main/java/org/apache/polaris/service/persistence/InMemoryPolarisMetaStoreManagerFactory.java
@@ -20,6 +20,7 @@ package org.apache.polaris.service.persistence;
import io.smallrye.common.annotation.Identifier;
import jakarta.annotation.Nonnull;
+import jakarta.annotation.Nullable;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.time.Clock;
@@ -33,6 +34,7 @@ import org.apache.polaris.core.PolarisDiagnostics;
import
org.apache.polaris.core.auth.PolarisSecretsManager.PrincipalSecretsResult;
import org.apache.polaris.core.context.RealmContext;
import org.apache.polaris.core.persistence.LocalPolarisMetaStoreManagerFactory;
+import org.apache.polaris.core.persistence.PolarisCredentialsBootstrap;
import org.apache.polaris.core.persistence.PolarisMetaStoreManager;
import org.apache.polaris.core.persistence.PolarisMetaStoreSession;
import org.apache.polaris.core.persistence.PolarisTreeMapMetaStoreSessionImpl;
@@ -75,9 +77,13 @@ public class InMemoryPolarisMetaStoreManagerFactory
protected PolarisMetaStoreSession createMetaStoreSession(
@Nonnull PolarisTreeMapStore store,
@Nonnull RealmContext realmContext,
+ @Nullable PolarisCredentialsBootstrap credentialsBootstrap,
@Nonnull PolarisDiagnostics diagnostics) {
return new PolarisTreeMapMetaStoreSessionImpl(
- store, storageIntegration, secretsGenerator(realmContext),
diagnostics);
+ store,
+ storageIntegration,
+ secretsGenerator(realmContext, credentialsBootstrap),
+ diagnostics);
}
@Override
@@ -102,7 +108,8 @@ public class InMemoryPolarisMetaStoreManagerFactory
private void bootstrapRealmAndPrintCredentials(String realmId) {
Map<String, PrincipalSecretsResult> results =
- this.bootstrapRealms(Collections.singletonList(realmId));
+ this.bootstrapRealms(
+ Collections.singletonList(realmId),
PolarisCredentialsBootstrap.fromEnvironment());
bootstrappedRealms.add(realmId);
PrincipalSecretsResult principalSecrets = results.get(realmId);