diff options
15 files changed, 108 insertions, 59 deletions
diff --git a/client/js/app/yarn.lock b/client/js/app/yarn.lock index ad0fe1145d3..cb1e25b562d 100644 --- a/client/js/app/yarn.lock +++ b/client/js/app/yarn.lock @@ -4778,9 +4778,9 @@ prettier-linter-helpers@^1.0.0: fast-diff "^1.1.2" prettier@3: - version "3.3.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.1.tgz#e68935518dd90bb7ec4821ba970e68f8de16e1ac" - integrity sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg== + version "3.3.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.3.2.tgz#03ff86dc7c835f2d2559ee76876a3914cec4a90a" + integrity sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA== pretty-format@^29.7.0: version "29.7.0" diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index 5833662ff66..fe50b86ebb3 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -1389,7 +1389,8 @@ "public boolean allowUserFilters()", "public java.time.Duration endpointConnectionTtl()", "public java.util.List dataplaneTokens()", - "public java.util.List requestPrefixForLoggingContent()" + "public java.util.List requestPrefixForLoggingContent()", + "public boolean launchApplicationAthenzService()" ], "fields" : [ ] }, diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index b4c101600da..670c989cf5b 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -176,6 +176,8 @@ public interface ModelContext { default List<String> requestPrefixForLoggingContent() { return List.of(); } + default boolean launchApplicationAthenzService() { return false; } + } @Retention(RetentionPolicy.RUNTIME) diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index 5b144f5950a..c2d6adddeed 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -85,6 +85,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea private boolean logserverOtelCol = false; private boolean symmetricPutAndActivateReplicaSelection = false; private boolean enforceStrictlyIncreasingClusterStateVersions = false; + private boolean launchApplicationAthenzService = false; @Override public ModelContext.FeatureFlags featureFlags() { return this; } @Override public boolean multitenant() { return multitenant; } @@ -144,6 +145,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea @Override public boolean logserverOtelCol() { return logserverOtelCol; } @Override public boolean symmetricPutAndActivateReplicaSelection() { return symmetricPutAndActivateReplicaSelection; } @Override public boolean enforceStrictlyIncreasingClusterStateVersions() { return enforceStrictlyIncreasingClusterStateVersions; } + @Override public boolean launchApplicationAthenzService() { return launchApplicationAthenzService; } public TestProperties sharedStringRepoNoReclaim(boolean sharedStringRepoNoReclaim) { this.sharedStringRepoNoReclaim = sharedStringRepoNoReclaim; @@ -389,6 +391,11 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea return this; } + public TestProperties setLaunchApplicationAthenzService(boolean launch) { + this.launchApplicationAthenzService = launch; + return this; + } + public static class Spec implements ConfigServerSpec { private final String hostName; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java index d3f5407b0f9..4995c20b985 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java @@ -140,6 +140,8 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { // Default path to vip status file for container in Hosted Vespa. static final String HOSTED_VESPA_STATUS_FILE = Defaults.getDefaults().underVespaHome("var/vespa/load-balancer/status.html"); + static final String HOSTED_VESPA_TENANT_PARENT_DOMAIN = "vespa.tenant."; + //Path to vip status file for container in Hosted Vespa. Only used if set, else use HOSTED_VESPA_STATUS_FILE private static final String HOSTED_VESPA_STATUS_FILE_SETTING = "VESPA_LB_STATUS_FILE"; @@ -235,6 +237,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { // Must be added after nodes: addDeploymentSpecConfig(cluster, context, deployState.getDeployLogger()); addZooKeeper(cluster, spec); + addAthenzServiceIdentityProvider(cluster, context, deployState.getDeployLogger()); addParameterStoreValidationHandler(cluster, deployState); } @@ -344,6 +347,20 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { cluster.addComponent(cloudSecretStore); } + private void addAthenzServiceIdentityProvider(ApplicationContainerCluster cluster, ConfigModelContext context, DeployLogger deployLogger) { + if ( ! context.getDeployState().isHosted()) return; + if ( ! context.getDeployState().zone().system().isPublic()) return; // Non-public is handled by deployment spec config. + if ( ! context.properties().launchApplicationAthenzService()) return; + addIdentityProvider(cluster, + context.getDeployState().getProperties().configServerSpecs(), + context.getDeployState().getProperties().loadBalancerName(), + context.getDeployState().getProperties().ztsUrl(), + context.getDeployState().getProperties().athenzDnsSuffix(), + context.getDeployState().zone(), + AthenzDomain.from(HOSTED_VESPA_TENANT_PARENT_DOMAIN + context.properties().applicationId().tenant().value()), + AthenzService.from(context.properties().applicationId().application().value())); + } + private void addDeploymentSpecConfig(ApplicationContainerCluster cluster, ConfigModelContext context, DeployLogger deployLogger) { if ( ! context.getDeployState().isHosted()) return; DeploymentSpec deploymentSpec = app.getDeploymentSpec(); @@ -1295,37 +1312,36 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { } } - private void addIdentityProvider(ApplicationContainerCluster cluster, - List<ConfigServerSpec> configServerSpecs, - HostName loadBalancerName, - URI ztsUrl, - String athenzDnsSuffix, - Zone zone, - DeploymentSpec spec) { - spec.athenzDomain() - .ifPresent(domain -> { - AthenzService service = spec.athenzService(app.getApplicationId().instance(), zone.environment(), zone.region()) - .orElseThrow(() -> new IllegalArgumentException("Missing Athenz service configuration in instance '" + - app.getApplicationId().instance() + "'")); - String zoneDnsSuffix = zone.environment().value() + "-" + zone.region().value() + "." + athenzDnsSuffix; - IdentityProvider identityProvider = new IdentityProvider(domain, - service, - getLoadBalancerName(loadBalancerName, configServerSpecs), - ztsUrl, - zoneDnsSuffix, - zone); - - // Replace AthenzIdentityProviderProvider - cluster.removeComponent(ComponentId.fromString("com.yahoo.container.jdisc.AthenzIdentityProviderProvider")); - cluster.addComponent(identityProvider); - - var serviceIdentityProviderProvider = "com.yahoo.vespa.athenz.identityprovider.client.ServiceIdentityProviderProvider"; - cluster.addComponent(new SimpleComponent(new ComponentModel(serviceIdentityProviderProvider, serviceIdentityProviderProvider, "vespa-athenz"))); - - cluster.getContainers().forEach(container -> { - container.setProp("identity.domain", domain.value()); - container.setProp("identity.service", service.value()); - }); + private void addIdentityProvider(ApplicationContainerCluster cluster, List<ConfigServerSpec> configServerSpecs, HostName loadBalancerName, + URI ztsUrl, String athenzDnsSuffix, Zone zone, DeploymentSpec spec) { + spec.athenzDomain().ifPresent(domain -> { + AthenzService service = spec.athenzService(app.getApplicationId().instance(), zone.environment(), zone.region()) + .orElseThrow(() -> new IllegalArgumentException("Missing Athenz service configuration in instance '" + + app.getApplicationId().instance() + "'")); + addIdentityProvider(cluster, configServerSpecs, loadBalancerName, ztsUrl, athenzDnsSuffix, zone, domain, service); + }); + } + + private void addIdentityProvider(ApplicationContainerCluster cluster, List<ConfigServerSpec> configServerSpecs, HostName loadBalancerName, + URI ztsUrl, String athenzDnsSuffix, Zone zone, AthenzDomain domain, AthenzService service) { + String zoneDnsSuffix = zone.environment().value() + "-" + zone.region().value() + "." + athenzDnsSuffix; + IdentityProvider identityProvider = new IdentityProvider(domain, + service, + getLoadBalancerName(loadBalancerName, configServerSpecs), + ztsUrl, + zoneDnsSuffix, + zone); + + // Replace AthenzIdentityProviderProvider + cluster.removeComponent(ComponentId.fromString("com.yahoo.container.jdisc.AthenzIdentityProviderProvider")); + cluster.addComponent(identityProvider); + + var serviceIdentityProviderProvider = "com.yahoo.vespa.athenz.identityprovider.client.ServiceIdentityProviderProvider"; + cluster.addComponent(new SimpleComponent(new ComponentModel(serviceIdentityProviderProvider, serviceIdentityProviderProvider, "vespa-athenz"))); + + cluster.getContainers().forEach(container -> { + container.setProp("identity.domain", domain.value()); + container.setProp("identity.service", service.value()); }); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index 607bb0dfb33..4b86d8834b9 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -214,6 +214,7 @@ public class ModelContextImpl implements ModelContext { private final Architecture adminClusterArchitecture; private final boolean symmetricPutAndActivateReplicaSelection; private final boolean enforceStrictlyIncreasingClusterStateVersions; + private final boolean launchApplicationAthenzService; public FeatureFlags(FlagSource source, ApplicationId appId, Version version) { this.defaultTermwiseLimit = Flags.DEFAULT_TERM_WISE_LIMIT.bindTo(source).with(appId).with(version).value(); @@ -261,6 +262,7 @@ public class ModelContextImpl implements ModelContext { this.adminClusterArchitecture = Architecture.valueOf(PermanentFlags.ADMIN_CLUSTER_NODE_ARCHITECTURE.bindTo(source).with(appId).with(version).value()); this.symmetricPutAndActivateReplicaSelection = Flags.SYMMETRIC_PUT_AND_ACTIVATE_REPLICA_SELECTION.bindTo(source).with(appId).with(version).value(); this.enforceStrictlyIncreasingClusterStateVersions = Flags.ENFORCE_STRICTLY_INCREASING_CLUSTER_STATE_VERSIONS.bindTo(source).with(appId).with(version).value(); + this.launchApplicationAthenzService = Flags.LAUNCH_APPLICATION_ATHENZ_SERVICE.bindTo(source).with(appId).with(version).value(); } @Override public int heapSizePercentage() { return heapPercentage; } @@ -346,6 +348,7 @@ public class ModelContextImpl implements ModelContext { private final boolean allowUserFilters; private final Duration endpointConnectionTtl; private final List<String> requestPrefixForLoggingContent; + private final boolean launchApplicationAthenzService; public Properties(ApplicationId applicationId, Version modelVersion, @@ -393,6 +396,7 @@ public class ModelContextImpl implements ModelContext { this.endpointConnectionTtl = Duration.ofSeconds(PermanentFlags.ENDPOINT_CONNECTION_TTL.bindTo(flagSource).with(applicationId).value()); this.dataplaneTokens = dataplaneTokens; this.requestPrefixForLoggingContent = PermanentFlags.LOG_REQUEST_CONTENT.bindTo(flagSource).with(applicationId).value(); + this.launchApplicationAthenzService = Flags.LAUNCH_APPLICATION_ATHENZ_SERVICE.bindTo(flagSource).with(applicationId).value(); } @Override public ModelContext.FeatureFlags featureFlags() { return featureFlags; } @@ -492,5 +496,8 @@ public class ModelContextImpl implements ModelContext { @Override public Duration endpointConnectionTtl() { return endpointConnectionTtl; } @Override public List<String> requestPrefixForLoggingContent() { return requestPrefixForLoggingContent; } + + @Override public boolean launchApplicationAthenzService() { return launchApplicationAthenzService; } } + } diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index 217009306a0..ee970e65c3e 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -68,7 +68,7 @@ <assertj.vespa.version>3.26.0</assertj.vespa.version> <!-- Athenz dependencies. Make sure these dependencies match those in Vespa's internal repositories --> - <aws-sdk.vespa.version>1.12.739</aws-sdk.vespa.version> + <aws-sdk.vespa.version>1.12.740</aws-sdk.vespa.version> <athenz.vespa.version>1.11.59</athenz.vespa.version> <!-- Athenz END --> @@ -126,7 +126,7 @@ <mimepull.vespa.version>1.10.0</mimepull.vespa.version> <mockito.vespa.version>5.12.0</mockito.vespa.version> <mojo-executor.vespa.version>2.4.0</mojo-executor.vespa.version> - <netty.vespa.version>4.1.110.Final</netty.vespa.version> + <netty.vespa.version>4.1.111.Final</netty.vespa.version> <netty-tcnative.vespa.version>2.0.65.Final</netty-tcnative.vespa.version> <onnxruntime.vespa.version>1.18.0</onnxruntime.vespa.version> <opennlp.vespa.version>2.3.3</opennlp.vespa.version> diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 895283b589b..8b40d68539d 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -460,6 +460,13 @@ public class Flags { "Takes effect immediately", INSTANCE_ID); + public static final UnboundBooleanFlag LAUNCH_APPLICATION_ATHENZ_SERVICE = defineFeatureFlag( + "launch-application-athenz-service", false, + List.of("jonmv"), "2024-06-11", "2024-09-01", + "Whether to launch an Athenz service unique to the application. Only valid in public systems!", + "Takes effect on next deployment", + INSTANCE_ID); + public static final UnboundBooleanFlag HUBSPOT_SYNC_CONTACTS = defineFeatureFlag( "hubspot-sync-contacts", false, List.of("bjorncs"), "2024-05-27", "2025-01-01", diff --git a/logforwarder/src/apps/vespa-otelcol-start/cf-handler.cpp b/logforwarder/src/apps/vespa-otelcol-start/cf-handler.cpp index 9579271f88a..1d0dd2cc544 100644 --- a/logforwarder/src/apps/vespa-otelcol-start/cf-handler.cpp +++ b/logforwarder/src/apps/vespa-otelcol-start/cf-handler.cpp @@ -3,7 +3,6 @@ #include "cf-handler.h" #include <vespa/config/common/configcontext.h> #include <vespa/config/common/configsystem.h> -#include <vespa/config/common/exceptions.h> #include <vespa/config/helper/legacy.h> #include <vespa/config/subscription/configsubscriber.hpp> @@ -52,16 +51,5 @@ constexpr std::chrono::milliseconds CONFIG_TIMEOUT_MS(30 * 1000); void CfHandler::start(const std::string &configId) { LOG(debug, "Reading configuration with id '%s'", configId.c_str()); - try { - subscribe(configId, CONFIG_TIMEOUT_MS); - } catch (config::ConfigTimeoutException & ex) { - LOG(warning, "Timout getting config, please check your setup. Will exit and restart: %s", ex.getMessage().c_str()); - std::_Exit(EXIT_FAILURE); - } catch (config::InvalidConfigException& ex) { - LOG(error, "Fatal: Invalid configuration, please check your setup: %s", ex.getMessage().c_str()); - std::_Exit(EXIT_FAILURE); - } catch (config::ConfigRuntimeException& ex) { - LOG(error, "Fatal: Could not get config, please check your setup: %s", ex.getMessage().c_str()); - std::_Exit(EXIT_FAILURE); - } + subscribe(configId, CONFIG_TIMEOUT_MS); } diff --git a/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp b/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp index 46ac3bea60e..4c5882b9710 100644 --- a/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp +++ b/logforwarder/src/apps/vespa-otelcol-start/child-handler.cpp @@ -58,8 +58,9 @@ void ChildHandler::startChild(const std::string &progPath, const std::string &cf return; } if (child == 0) { - std::string cfArg{"--config=file:" + cfPath}; - const char *cargv[] = { progPath.c_str(), cfArg.c_str(), nullptr }; + std::string cfArg1{"--config=file:" "/etc/otelcol/gw-config.yaml"}; + std::string cfArg2{"--config=file:" + cfPath}; + const char *cargv[] = { progPath.c_str(), cfArg1.c_str(), cfArg2.c_str(), nullptr }; execv(progPath.c_str(), const_cast<char **>(cargv)); // if execv fails: perror(progPath.c_str()); diff --git a/logforwarder/src/apps/vespa-otelcol-start/main.cpp b/logforwarder/src/apps/vespa-otelcol-start/main.cpp index 2e3e0659707..9310a0ceffa 100644 --- a/logforwarder/src/apps/vespa-otelcol-start/main.cpp +++ b/logforwarder/src/apps/vespa-otelcol-start/main.cpp @@ -3,6 +3,7 @@ #include "wrapper.h" #include <csignal> #include <unistd.h> +#include <vespa/config/common/exceptions.h> #include <vespa/vespalib/util/sig_catch.h> #include <vespa/defaults.h> @@ -12,10 +13,21 @@ LOG_SETUP("vespa-otelcol-start"); static void run(const char *configId) { vespalib::SigCatch catcher; Wrapper handler(configId); - handler.start(configId); - while (! catcher.receivedStopSignal()) { - handler.check(); - usleep(125000); // Avoid busy looping; + try { + handler.start(configId); + while (! catcher.receivedStopSignal()) { + handler.check(); + usleep(125000); // Avoid busy looping; + } + } catch (config::ConfigTimeoutException & ex) { + LOG(warning, "Timout getting config, please check your setup. Will exit and restart: %s", ex.getMessage().c_str()); + std::_Exit(EXIT_FAILURE); + } catch (config::InvalidConfigException& ex) { + LOG(error, "Fatal: Invalid configuration, please check your setup: %s", ex.getMessage().c_str()); + std::_Exit(EXIT_FAILURE); + } catch (config::ConfigRuntimeException& ex) { + LOG(error, "Fatal: Could not get config, please check your setup: %s", ex.getMessage().c_str()); + std::_Exit(EXIT_FAILURE); } handler.stop(); }; diff --git a/metrics/src/main/java/ai/vespa/metrics/ClusterControllerMetrics.java b/metrics/src/main/java/ai/vespa/metrics/ClusterControllerMetrics.java index 801740c9cf5..f15b7412b24 100644 --- a/metrics/src/main/java/ai/vespa/metrics/ClusterControllerMetrics.java +++ b/metrics/src/main/java/ai/vespa/metrics/ClusterControllerMetrics.java @@ -13,6 +13,7 @@ public enum ClusterControllerMetrics implements VespaMetrics { STOPPING_COUNT("cluster-controller.stopping.count", Unit.NODE, "Number of content nodes currently stopping"), UP_COUNT("cluster-controller.up.count", Unit.NODE, "Number of content nodes up"), CLUSTER_STATE_CHANGE_COUNT("cluster-controller.cluster-state-change.count", Unit.NODE, "Number of nodes changing state"), + NODES_NOT_CONVERGED("cluster-controller.nodes-not-converged", Unit.NODE, "Number of nodes not converging to the latest cluster state version"), CLUSTER_BUCKETS_OUT_OF_SYNC_RATIO("cluster-controller.cluster-buckets-out-of-sync-ratio", Unit.FRACTION, "Ratio of buckets in the cluster currently in need of syncing"), BUSY_TICK_TIME_MS("cluster-controller.busy-tick-time-ms", Unit.MILLISECOND, "Time busy"), IDLE_TICK_TIME_MS("cluster-controller.idle-tick-time-ms", Unit.MILLISECOND, "Time idle"), diff --git a/metrics/src/main/java/ai/vespa/metrics/set/Vespa9VespaMetricSet.java b/metrics/src/main/java/ai/vespa/metrics/set/Vespa9VespaMetricSet.java index 957eaf8304f..0d5827369fd 100644 --- a/metrics/src/main/java/ai/vespa/metrics/set/Vespa9VespaMetricSet.java +++ b/metrics/src/main/java/ai/vespa/metrics/set/Vespa9VespaMetricSet.java @@ -226,6 +226,8 @@ public class Vespa9VespaMetricSet { addMetric(metrics, ClusterControllerMetrics.MAINTENANCE_COUNT.max()); addMetric(metrics, ClusterControllerMetrics.RETIRED_COUNT.max()); addMetric(metrics, ClusterControllerMetrics.UP_COUNT.max()); + addMetric(metrics, ClusterControllerMetrics.NODES_NOT_CONVERGED.max()); + addMetric(metrics, ClusterControllerMetrics.CLUSTER_BUCKETS_OUT_OF_SYNC_RATIO.max()); addMetric(metrics, ClusterControllerMetrics.CLUSTER_STATE_CHANGE_COUNT.baseName()); addMetric(metrics, ClusterControllerMetrics.BUSY_TICK_TIME_MS, EnumSet.of(max, sum, count)); addMetric(metrics, ClusterControllerMetrics.IDLE_TICK_TIME_MS, EnumSet.of(max, sum, count)); diff --git a/metrics/src/main/java/ai/vespa/metrics/set/VespaMetricSet.java b/metrics/src/main/java/ai/vespa/metrics/set/VespaMetricSet.java index 9c73b5bd877..0e6c537f56d 100644 --- a/metrics/src/main/java/ai/vespa/metrics/set/VespaMetricSet.java +++ b/metrics/src/main/java/ai/vespa/metrics/set/VespaMetricSet.java @@ -257,6 +257,7 @@ public class VespaMetricSet { addMetric(metrics, ClusterControllerMetrics.RETIRED_COUNT, EnumSet.of(max, last)); // TODO: Vespa 9: Remove last addMetric(metrics, ClusterControllerMetrics.STOPPING_COUNT.last()); addMetric(metrics, ClusterControllerMetrics.UP_COUNT, EnumSet.of(max, last)); // TODO: Vespa 9: Remove last + addMetric(metrics, ClusterControllerMetrics.NODES_NOT_CONVERGED.max()); addMetric(metrics, ClusterControllerMetrics.CLUSTER_STATE_CHANGE_COUNT.baseName()); addMetric(metrics, ClusterControllerMetrics.CLUSTER_BUCKETS_OUT_OF_SYNC_RATIO.max()); addMetric(metrics, ClusterControllerMetrics.BUSY_TICK_TIME_MS, EnumSet.of(last, max, sum, count)); // TODO: Vespa 9: Remove last diff --git a/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java b/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java index a74617a97eb..ba597d177c4 100644 --- a/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java +++ b/zkfacade/src/main/java/com/yahoo/vespa/curator/Curator.java @@ -228,7 +228,9 @@ public class Curator extends AbstractComponent implements AutoCloseable { /** @see #create(Path, Duration) */ - public boolean create(Path path) { return create(path, null); } + public boolean create(Path path) { + return create(path, null); + } /** * Creates an empty node at a path, creating any parents as necessary. @@ -262,7 +264,9 @@ public class Curator extends AbstractComponent implements AutoCloseable { } /** - * Creates all the given paths in a single transaction. Any paths which already exists are ignored. + * Creates all the given paths in a single transaction. Any paths which already exists are ignored.<br> + * <em>No, this is <strong>NOT</strong> atomic, when viewed from other ZK clients!</em> Maybe it once was, but it is not anymore, + * unless ZK is configured to run commits and read in a single thread, which is not the default. */ public void createAtomically(Path... paths) { try { @@ -272,7 +276,7 @@ public class Curator extends AbstractComponent implements AutoCloseable { transaction = transaction.create().forPath(path.getAbsolute(), new byte[0]).and(); } } - ((CuratorTransactionFinal)transaction).commit(); + ((CuratorTransactionFinal) transaction).commit(); } catch (Exception e) { throw new RuntimeException("Could not create " + Arrays.toString(paths), e); } |