diff --git a/atlasdb-api/src/main/java/com/palantir/atlasdb/timestamp/DbTimeLockFactory.java b/atlasdb-api/src/main/java/com/palantir/atlasdb/timestamp/DbTimeLockFactory.java index cf2630cd784..60dea8f06ae 100644 --- a/atlasdb-api/src/main/java/com/palantir/atlasdb/timestamp/DbTimeLockFactory.java +++ b/atlasdb-api/src/main/java/com/palantir/atlasdb/timestamp/DbTimeLockFactory.java @@ -22,8 +22,11 @@ import com.palantir.atlasdb.keyvalue.api.TableReference; import com.palantir.atlasdb.keyvalue.api.TimestampSeriesProvider; import com.palantir.atlasdb.spi.KeyValueServiceConfig; +import com.palantir.atlasdb.spi.KeyValueServiceRuntimeConfig; import com.palantir.atlasdb.util.MetricsManager; +import com.palantir.refreshable.Refreshable; import com.palantir.timestamp.ManagedTimestampService; +import java.util.Optional; /** * See {@link com.palantir.atlasdb.spi.AtlasDbFactory}. A {@link DbTimeLockFactory} is an extension of an @@ -33,8 +36,21 @@ public interface DbTimeLockFactory { String getType(); + /** + * @deprecated Creating a DbKeyValueService with this method will not support live reloading the DB password. Use + * {@link #createRawKeyValueService(MetricsManager, KeyValueServiceConfig, Refreshable, LeaderConfig)} instead. + */ + @Deprecated + default KeyValueService createRawKeyValueService( + MetricsManager metricsManager, KeyValueServiceConfig config, LeaderConfig leaderConfig) { + return createRawKeyValueService(metricsManager, config, Refreshable.only(Optional.empty()), leaderConfig); + } + KeyValueService createRawKeyValueService( - MetricsManager metricsManager, KeyValueServiceConfig config, LeaderConfig leaderConfig); + MetricsManager metricManager, + KeyValueServiceConfig config, + Refreshable> runtimeConfig, + LeaderConfig leaderConfig); ManagedTimestampService createManagedTimestampService( KeyValueService rawKvs, DbTimestampCreationSetting dbTimestampCreationSetting, boolean initializeAsync); diff --git a/atlasdb-dbkvs-hikari/src/main/java/com/palantir/nexus/db/pool/config/ConnectionConfig.java b/atlasdb-dbkvs-hikari/src/main/java/com/palantir/nexus/db/pool/config/ConnectionConfig.java index 7dbab26897a..1464df417db 100644 --- a/atlasdb-dbkvs-hikari/src/main/java/com/palantir/nexus/db/pool/config/ConnectionConfig.java +++ b/atlasdb-dbkvs-hikari/src/main/java/com/palantir/nexus/db/pool/config/ConnectionConfig.java @@ -44,7 +44,14 @@ public abstract class ConnectionConfig { public abstract String getDbLogin(); - public abstract MaskedValue getDbPassword(); + /** + * If a runtime config is present, this does not need to be set and will not be used. A default value is provided + * so that the config will parse when this field is missing. + */ + @Value.Default + public MaskedValue getDbPassword() { + return ImmutableMaskedValue.of(""); + } public abstract String getUrl(); diff --git a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbAtlasDbFactory.java b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbAtlasDbFactory.java index f9963f7695e..79d3d319d77 100644 --- a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbAtlasDbFactory.java +++ b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbAtlasDbFactory.java @@ -69,7 +69,7 @@ public KeyValueService createRawKeyValueService( config instanceof DbKeyValueServiceConfig, "DbAtlasDbFactory expects a configuration of type DbKeyValueServiceConfiguration, found %s", config.getClass()); - return ConnectionManagerAwareDbKvs.create((DbKeyValueServiceConfig) config, initializeAsync); + return ConnectionManagerAwareDbKvs.create((DbKeyValueServiceConfig) config, runtimeConfig, initializeAsync); } @Override diff --git a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbKeyValueServiceRuntimeConfig.java b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbKeyValueServiceRuntimeConfig.java new file mode 100644 index 00000000000..f46b9d3b51e --- /dev/null +++ b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/DbKeyValueServiceRuntimeConfig.java @@ -0,0 +1,38 @@ +/* + * (c) Copyright 2021 Palantir Technologies Inc. All rights reserved. + * + * Licensed 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 com.palantir.atlasdb.keyvalue.dbkvs; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.auto.service.AutoService; +import com.palantir.atlasdb.spi.KeyValueServiceRuntimeConfig; +import com.palantir.nexus.db.pool.config.MaskedValue; +import org.immutables.value.Value; + +@AutoService(KeyValueServiceRuntimeConfig.class) +@JsonSerialize(as = ImmutableDbKeyValueServiceRuntimeConfig.class) +@JsonDeserialize(as = ImmutableDbKeyValueServiceRuntimeConfig.class) +@Value.Immutable +public abstract class DbKeyValueServiceRuntimeConfig implements KeyValueServiceRuntimeConfig { + + @Override + public String type() { + return DbAtlasDbFactory.TYPE; + } + + public abstract MaskedValue getDbPassword(); +} diff --git a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/RelationalDbTimeLockFactory.java b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/RelationalDbTimeLockFactory.java index 31a49f985c3..72917d3beb9 100644 --- a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/RelationalDbTimeLockFactory.java +++ b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/RelationalDbTimeLockFactory.java @@ -30,6 +30,7 @@ import com.palantir.atlasdb.keyvalue.dbkvs.timestamp.MultiSequenceTimestampSeriesProvider; import com.palantir.atlasdb.spi.AtlasDbFactory; import com.palantir.atlasdb.spi.KeyValueServiceConfig; +import com.palantir.atlasdb.spi.KeyValueServiceRuntimeConfig; import com.palantir.atlasdb.timestamp.DbTimeLockFactory; import com.palantir.atlasdb.util.MetricsManager; import com.palantir.refreshable.Refreshable; @@ -51,11 +52,14 @@ public String getType() { @Override public KeyValueService createRawKeyValueService( - MetricsManager metricsManager, KeyValueServiceConfig config, LeaderConfig leaderConfig) { + MetricsManager metricsManager, + KeyValueServiceConfig config, + Refreshable> runtimeConfig, + LeaderConfig leaderConfig) { return delegate.createRawKeyValueService( metricsManager, config, - Refreshable.only(Optional.empty()), + runtimeConfig, Optional.of(leaderConfig), Optional.empty(), // This refers to an AtlasDB namespace - we use the config to talk to the db AtlasDbFactory.THROWING_FRESH_TIMESTAMP_SOURCE, // This is how we give out timestamps! diff --git a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/impl/ConnectionManagerAwareDbKvs.java b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/impl/ConnectionManagerAwareDbKvs.java index 06194b33e3c..d23f4304603 100644 --- a/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/impl/ConnectionManagerAwareDbKvs.java +++ b/atlasdb-dbkvs/src/main/java/com/palantir/atlasdb/keyvalue/dbkvs/impl/ConnectionManagerAwareDbKvs.java @@ -19,7 +19,9 @@ import com.palantir.atlasdb.AtlasDbConstants; import com.palantir.atlasdb.keyvalue.api.KeyValueService; import com.palantir.atlasdb.keyvalue.dbkvs.DbKeyValueServiceConfig; +import com.palantir.atlasdb.keyvalue.dbkvs.DbKeyValueServiceRuntimeConfig; import com.palantir.atlasdb.keyvalue.impl.ForwardingKeyValueService; +import com.palantir.atlasdb.spi.KeyValueServiceRuntimeConfig; import com.palantir.nexus.db.monitoring.timer.SqlTimer; import com.palantir.nexus.db.monitoring.timer.SqlTimers; import com.palantir.nexus.db.pool.ConnectionManager; @@ -29,7 +31,9 @@ import com.palantir.nexus.db.sql.SQL; import com.palantir.nexus.db.sql.SqlConnection; import com.palantir.nexus.db.sql.SqlConnectionHelper; +import com.palantir.refreshable.Refreshable; import java.sql.Connection; +import java.util.Optional; import java.util.function.Supplier; // This class should be removed and replaced by DbKvs when InDbTimestampStore depends directly on DbKvs @@ -38,18 +42,49 @@ public final class ConnectionManagerAwareDbKvs extends ForwardingKeyValueService private final ConnectionManager connManager; private final SqlConnectionSupplier sqlConnectionSupplier; + /** + * @deprecated This method does not support live reloading the DB password. Use + * {@link #create(DbKeyValueServiceConfig, Refreshable, boolean)} instead. + */ + @Deprecated public static ConnectionManagerAwareDbKvs create(DbKeyValueServiceConfig config) { return create(config, AtlasDbConstants.DEFAULT_INITIALIZE_ASYNC); } + /** + * @deprecated This method does not support live reloading the DB password. Use + * {@link #create(DbKeyValueServiceConfig, Refreshable, boolean)} instead. + */ + @Deprecated public static ConnectionManagerAwareDbKvs create(DbKeyValueServiceConfig config, boolean initializeAsync) { + return create(config, Refreshable.only(Optional.empty()), initializeAsync); + } + + public static ConnectionManagerAwareDbKvs create( + DbKeyValueServiceConfig config, + Refreshable> runtimeConfig, + boolean initializeAsync) { HikariCPConnectionManager connManager = new HikariCPConnectionManager(config.connection()); + runtimeConfig.subscribe(newRuntimeConfig -> updateConnManagerConfig(connManager, config, newRuntimeConfig)); ReentrantManagedConnectionSupplier connSupplier = new ReentrantManagedConnectionSupplier(connManager); SqlConnectionSupplier sqlConnSupplier = getSimpleTimedSqlConnectionSupplier(connSupplier); return new ConnectionManagerAwareDbKvs( DbKvs.create(config, sqlConnSupplier, initializeAsync), connManager, sqlConnSupplier); } + private static void updateConnManagerConfig( + HikariCPConnectionManager connManager, + DbKeyValueServiceConfig config, + Optional runtimeConfig) { + if (runtimeConfig.isPresent() && runtimeConfig.get() instanceof DbKeyValueServiceRuntimeConfig) { + DbKeyValueServiceRuntimeConfig dbRuntimeConfig = (DbKeyValueServiceRuntimeConfig) runtimeConfig.get(); + connManager.setPassword(dbRuntimeConfig.getDbPassword().unmasked()); + } else { + // no runtime config (or wrong type), use the password from the install config + connManager.setPassword(config.connection().getDbPassword().unmasked()); + } + } + private static SqlConnectionSupplier getSimpleTimedSqlConnectionSupplier( ReentrantManagedConnectionSupplier connectionSupplier) { Supplier supplier = connectionSupplier; diff --git a/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/memory/InMemoryDbTimeLockFactory.java b/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/memory/InMemoryDbTimeLockFactory.java index c7de4ba0868..d70386872c8 100644 --- a/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/memory/InMemoryDbTimeLockFactory.java +++ b/atlasdb-impl-shared/src/main/java/com/palantir/atlasdb/memory/InMemoryDbTimeLockFactory.java @@ -25,12 +25,15 @@ import com.palantir.atlasdb.keyvalue.api.TimestampSeriesProvider; import com.palantir.atlasdb.keyvalue.impl.InMemoryKeyValueService; import com.palantir.atlasdb.spi.KeyValueServiceConfig; +import com.palantir.atlasdb.spi.KeyValueServiceRuntimeConfig; import com.palantir.atlasdb.timestamp.DbTimeLockFactory; import com.palantir.atlasdb.util.MetricsManager; +import com.palantir.refreshable.Refreshable; import com.palantir.timestamp.InMemoryTimestampService; import com.palantir.timestamp.ManagedTimestampService; import java.util.HashMap; import java.util.Map; +import java.util.Optional; @AutoService(DbTimeLockFactory.class) public class InMemoryDbTimeLockFactory implements DbTimeLockFactory { @@ -43,7 +46,10 @@ public String getType() { @Override public KeyValueService createRawKeyValueService( - MetricsManager metricsManager, KeyValueServiceConfig config, LeaderConfig leaderConfig) { + MetricsManager metricManager, + KeyValueServiceConfig config, + Refreshable> runtimeConfig, + LeaderConfig leaderConfig) { return new InMemoryKeyValueService(true); } diff --git a/changelog/@unreleased/pr-5365.v2.yml b/changelog/@unreleased/pr-5365.v2.yml new file mode 100644 index 00000000000..435b93116c0 --- /dev/null +++ b/changelog/@unreleased/pr-5365.v2.yml @@ -0,0 +1,6 @@ +type: improvement +improvement: + description: |- + Adds supports for live password changes for products that use the standard atlas install and runtime config. To take advantage of this products must add a runtime config for dbkvs (this appears in the same place as the cassandra runtime config would appear but has type "relational"). No behavior is changed when the new dbkvs runtime config is absent. + links: + - https://github.com/palantir/atlasdb/pull/5365