diff options
Diffstat (limited to 'config-model/src')
50 files changed, 671 insertions, 616 deletions
diff --git a/config-model/src/main/Makefile b/config-model/src/main/Makefile index 5e7024ccff9..c3dfd0c2e3e 100644 --- a/config-model/src/main/Makefile +++ b/config-model/src/main/Makefile @@ -3,7 +3,7 @@ trangjar=../../target/trang.jar -all: resources/schema/services.rng resources/schema/hosts.rng resources/schema/container-include.rng resources/schema/services.xsd resources/schema/hosts.xsd resources/schema/container-include.xsd +all: resources/schema/services.rng resources/schema/hosts.rng resources/schema/container-include.rng resources/schema/services.xsd resources/schema/hosts.xsd resources/schema/container-include.xsd resources/schema/deployment.xsd resources/schema/services.rng: resources/schema/services.rnc resources/schema/common.rnc resources/schema/admin.rnc resources/schema/clients.rnc resources/schema/docproc.rnc resources/schema/routing.rnc resources/schema/clients-v2.rnc resources/schema/content.rnc resources/schema/genericmodule.rnc resources/schema/legacygenericcluster.rnc resources/schema/genericcluster.rnc resources/schema/legacygenericmodule.rnc resources/schema/containercluster.rnc java -jar $(trangjar) -I rnc -O rng resources/schema/services.rnc resources/schema/services.rng @@ -25,6 +25,12 @@ resources/schema/hosts.rng: resources/schema/hosts.rnc resources/schema/hosts.xsd: resources/schema/hosts.rng java -jar $(trangjar) -I rng -O xsd resources/schema/hosts.rng resources/schema/hosts.xsd +resources/schema/deployment.rng: resources/schema/deployment.rnc + java -jar $(trangjar) -I rnc -O rng resources/schema/deployment.rnc resources/schema/deployment.rng + +resources/schema/deployment.xsd: resources/schema/deployment.rng + java -jar $(trangjar) -I rng -O xsd resources/schema/deployment.rng resources/schema/deployment.xsd + clean: rm -f resources/schema/*.rng rm -f resources/schema/*.xsd diff --git a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java index e6df94c8855..0b0ac77443c 100644 --- a/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java +++ b/config-model/src/main/java/com/yahoo/config/model/ApplicationConfigProducerRoot.java @@ -265,6 +265,7 @@ public class ApplicationConfigProducerRoot extends AbstractConfigProducer<Abstra } public FileDistributionConfigProducer getFileDistributionConfigProducer() { + if (admin == null) return null; // no admin if standalone return admin.getFileDistributionConfigProducer(); } diff --git a/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java b/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java index 8e1097907f1..8778107cd8a 100644 --- a/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java +++ b/config-model/src/main/java/com/yahoo/config/model/producer/AbstractConfigProducer.java @@ -105,10 +105,10 @@ public abstract class AbstractConfigProducer<CHILD extends AbstractConfigProduce child.setParent(this); if (childrenBySubId.get(child.getSubId()) != null) { throw new IllegalArgumentException("Multiple services/instances of the id '" + child.getSubId() + "' under the service/instance " + - errorMsgClassName() + " '" + subId + "'. (This is commonly caused by service/node index " + - "collisions in the config.)." + - "\nExisting instance: " + childrenBySubId.get(child.getSubId()) + - "\nAttempted to add: " + child); + errorMsgClassName() + " '" + subId + "'. (This is commonly caused by service/node index " + + "collisions in the config.)." + + "\nExisting instance: " + childrenBySubId.get(child.getSubId()) + + "\nAttempted to add: " + child); } childrenBySubId.put(child.getSubId(), child); diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java index 5c9d03b434f..c4ac4d91001 100644 --- a/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java +++ b/config-model/src/main/java/com/yahoo/config/model/provision/InMemoryProvisioner.java @@ -101,8 +101,9 @@ public class InMemoryProvisioner implements HostProvisioner { throw new IllegalArgumentException("Requested " + requestedCapacity.nodeCount() + " nodes in " + groups + " groups, but the node count is not divisible into this number of groups"); - int capacity = failOnOutOfCapacity ? requestedCapacity.nodeCount() : - Math.min(requestedCapacity.nodeCount(), freeNodes.get("default").size() + totalAllocatedTo(cluster)); + int capacity = failOnOutOfCapacity || requestedCapacity.isRequired() + ? requestedCapacity.nodeCount() + : Math.min(requestedCapacity.nodeCount(), freeNodes.get("default").size() + totalAllocatedTo(cluster)); if (groups > capacity) groups = capacity; @@ -138,7 +139,7 @@ public class InMemoryProvisioner implements HostProvisioner { int nextIndex = nextIndexInCluster.getOrDefault(new Pair<>(clusterGroup.type(), clusterGroup.id()), startIndex); while (allocation.size() < nodesInGroup) { - if (freeNodes.get(flavor).isEmpty()) throw new IllegalArgumentException("No nodes of flavor '" + flavor + "' available"); + if (freeNodes.get(flavor).isEmpty()) throw new IllegalArgumentException("Insufficient capacity of flavor '" + flavor + "'"); Host newHost = freeNodes.removeValue(flavor, 0); ClusterMembership membership = ClusterMembership.from(clusterGroup, nextIndex++); allocation.add(new HostSpec(newHost.hostname(), newHost.aliases(), membership)); diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java b/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java index 1d5544873d9..fe8b3935fcf 100644 --- a/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java +++ b/config-model/src/main/java/com/yahoo/config/model/provision/SingleNodeProvisioner.java @@ -27,10 +27,11 @@ public class SingleNodeProvisioner implements HostProvisioner { public SingleNodeProvisioner() { try { host = new Host(HostSystem.lookupCanonicalHostname(HostName.getLocalhost())); - } catch (UnknownHostException e) { + this.hostSpec = new HostSpec(host.hostname(), host.aliases()); + } + catch (UnknownHostException e) { throw new RuntimeException(e); } - this.hostSpec = new HostSpec(host.hostname(), host.aliases()); } @Override diff --git a/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java b/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java index 731410c9bf3..c30c62b44bc 100644 --- a/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java +++ b/config-model/src/main/java/com/yahoo/config/model/test/MockApplicationPackage.java @@ -232,6 +232,16 @@ public class MockApplicationPackage implements ApplicationPackage { " </host>" + "</hosts>"; + + @Override + public void validateXML() throws IOException { + if (failOnValidateXml) { + throw new IllegalArgumentException("Error in application package"); + } else { + throw new UnsupportedOperationException("This application package cannot validate XML"); + } + } + @Override public void validateXML(DeployLogger logger) throws IOException { if (failOnValidateXml) { diff --git a/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java b/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java index fa84cf1c7eb..314060e7543 100644 --- a/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java +++ b/config-model/src/main/java/com/yahoo/config/model/test/MockRoot.java @@ -35,7 +35,9 @@ import java.util.Set; * * @author gjoranv */ +// TODO: mockRoot instances can probably be replaced by VespaModel.createIncomplete public class MockRoot extends AbstractConfigProducerRoot { + private static final long serialVersionUID = 1L; public static final String MOCKHOST = "mockhost"; diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/Search.java b/config-model/src/main/java/com/yahoo/searchdefinition/Search.java index 2ab634801c2..9032f913d0b 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/Search.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/Search.java @@ -51,6 +51,7 @@ public class Search implements Serializable { private boolean documentsOnly = false; // The stemming setting of this search definition. Default is SHORTEST. + // TODO: Change to Stemming.BEST on Vespa 7 private Stemming stemming = Stemming.SHORTEST; // Documents contained in this definition. diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/derived/IndexInfo.java b/config-model/src/main/java/com/yahoo/searchdefinition/derived/IndexInfo.java index e98ee662b3a..0d8d21400aa 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/derived/IndexInfo.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/derived/IndexInfo.java @@ -420,7 +420,7 @@ public class IndexInfo extends Derived implements IndexInfoConfig.Producer { if (active != null) { return active; } - // assume default + // assume default: TODO: Change to Stemming.BEST on Vespa 7 return Stemming.SHORTEST; } diff --git a/config-model/src/main/java/com/yahoo/searchdefinition/document/Stemming.java b/config-model/src/main/java/com/yahoo/searchdefinition/document/Stemming.java index f471201f55e..5b145051de5 100644 --- a/config-model/src/main/java/com/yahoo/searchdefinition/document/Stemming.java +++ b/config-model/src/main/java/com/yahoo/searchdefinition/document/Stemming.java @@ -17,13 +17,17 @@ public enum Stemming { /** No stemming */ NONE("none"), - /** Stem as much as possible */ + /** @deprecated incorrectly don't stem at all */ + @Deprecated ALL("all"), /** select shortest possible stem */ SHORTEST("shortest"), - /** index (and query?) multiple stems */ + /** select the "best" stem alternative */ + BEST("best"), + + /** index multiple stems */ MULTIPLE("multiple"); private static Logger log=Logger.getLogger(Stemming.class.getName()); @@ -36,6 +40,7 @@ public enum Stemming { * * @throws IllegalArgumentException if there is no stemming type with the given name */ + @SuppressWarnings("deprecation") public static Stemming get(String stemmingName) { try { Stemming stemming = Stemming.valueOf(stemmingName.toUpperCase()); @@ -49,7 +54,7 @@ public enum Stemming { } } - private Stemming(String name) { + Stemming(String name) { this.name = name; } @@ -59,14 +64,16 @@ public enum Stemming { return "stemming " + name; } + @SuppressWarnings("deprecation") public StemMode toStemMode() { - if (this == Stemming.SHORTEST) { - return StemMode.SHORTEST; - } - if (this == Stemming.MULTIPLE) { - return StemMode.ALL; + switch(this) { + case SHORTEST: return StemMode.SHORTEST; + case MULTIPLE: return StemMode.ALL; + case BEST : return StemMode.BEST; + case NONE: return StemMode.NONE; + case ALL: return StemMode.SHORTEST; // Intentional; preserve historic behavior + default: throw new IllegalStateException("Inconvertible stem mode " + this); } - return StemMode.NONE; } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/Client.java b/config-model/src/main/java/com/yahoo/vespa/model/Client.java index 15685f5f669..2a2498cc310 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/Client.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/Client.java @@ -8,7 +8,7 @@ import com.yahoo.config.model.producer.AbstractConfigProducer; * This is a placeholder config producer that makes global configuration available through a single identifier. This * is added directly to the {@link ApplicationConfigProducerRoot} producer, and so can be accessed by the simple "client" identifier. * - * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a> + * @author Simon Thoresen */ public class Client extends AbstractConfigProducer { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/ConfigProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/ConfigProducer.java index 852e4e73331..aaeedf10bc8 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/ConfigProducer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/ConfigProducer.java @@ -19,44 +19,38 @@ import com.yahoo.config.model.producer.UserConfigRepo; */ public interface ConfigProducer extends com.yahoo.config.ConfigInstance.Producer { - /** - * @return the configId of this ConfigProducer. - */ - public String getConfigId(); + /** Returns the configId of this ConfigProducer. */ + String getConfigId(); - /** - * @return The one and only HostSystem of the root node - */ - public HostSystem getHostSystem(); + /** Returns the one and only HostSystem of the root node */ + HostSystem getHostSystem(); /** Returns the user configs of this */ - public UserConfigRepo getUserConfigs(); + UserConfigRepo getUserConfigs(); - /** - * @return this ConfigProducer's children (only 1st level) - */ - public Map<String,? extends ConfigProducer> getChildren(); + /** Returns this ConfigProducer's children (only 1st level) */ + Map<String,? extends ConfigProducer> getChildren(); - /** - * @return a List of all Services that are descendants to this ConfigProducer - */ - public List<Service> getDescendantServices(); + /** Returns a List of all Services that are descendants to this ConfigProducer */ + List<Service> getDescendantServices(); /** * Writes files that need to be written. The files will usually * only be written when the Vespa model is generated through the * deploy-application script. - * gv: This is primarily intended for debugging. + * This is primarily intended for debugging. + * * @param directory directory to write files to * @throws java.io.IOException if writing fails */ - public void writeFiles(File directory) throws IOException; + void writeFiles(File directory) throws IOException; /** * Dump the three of config producers to the specified stream. + * * @param out The stream to print to, e.g. System.out */ - public void dump(PrintStream out); + void dump(PrintStream out); /** * Build config from this and all parent ConfigProducers, @@ -74,11 +68,12 @@ public interface ConfigProducer extends com.yahoo.config.ConfigInstance.Producer * @param builder The ConfigBuilder to add user config overrides. * @return true if overrides were added, false if not. */ - public boolean addUserConfig(ConfigInstance.Builder builder); + boolean addUserConfig(ConfigInstance.Builder builder); /** * check constraints depending on the state of the vespamodel graph. * When overriding, you must invoke super. */ - public void validate() throws Exception; + void validate() throws Exception; + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/HostSystem.java b/config-model/src/main/java/com/yahoo/vespa/model/HostSystem.java index d3e922c69dc..2d825e3332d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/HostSystem.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/HostSystem.java @@ -5,12 +5,21 @@ import com.yahoo.config.application.api.DeployLogger; import com.yahoo.config.model.api.HostProvisioner; import com.yahoo.config.model.producer.AbstractConfigProducer; import com.yahoo.config.model.test.MockRoot; -import com.yahoo.config.provision.*; +import com.yahoo.config.provision.Capacity; +import com.yahoo.config.provision.ClusterMembership; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.HostSpec; +import com.yahoo.config.provision.ProvisionLogger; import com.yahoo.net.HostName; import java.net.InetAddress; import java.net.UnknownHostException; -import java.util.*; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; @@ -73,6 +82,7 @@ public class HostSystem extends AbstractConfigProducer<Host> { * @return The canonical hostname, or null if unable to resolve. * @throws UnknownHostException if the hostname cannot be resolved */ + // public - This is used by amenders outside this repo public static String lookupCanonicalHostname(String hostname) throws UnknownHostException { return java.net.InetAddress.getByName(hostname).getCanonicalHostName(); } @@ -87,7 +97,7 @@ public class HostSystem extends AbstractConfigProducer<Host> { if (ipAddresses.containsKey(hostname)) return ipAddresses.get(hostname); String ipAddress; - if (hostname.startsWith(MockRoot.MOCKHOST)) { + if (hostname.startsWith(MockRoot.MOCKHOST)) { // TODO: Remove ipAddress = "0.0.0.0"; } else { try { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/PlainFormatter.java b/config-model/src/main/java/com/yahoo/vespa/model/PlainFormatter.java deleted file mode 100644 index d424f4fa31b..00000000000 --- a/config-model/src/main/java/com/yahoo/vespa/model/PlainFormatter.java +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.model; - -import java.util.logging.Formatter; -import java.util.logging.LogRecord; - -/** - * A log formatter that returns a plain log message only with level, not - * including timestamp and method (as java.util.logging.SimpleFormatter). - * See bug #1789867. - * - * @author gjoranv - */ -public class PlainFormatter extends Formatter { - - public PlainFormatter() { - super(); - } - - public String format(LogRecord record) { - StringBuffer sb = new StringBuffer(); - - sb.append(record.getLevel().getName()).append(": "); - sb.append(formatMessage(record)).append("\n"); - - return sb.toString(); - } -} diff --git a/config-model/src/main/java/com/yahoo/vespa/model/PortsMeta.java b/config-model/src/main/java/com/yahoo/vespa/model/PortsMeta.java index ea2151f9976..a0b3cc7294b 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/PortsMeta.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/PortsMeta.java @@ -7,11 +7,12 @@ import java.util.LinkedList; import java.util.List; /** - * Track metainformation about the ports of a service. + * Track meta information about the ports of a service. * * @author Vidar Larsen */ public class PortsMeta implements Serializable { + /** A list of all ports. The list elements are lists of strings. */ private List<LinkedList<String>> ports; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java index 9a23be1f5c5..bdba3549033 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModel.java @@ -100,6 +100,8 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri /** The validation overrides of this. This is never null. */ private final ValidationOverrides validationOverrides; + + private final FileDistributor fileDistributor; /** Creates a Vespa Model from internal model types only */ public VespaModel(ApplicationPackage app) throws IOException, SAXException { @@ -130,23 +132,38 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri * @param deployState the global deploy state to use for this model. */ public VespaModel(ConfigModelRegistry configModelRegistry, DeployState deployState) throws IOException, SAXException { + this(configModelRegistry, deployState, true, null); + } + + private VespaModel(ConfigModelRegistry configModelRegistry, DeployState deployState, boolean complete, FileDistributor fileDistributor) throws IOException, SAXException { super("vespamodel"); this.deployState = deployState; this.validationOverrides = deployState.validationOverrides(); configModelRegistry = new VespaConfigModelRegistry(configModelRegistry); VespaModelBuilder builder = new VespaDomBuilder(); root = builder.getRoot(VespaModel.ROOT_CONFIGID, deployState, this); - configModelRepo.readConfigModels(deployState, builder, root, configModelRegistry); - addServiceClusters(deployState.getApplicationPackage(), builder); - setupRouting(); - log.log(LogLevel.DEBUG, "hostsystem=" + getHostSystem()); - this.info = Optional.of(createProvisionInfo()); - getAdmin().addPerHostServices(getHostSystem().getHosts(), deployState.getProperties()); - freezeModelTopology(); - root.prepare(configModelRepo); - configModelRepo.prepareConfigModels(); - validateWrapExceptions(); - this.deployState = null; + if (complete) { // create a a completed, frozen model + configModelRepo.readConfigModels(deployState, builder, root, configModelRegistry); + addServiceClusters(deployState.getApplicationPackage(), builder); + this.info = Optional.of(createProvisionInfo()); // must happen after the two lines above + setupRouting(); + this.fileDistributor = root.getFileDistributionConfigProducer().getFileDistributor(); + getAdmin().addPerHostServices(getHostSystem().getHosts(), deployState.getProperties()); + freezeModelTopology(); + root.prepare(configModelRepo); + configModelRepo.prepareConfigModels(); + validateWrapExceptions(); + this.deployState = null; + } + else { // create a model with no services instantiated and the given file distributor + this.info = Optional.of(createProvisionInfo()); + this.fileDistributor = fileDistributor; + } + } + + /** Creates a mutable model with no services instantiated */ + public static VespaModel createIncomplete(DeployState deployState) throws IOException, SAXException { + return new VespaModel(new NullConfigModelRegistry(), deployState, false, new FileDistributor(deployState.getFileRegistry())); } private ProvisionInfo createProvisionInfo() { @@ -192,7 +209,8 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri } public FileDistributor getFileDistributor() { - return root.getFileDistributionConfigProducer().getFileDistributor(); + // return root.getFileDistributionConfigProducer().getFileDistributor(); + return fileDistributor; } /** Returns this models Vespa instance */ @@ -437,9 +455,8 @@ public final class VespaModel extends AbstractConfigProducerRoot implements Seri @Override public DeployState getDeployState() { - if (deployState == null) { + if (deployState == null) throw new IllegalStateException("Cannot call getDeployState() once model has been built"); - } return deployState; } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java index 9b234435ce2..adbd4d7bae1 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java @@ -4,7 +4,6 @@ package com.yahoo.vespa.model; import com.google.inject.Inject; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.config.application.api.ApplicationPackage; -import com.yahoo.config.application.api.DeployLogger; import com.yahoo.config.model.ConfigModelRegistry; import com.yahoo.config.model.MapConfigModelRegistry; import com.yahoo.config.model.NullConfigModelRegistry; @@ -89,7 +88,6 @@ public class VespaModelFactory implements ModelFactory { if (modelContext.appDir().isPresent()) { ApplicationPackageXmlFilesValidator validator = ApplicationPackageXmlFilesValidator.createDefaultXMLValidator(modelContext.appDir().get(), - modelContext.deployLogger(), modelContext.vespaVersion()); try { validator.checkApplication(); @@ -101,7 +99,7 @@ public class VespaModelFactory implements ModelFactory { } } else { - validateXML(modelContext.applicationPackage(), modelContext.deployLogger(), ignoreValidationErrors); + validateXML(modelContext.applicationPackage(), ignoreValidationErrors); } DeployState deployState = createDeployState(modelContext); VespaModel model = buildModel(deployState); @@ -173,9 +171,9 @@ public class VespaModelFactory implements ModelFactory { return modelContext.properties().hostedVespa() && id.isHostedVespaRoutingApplication(); } - private void validateXML(ApplicationPackage applicationPackage, DeployLogger deployLogger, boolean ignoreValidationErrors) { + private void validateXML(ApplicationPackage applicationPackage, boolean ignoreValidationErrors) { try { - applicationPackage.validateXML(deployLogger); + applicationPackage.validateXML(); } catch (IllegalArgumentException e) { rethrowUnlessIgnoreErrors(e, ignoreValidationErrors); } catch (Exception e) { @@ -185,7 +183,7 @@ public class VespaModelFactory implements ModelFactory { private List<ConfigChangeAction> validateModel(VespaModel model, DeployState deployState, boolean ignoreValidationErrors) { try { - deployState.getApplicationPackage().validateXML(deployState.getDeployLogger()); + deployState.getApplicationPackage().validateXML(); return Validation.validate(model, ignoreValidationErrors, deployState); } catch (IllegalArgumentException e) { rethrowUnlessIgnoreErrors(e, ignoreValidationErrors); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java index 38a1e59433f..67281b7816d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/Admin.java @@ -34,7 +34,7 @@ public class Admin extends AbstractConfigProducer implements Serializable { private static final long serialVersionUID = 1L; private final Yamas yamas; - private final Map<String,MetricsConsumer> metricsConsumers; + private final Map<String, MetricsConsumer> metricsConsumers; private final List<Configserver> configservers = new ArrayList<>(); private final List<Slobrok> slobroks = new ArrayList<>(); @@ -200,7 +200,7 @@ public class Admin extends AbstractConfigProducer implements Serializable { HostResource deployHost = getHostSystem().getHostByHostname(fileDistributor.fileSourceHost()); if (deployHostIsMissing(deployHost)) { throw new RuntimeException("Could not find host in the application's host system: '" + - fileDistributor.fileSourceHost() + "'. Hostsystem=" + getHostSystem()); + fileDistributor.fileSourceHost() + "'. Hostsystem=" + getHostSystem()); } FileDistributorService fds = new FileDistributorService(fileDistribution, host.getHost().getHostName(), @@ -245,4 +245,5 @@ public class Admin extends AbstractConfigProducer implements Serializable { public boolean multitenant() { return multitenant; } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/Configserver.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/Configserver.java index 11508ba91ed..47332b064da 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/Configserver.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/Configserver.java @@ -96,10 +96,12 @@ public class Configserver extends AbstractService { // TODO: Remove this implementation when we are on Hosted Vespa. public static class Spec implements ConfigServerSpec { + private final String hostName; private final int configServerPort; private final int httpPort; private final int zooKeeperPort; + public String getHostName() { return hostName; } @@ -142,4 +144,5 @@ public class Configserver extends AbstractService { this.zooKeeperPort = zooKeeperPort; } } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java index 75e9caefbd5..bcf523e1c99 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/VespaModelBuilder.java @@ -27,4 +27,5 @@ public abstract class VespaModelBuilder { * @param configModelRepo a {@link com.yahoo.config.model.ConfigModelRepo instance} */ public abstract void postProc(AbstractConfigProducer producerRoot, ConfigModelRepo configModelRepo); + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientsBuilder.java index 876017e16bc..f1829a1d718 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientsBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomClientsBuilder.java @@ -35,4 +35,5 @@ public class DomClientsBuilder extends LegacyConfigModelBuilder<Clients> { throw new IllegalArgumentException("Version '" + version + "' of 'clients' not supported."); } } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomV20ClientsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomV20ClientsBuilder.java index cea325b785f..b4070c67ae1 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomV20ClientsBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/DomV20ClientsBuilder.java @@ -1,40 +1,17 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.builder.xml.dom; -import com.yahoo.component.ComponentId; -import com.yahoo.component.ComponentSpecification; -import com.yahoo.component.chain.Phase; -import com.yahoo.component.chain.dependencies.Dependencies; -import com.yahoo.component.chain.model.ChainSpecification; -import com.yahoo.component.chain.model.ChainedComponentModel; -import com.yahoo.config.model.ConfigModelUtils; import com.yahoo.vespa.config.content.spooler.SpoolerConfig; import com.yahoo.config.model.producer.AbstractConfigProducer; -import com.yahoo.container.bundle.BundleInstantiationSpecification; -import com.yahoo.osgi.provider.model.ComponentModel; import com.yahoo.text.XML; import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.model.SimpleConfigProducer; import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder.DomConfigProducerBuilder; -import com.yahoo.vespa.model.builder.xml.dom.chains.docproc.DomDocprocChainsBuilder; import com.yahoo.vespa.model.clients.Clients; -import com.yahoo.vespa.model.clients.HttpGatewayOwner; import com.yahoo.vespa.model.clients.VespaSpoolMaster; import com.yahoo.vespa.model.clients.VespaSpooler; import com.yahoo.vespa.model.clients.VespaSpoolerProducer; import com.yahoo.vespa.model.clients.VespaSpoolerService; -import com.yahoo.vespa.model.container.Container; -import com.yahoo.vespa.model.container.ContainerCluster; -import com.yahoo.vespa.model.container.component.Handler; -import com.yahoo.vespa.model.container.component.chain.ProcessingHandler; -import com.yahoo.vespa.model.container.docproc.ContainerDocproc; -import com.yahoo.vespa.model.container.docproc.DocprocChains; -import com.yahoo.vespa.model.container.search.ContainerHttpGateway; -import com.yahoo.vespa.model.container.search.ContainerSearch; -import com.yahoo.vespa.model.container.search.searchchain.SearchChain; -import com.yahoo.vespa.model.container.search.searchchain.SearchChains; -import com.yahoo.vespa.model.container.search.searchchain.Searcher; -import com.yahoo.vespa.model.container.xml.ContainerModelBuilder; import com.yahoo.vespaclient.config.FeederConfig; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -43,9 +20,6 @@ import org.w3c.dom.NodeList; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.logging.Level; /** * Builds the Clients plugin @@ -54,29 +28,17 @@ import java.util.logging.Level; */ public class DomV20ClientsBuilder { - public static final String vespaClientBundleSpecification = "vespaclient-container-plugin"; - // The parent docproc plugin to register data with. private final Clients clients; DomV20ClientsBuilder(Clients clients, String version) { - this.clients = clients; - if (!version.equals("2.0")) { + if ( ! version.equals("2.0")) throw new IllegalArgumentException("Version '" + version + "' of 'clients' not supported."); - } + this.clients = clients; } public void build(Element spec) { - NodeList children = spec.getElementsByTagName("gateways"); - if (children.getLength() > 0 && clients.getConfigProducer()!=null) - clients.getConfigProducer().deployLogger().log(Level.WARNING, "The 'gateways' element is deprecated, and will be disallowed in a " + - "later version of Vespa. Use 'document-api' under 'jdisc' instead, see: " + - ConfigModelUtils.createDocLink("reference/services-jdisc.html")); - for (int i = 0; i < children.getLength(); i++) { - createGateways(clients.getConfigProducer(), (Element) children.item(i), clients); - } - - children = spec.getElementsByTagName("spoolers"); + NodeList children = spec.getElementsByTagName("spoolers"); for (int i = 0; i < children.getLength(); i++) { createSpoolers(clients.getConfigProducer(), (Element) children.item(i), clients); } @@ -87,29 +49,6 @@ public class DomV20ClientsBuilder { } } - static Boolean getBooleanNodeValue(Node node) { - return Boolean.valueOf(node.getFirstChild().getNodeValue()); - } - - static boolean getHttpFileServerEnabled(Element parentHttpFileServer, Element httpFileServer) { - boolean ret=false; - if (parentHttpFileServer != null) { - for (Element child : XML.getChildren(parentHttpFileServer)) { - if ("enabled".equals(child.getNodeName())) { - ret = getBooleanNodeValue(child); - } - } - } - if (httpFileServer != null) { - for (Element child : XML.getChildren(httpFileServer)) { - if ("enabled".equals(child.getNodeName())) { - ret = getBooleanNodeValue(child); - } - } - } - return ret; - } - private void createLoadTypes(Element element, Clients clients) { for (Element e : XML.getChildren(element, "type")) { String priority = e.getAttribute("default-priority"); @@ -118,31 +57,6 @@ public class DomV20ClientsBuilder { } /** - * Creates HttpGateway objects using the given xml Element. - * - * @param pcp AbstractConfigProducer - * @param element The xml Element - */ - private void createGateways(AbstractConfigProducer pcp, Element element, Clients clients) { - String jvmArgs = null; - if (element.hasAttribute(VespaDomBuilder.JVMARGS_ATTRIB_NAME)) jvmArgs=element.getAttribute(VespaDomBuilder.JVMARGS_ATTRIB_NAME); - - Element gatewaysFeederOptions = findFeederOptions(element); - - HttpGatewayOwner owner = new HttpGatewayOwner(pcp, getFeederConfig(null, gatewaysFeederOptions)); - ContainerCluster cluster = new ContainerHttpGatewayClusterBuilder().build(owner, element); - - int index = 0; - for (Element e : XML.getChildren(element, "gateway")) { - ContainerHttpGateway qrs = new ContainerHttpGatewayBuilder(cluster, index).build(cluster, e); - - if ("".equals(qrs.getJvmArgs()) && jvmArgs!=null) qrs.setJvmArgs(jvmArgs); - index++; - } - clients.setContainerHttpGateways(cluster); - } - - /** * Creates VespaSpooler objects using the given xml Element. */ private void createSpoolers(AbstractConfigProducer pcp, Element element, Clients clients) { @@ -170,13 +84,10 @@ public class DomV20ClientsBuilder { } } - private void createSpoolMasters(SimpleConfigProducer producer, - Element element) { + private void createSpoolMasters(SimpleConfigProducer producer, Element element) { int i=0; - for (Element e : XML.getChildren(element, "spoolmaster")) { - VespaSpoolMaster master = new VespaSpoolMasterBuilder(i).build(producer, e); - i++; - } + for (Element e : XML.getChildren(element, "spoolmaster")) + new VespaSpoolMasterBuilder(i++).build(producer, e); } private SpoolerConfig.Builder getSpoolConfig(Element conf) { @@ -313,133 +224,6 @@ public class DomV20ClientsBuilder { } } - public static class ContainerHttpGatewayClusterBuilder extends DomConfigProducerBuilder<ContainerCluster> { - @Override - protected ContainerCluster doBuild(AbstractConfigProducer parent, - Element spec) { - - ContainerCluster cluster = new ContainerCluster(parent, "gateway", "gateway"); - - SearchChains searchChains = new SearchChains(cluster, "searchchain"); - Set<ComponentSpecification> inherited = new TreeSet<>(); - //inherited.add(new ComponentSpecification("vespa", null, null)); - { - SearchChain mySearchChain = new SearchChain(new ChainSpecification(new ComponentId("vespaget"), - new ChainSpecification.Inheritance(inherited, null), new ArrayList<>(), new TreeSet<>())); - Searcher getComponent = newVespaClientSearcher("com.yahoo.storage.searcher.GetSearcher"); - mySearchChain.addInnerComponent(getComponent); - searchChains.add(mySearchChain); - } - { - SearchChain mySearchChain = new SearchChain(new ChainSpecification(new ComponentId("vespavisit"), - new ChainSpecification.Inheritance(inherited, null), new ArrayList<>(), new TreeSet<>())); - Searcher getComponent = newVespaClientSearcher("com.yahoo.storage.searcher.VisitSearcher"); - mySearchChain.addInnerComponent(getComponent); - searchChains.add(mySearchChain); - } - - ContainerSearch containerSearch = new ContainerSearch(cluster, searchChains, new ContainerSearch.Options()); - cluster.setSearch(containerSearch); - - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandler", "http://*/feed")); - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandlerRemove", "http://*/remove")); - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandlerRemoveLocation", "http://*/removelocation")); - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandlerGet", "http://*/get")); - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandlerVisit", "http://*/visit")); - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandlerCompatibility", "http://*/document")); - cluster.addComponent(newVespaClientHandler("com.yahoo.feedhandler.VespaFeedHandlerStatus", "http://*/feedstatus")); - final ProcessingHandler<SearchChains> searchHandler = new ProcessingHandler<>( - cluster.getSearch().getChains(), "com.yahoo.search.handler.SearchHandler"); - searchHandler.addServerBindings("http://*/search/*"); - cluster.addComponent(searchHandler); - - ContainerModelBuilder.addDefaultHandler_legacyBuilder(cluster); - - //BEGIN HACK for docproc chains: - DocprocChains docprocChains = getDocprocChains(cluster, spec); - if (docprocChains != null) { - ContainerDocproc containerDocproc = new ContainerDocproc(cluster, docprocChains); - cluster.setDocproc(containerDocproc); - } - //END HACK - - return cluster; - } - - private Handler newVespaClientHandler(String componentId, String binding) { - Handler<AbstractConfigProducer<?>> handler = new Handler<>(new ComponentModel( - BundleInstantiationSpecification.getFromStrings(componentId, null, vespaClientBundleSpecification), "")); - handler.addServerBindings(binding); - handler.addServerBindings(binding + '/'); - return handler; - } - - private Searcher newVespaClientSearcher(String componentSpec) { - return new Searcher<>(new ChainedComponentModel( - BundleInstantiationSpecification.getFromStrings(componentSpec, null, vespaClientBundleSpecification), - new Dependencies(null, null, null))); - } - - //BEGIN HACK for docproc chains: - private DocprocChains getDocprocChains(AbstractConfigProducer qrs, Element gateways) { - Element clients = (Element) gateways.getParentNode(); - Element services = (Element) clients.getParentNode(); - if (services == null) { - return null; - } - - Element docproc = XML.getChild(services, "docproc"); - if (docproc == null) { - return null; - } - - String version = docproc.getAttribute("version"); - if (version.startsWith("1.")) { - return null; - } else if (version.startsWith("2.")) { - return null; - } else if (version.startsWith("3.")) { - return getDocprocChainsV3(qrs, docproc); - } else { - throw new IllegalArgumentException("Docproc version " + version + " unknown."); - } - } - - private DocprocChains getDocprocChainsV3(AbstractConfigProducer qrs, Element docproc) { - Element docprocChainsElem = XML.getChild(docproc, "docprocchains"); - if (docprocChainsElem == null) { - return null; - } - return new DomDocprocChainsBuilder(null, true).build(qrs, docprocChainsElem); - } - //END HACK - } - - public static class ContainerHttpGatewayBuilder extends DomConfigProducerBuilder<ContainerHttpGateway> { - int index; - ContainerCluster cluster; - - public ContainerHttpGatewayBuilder(ContainerCluster cluster, int index) { - this.index = index; - this.cluster = cluster; - } - - @Override - protected ContainerHttpGateway doBuild(AbstractConfigProducer parent, Element spec) { - // TODO: remove port handling - int port = 19020; - if (spec != null && spec.hasAttribute("baseport")) { - port = Integer.parseInt(spec.getAttribute("baseport")); - } - ContainerHttpGateway httpGateway = new ContainerHttpGateway(cluster, "" + index, port, index); - List<Container> containers = new ArrayList<>(); - containers.add(httpGateway); - - cluster.addContainers(containers); - return httpGateway; - } - } - /** * This class parses the feederoptions xml tag and produces Vespa config output. * @@ -553,4 +337,5 @@ public class DomV20ClientsBuilder { return builder; } } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java index 7dabfdc600b..c83f6098a0f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/builder/xml/dom/NodesSpecification.java @@ -25,14 +25,22 @@ public class NodesSpecification { private final int groups; + /** + * Whether the capacity amount specified is required or can it be relaxed + * at the discretion of the component fulfilling it + */ + private final boolean required; + private final Optional<String> flavor; private final Optional<String> dockerImage; - private NodesSpecification(boolean dedicated, int count, int groups, Optional<String> flavor, Optional<String> dockerImage) { + private NodesSpecification(boolean dedicated, int count, int groups, boolean required, + Optional<String> flavor, Optional<String> dockerImage) { this.dedicated = dedicated; this.count = count; this.groups = groups; + this.required = required; this.flavor = flavor; this.dockerImage = dockerImage; } @@ -41,6 +49,7 @@ public class NodesSpecification { this(dedicated, nodesElement.requiredIntegerAttribute("count"), nodesElement.getIntegerAttribute("groups", 1), + nodesElement.getBooleanAttribute("required", false), Optional.ofNullable(nodesElement.getStringAttribute("flavor")), Optional.ofNullable(nodesElement.getStringAttribute("docker-image"))); } @@ -78,7 +87,7 @@ public class NodesSpecification { /** Returns a requirement from <code>count</code> nondedicated nodes in one group */ public static NodesSpecification nonDedicated(int count) { - return new NodesSpecification(false, count, 1, Optional.empty(), Optional.empty()); + return new NodesSpecification(false, count, 1, false, Optional.empty(), Optional.empty()); } /** @@ -95,7 +104,7 @@ public class NodesSpecification { public Map<HostResource, ClusterMembership> provision(HostSystem hostSystem, ClusterSpec.Type clusterType, ClusterSpec.Id clusterId, DeployLogger logger) { ClusterSpec cluster = ClusterSpec.request(clusterType, clusterId, dockerImage); - return hostSystem.allocateHosts(cluster, Capacity.fromNodeCount(count, flavor), groups, logger); + return hostSystem.allocateHosts(cluster, Capacity.fromNodeCount(count, flavor, required), groups, logger); } @Override diff --git a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java index 55cfc8b2fba..c1ad6eead47 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java @@ -26,7 +26,7 @@ import java.util.Set; import java.util.TreeSet; /** - * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + * @author Einar M R Rosenvinge * @since 5.1.11 */ public class ContainerDocumentApi implements FeederConfig.Producer { 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 e92bffe2542..1351933fbc8 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 @@ -16,6 +16,7 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.NodeType; import com.yahoo.container.jdisc.config.MetricDefaultsConfig; +import com.yahoo.path.Path; import com.yahoo.search.rendering.RendererRegistry; import com.yahoo.text.XML; import com.yahoo.vespa.defaults.Defaults; @@ -104,7 +105,6 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { checkVersion(spec); this.log = modelContext.getDeployLogger(); - ContainerCluster cluster = createContainerCluster(spec, modelContext); addClusterContent(cluster, spec, modelContext); addBundlesForPlatformComponents(cluster); @@ -587,9 +587,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { private ContainerDocumentApi buildDocumentApi(ContainerCluster cluster, Element spec) { Element documentApiElement = XML.getChild(spec, "document-api"); - if (documentApiElement == null) { - return null; - } + if (documentApiElement == null) return null; ContainerDocumentApi.Options documentApiOptions = DocumentApiOptionsBuilder.build(documentApiElement); return new ContainerDocumentApi(cluster, documentApiOptions); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java index df2090db166..b1ffd55b0f0 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/DocumentApiOptionsBuilder.java @@ -12,10 +12,11 @@ import java.util.List; import java.util.logging.Logger; /** - * @author <a href="mailto:einarmr@yahoo-inc.com">Einar M R Rosenvinge</a> + * @author Einar M R Rosenvinge * @since 5.1.11 */ public class DocumentApiOptionsBuilder { + private static final Logger log = Logger.getLogger(DocumentApiOptionsBuilder.class.getName()); private static final String[] DEFAULT_BINDINGS = {"http://*/", "https://*/"}; @@ -116,4 +117,5 @@ public class DocumentApiOptionsBuilder { String value = getCleanValue(spec, "abortondocumenterror"); return value == null ? null : Boolean.parseBoolean(value); } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java index 56e275e74ac..7e24285c6fb 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/ContentSearchCluster.java @@ -31,6 +31,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot /** The single, indexed search cluster this sets up (supporting multiple document types), or null if none */ private IndexedSearchCluster indexedCluster; + private Redundancy redundancy; private final String clusterName; Map<String, NewDocumentType> documentDefinitions; @@ -254,6 +255,7 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot if (usesHierarchicDistribution()) { indexedCluster.setMaxNodesDownPerFixedRow((redundancy.effectiveFinalRedundancy() / groupToSpecMap.size()) - 1); } + this.redundancy = redundancy; } @Override @@ -287,6 +289,9 @@ public class ContentSearchCluster extends AbstractConfigProducer implements Prot if (tuning != null) { tuning.getConfig(builder); } + if (redundancy != null) { + redundancy.getConfig(builder); + } } @Override diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java b/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java index 262c985e733..918bdcb8cb7 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/Redundancy.java @@ -2,19 +2,21 @@ package com.yahoo.vespa.model.content; import com.yahoo.vespa.config.content.StorDistributionConfig; +import com.yahoo.vespa.config.search.core.ProtonConfig; /** * Configuration of the redundancy of a content cluster. * * @author bratseth */ -public class Redundancy implements StorDistributionConfig.Producer { +public class Redundancy implements StorDistributionConfig.Producer, ProtonConfig.Producer { private final int initialRedundancy ; private final int finalRedundancy; private final int readyCopies; private int implicitGroups = 1; + private int explicitGroups = 1; /** The total number of nodes available in this cluster (assigned when this becomes known) */ private int totalNodes = 0; @@ -39,6 +41,7 @@ public class Redundancy implements StorDistributionConfig.Producer { * values returned in the config. */ public void setImplicitGroups(int implicitGroups) { this.implicitGroups = implicitGroups; } + public void setExplicitGroups(int explicitGroups) { this.explicitGroups = explicitGroups; } public int initialRedundancy() { return initialRedundancy; } public int finalRedundancy() { return finalRedundancy; } @@ -54,4 +57,11 @@ public class Redundancy implements StorDistributionConfig.Producer { builder.redundancy(effectiveFinalRedundancy()); builder.ready_copies(effectiveReadyCopies()); } + @Override + public void getConfig(ProtonConfig.Builder builder) { + ProtonConfig.Distribution.Builder distBuilder = new ProtonConfig.Distribution.Builder(); + distBuilder.redundancy(finalRedundancy/explicitGroups); + distBuilder.searchablecopies(readyCopies/(explicitGroups*implicitGroups)); + builder.distribution(distBuilder); + } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java index fa417b34844..ef05a3d6ff5 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/content/cluster/ContentCluster.java @@ -104,8 +104,7 @@ public class ContentCluster extends AbstractConfigProducer implements StorDistri String routingSelection = new DocumentSelectionBuilder().build(contentElement.getChild("documents")); Redundancy redundancy = new RedundancyBuilder().build(contentElement); - ContentCluster c = new ContentCluster(ancestor, getClusterName(contentElement), documentDefinitions, - routingSelection, redundancy); + ContentCluster c = new ContentCluster(ancestor, getClusterName(contentElement), documentDefinitions, routingSelection, redundancy); c.clusterControllerConfig = new ClusterControllerConfig.Builder(getClusterName(contentElement), contentElement).build(c, contentElement.getXml()); c.search = new ContentSearchCluster.Builder(documentDefinitions).build(c, contentElement.getXml()); c.persistenceFactory = new EngineFactoryBuilder().build(contentElement, c); @@ -113,6 +112,7 @@ public class ContentCluster extends AbstractConfigProducer implements StorDistri c.distributorNodes = new DistributorCluster.Builder(c).build(c, w3cContentElement); c.rootGroup = new StorageGroup.Builder(contentElement, c, deployLogger).buildRootGroup(); validateThatGroupSiblingsAreUnique(c.clusterName, c.rootGroup); + redundancy.setExplicitGroups(c.getRootGroup().getNumberOfLeafGroups()); c.search.handleRedundancy(redundancy); IndexedSearchCluster index = c.search.getIndexed(); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributionConfigProducer.java b/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributionConfigProducer.java index 630118cc60c..095a5e29450 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributionConfigProducer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributionConfigProducer.java @@ -13,6 +13,7 @@ import java.util.Map; * @author tonytv */ public class FileDistributionConfigProducer extends AbstractConfigProducer { + private final Map<Host, FileDistributorService> fileDistributorServices = new IdentityHashMap<>(); private final FileDistributor fileDistributor; private final FileDistributionOptions options; @@ -56,4 +57,5 @@ public class FileDistributionConfigProducer extends AbstractConfigProducer { return new FileDistributionConfigProducer(ancestor, fileDistributor, options); } } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributor.java b/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributor.java index 4dc24618a61..df7b4f58ab5 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributor.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/filedistribution/FileDistributor.java @@ -117,4 +117,5 @@ public class FileDistributor { result.addAll(asList(additionalHosts)); return result; } + } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/utils/FileSender.java b/config-model/src/main/java/com/yahoo/vespa/model/utils/FileSender.java index 4ab9ed3af85..84685ecef3d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/utils/FileSender.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/utils/FileSender.java @@ -32,8 +32,8 @@ public class FileSender implements Serializable { public static FileReference sendFileToServices(String relativePath, Collection<? extends AbstractService> services) { if (services.isEmpty()) { - throw new IllegalStateException("'sendFileToServices called for empty services!" + - " - This should never happen!"); + throw new IllegalStateException("No service instances. Probably a standalone cluster setting up <nodes> " + + "using 'count' instead of <node> tags."); } FileReference fileref = null; for (AbstractService service : services) { @@ -146,4 +146,5 @@ public class FileSender implements Serializable { } builder.setValue(reference.value()); } + }
\ No newline at end of file diff --git a/config-model/src/main/java/com/yahoo/vespa/model/utils/FreezableMap.java b/config-model/src/main/java/com/yahoo/vespa/model/utils/FreezableMap.java index a05008cc9a0..211413f9bff 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/utils/FreezableMap.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/utils/FreezableMap.java @@ -4,8 +4,9 @@ package com.yahoo.vespa.model.utils; import java.util.*; /** - * Delegates to a map that can be froozen. + * Delegates to a map that can be frozen. * Not thread safe. + * * @author tonytv */ public class FreezableMap<K, V> implements Map<K, V> { @@ -88,4 +89,5 @@ public class FreezableMap<K, V> implements Map<K, V> { public boolean isFrozen() { return frozen; } + } diff --git a/config-model/src/main/resources/schema/common.rnc b/config-model/src/main/resources/schema/common.rnc index 06e7b945c18..b89fe0d7fcb 100644 --- a/config-model/src/main/resources/schema/common.rnc +++ b/config-model/src/main/resources/schema/common.rnc @@ -23,6 +23,7 @@ Nodes = element nodes { OptionalDedicatedNodes = element nodes { attribute count { xsd:positiveInteger } & attribute flavor { xsd:string }? & + attribute required { xsd:boolean }? & attribute docker-image { xsd:string }? & attribute dedicated { xsd:boolean }? } diff --git a/config-model/src/main/resources/schema/containercluster.rnc b/config-model/src/main/resources/schema/containercluster.rnc index 8f1ed0d874e..17e38883755 100644 --- a/config-model/src/main/resources/schema/containercluster.rnc +++ b/config-model/src/main/resources/schema/containercluster.rnc @@ -161,7 +161,7 @@ ProcessingInContainer = element processing { -# DOCUMENT API/GATEWAY: +# DOCUMENT API: DocumentApi = element document-api { ServerBindings & @@ -194,6 +194,7 @@ NodesOfContainerCluster = element nodes { ( attribute count { xsd:positiveInteger } & attribute flavor { xsd:string }? & + attribute required { xsd:boolean }? & attribute docker-image { xsd:string }? ) | diff --git a/config-model/src/main/resources/schema/content.rnc b/config-model/src/main/resources/schema/content.rnc index 30b931053d5..c3a8386ac5e 100644 --- a/config-model/src/main/resources/schema/content.rnc +++ b/config-model/src/main/resources/schema/content.rnc @@ -216,6 +216,7 @@ ContentNodes = element nodes { ( attribute count { xsd:positiveInteger } & attribute flavor { xsd:string }? & + attribute required { xsd:boolean }? & attribute docker-image { xsd:string }? & attribute groups { xsd:positiveInteger }? ) @@ -260,6 +261,7 @@ Group = element group { element nodes { attribute count { xsd:positiveInteger } & attribute flavor { xsd:string }? & + attribute required { xsd:boolean }? & attribute docker-image { xsd:string }? & attribute groups { xsd:positiveInteger }? } diff --git a/config-model/src/main/resources/schema/deployment.rnc b/config-model/src/main/resources/schema/deployment.rnc new file mode 100644 index 00000000000..22ceab4efa5 --- /dev/null +++ b/config-model/src/main/resources/schema/deployment.rnc @@ -0,0 +1,26 @@ +# RELAX NG Compact Syntax +# Vespa Deployment file + +start = element deployment { + attribute version { "1.0" } & + Test? & + Staging? & + Prod* +} + +Test = element test { + text +} + +Staging = element staging { + text +} + +Prod = + element prod { + attribute global-service-id { text }?, + element region { + attribute active { xsd:boolean }, + text + }* + } diff --git a/config-model/src/main/resources/schema/schemas.xml b/config-model/src/main/resources/schema/schemas.xml index 728754e3a5f..ed39af3d490 100644 --- a/config-model/src/main/resources/schema/schemas.xml +++ b/config-model/src/main/resources/schema/schemas.xml @@ -3,4 +3,5 @@ <locatingRules xmlns="http://thaiopensource.com/ns/locating-rules/1.0"> <documentElement localName="hosts" uri="hosts.rnc"/> <documentElement localName="services" uri="services.rnc"/> + <documentElement localName="deployment" uri="deployment.rnc"/> </locatingRules> diff --git a/config-model/src/test/cfg/application/app1/deployment.xml b/config-model/src/test/cfg/application/app1/deployment.xml new file mode 100644 index 00000000000..34d2036c1a5 --- /dev/null +++ b/config-model/src/test/cfg/application/app1/deployment.xml @@ -0,0 +1,8 @@ +<deployment version="1.0"> + <test/> + <staging/> + <prod global-service-id="query"> + <region active="true">us-east-3</region> + <region active="false">us-west-1</region> + </prod> +</deployment> diff --git a/config-model/src/test/cfg/application/app_invalid_deployment_xml/deployment.xml b/config-model/src/test/cfg/application/app_invalid_deployment_xml/deployment.xml new file mode 100644 index 00000000000..7a1089a6c1e --- /dev/null +++ b/config-model/src/test/cfg/application/app_invalid_deployment_xml/deployment.xml @@ -0,0 +1,8 @@ +<deployment version="1.0"> + <test/> + <staging/> + <prod global-service-id="query"> + <region>us-east-3</region> + <region active="false">us-west-1</region> + </prod> +</deployment> diff --git a/config-model/src/test/cfg/application/app_invalid_deployment_xml/hosts.xml b/config-model/src/test/cfg/application/app_invalid_deployment_xml/hosts.xml new file mode 100644 index 00000000000..132169097cf --- /dev/null +++ b/config-model/src/test/cfg/application/app_invalid_deployment_xml/hosts.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hosts> + <host name="localhost"> + <alias>node1</alias> + </host> + <host name="schmocalhost"> + <alias>node2</alias> + </host> +</hosts> diff --git a/config-model/src/test/cfg/application/app_invalid_deployment_xml/services.xml b/config-model/src/test/cfg/application/app_invalid_deployment_xml/services.xml new file mode 100644 index 00000000000..a1702af234f --- /dev/null +++ b/config-model/src/test/cfg/application/app_invalid_deployment_xml/services.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" ?> +<services version="1.0"> + + <admin version="2.0"> + <adminserver hostalias="node1"/> + </admin> + + <container version="1.0"> + <nodes> + <node hostalias="node1" /> + </nodes> + <search/> + </container> + +</services> diff --git a/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/deployment.xml b/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/deployment.xml new file mode 100644 index 00000000000..d04cc5dfd65 --- /dev/null +++ b/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/deployment.xml @@ -0,0 +1,5 @@ +<deployment version="1.0"> + <test/> + <staging/> + <prod /> +</deployment> diff --git a/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/hosts.xml b/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/hosts.xml new file mode 100644 index 00000000000..132169097cf --- /dev/null +++ b/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/hosts.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8" ?> +<hosts> + <host name="localhost"> + <alias>node1</alias> + </host> + <host name="schmocalhost"> + <alias>node2</alias> + </host> +</hosts> diff --git a/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/services.xml b/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/services.xml new file mode 100644 index 00000000000..a1702af234f --- /dev/null +++ b/config-model/src/test/cfg/application/empty_prod_region_in_deployment_xml/services.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8" ?> +<services version="1.0"> + + <admin version="2.0"> + <adminserver hostalias="node1"/> + </admin> + + <container version="1.0"> + <nodes> + <node hostalias="node1" /> + </nodes> + <search/> + </container> + +</services> diff --git a/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java b/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java index d4e521ebd13..0334b3c867b 100644 --- a/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java +++ b/config-model/src/test/java/com/yahoo/config/model/ApplicationDeployTest.java @@ -21,6 +21,7 @@ import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.search.SearchDefinition; import org.json.JSONException; import org.junit.After; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -203,6 +204,28 @@ public class ApplicationDeployTest { assertThat(getSearchDefinitions(app).size(), is(6)); } + @Test + public void testThatAppWithDeploymentXmlIsValid() throws IOException { + File tmpDir = Files.createTempDir(); + IOUtils.copyDirectory(new File(TESTDIR, "app1"), tmpDir); + createAppPkg(tmpDir.getAbsolutePath()); + } + + @Ignore // TODO: Enable when code in ApplicationPackageXmlFilesValidator does validation of deployment.xml + @Test(expected = IllegalArgumentException.class) + public void testThatAppWithIllegalDeploymentXmlIsNotValid() throws IOException { + File tmpDir = Files.createTempDir(); + IOUtils.copyDirectory(new File(TESTDIR, "app_invalid_deployment_xml"), tmpDir); + createAppPkg(tmpDir.getAbsolutePath()); + } + + @Test + public void testThatAppWithIllegalEmptyProdRegion() throws IOException { + File tmpDir = Files.createTempDir(); + IOUtils.copyDirectory(new File(TESTDIR, "empty_prod_region_in_deployment_xml"), tmpDir); + createAppPkg(tmpDir.getAbsolutePath()); + } + private List<SearchDefinition> getSearchDefinitions(FilesApplicationPackage app) { return new DeployState.Builder().applicationPackage(app).build().getSearchDefinitions(); } diff --git a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java index 86fabdf26bc..8ed4539456a 100644 --- a/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java +++ b/config-model/src/test/java/com/yahoo/config/model/provision/ModelProvisioningTest.java @@ -522,6 +522,7 @@ public class ModelProvisioningTest { assertEquals(1, clusterControllers.getContainers().size()); // TODO: Expected 5 with this feature reactivated } + @Test public void testClusterControllersAreNotPlacedOnRetiredNodes() { String services = "<?xml version='1.0' encoding='utf-8' ?>\n" + @@ -907,6 +908,26 @@ public class ModelProvisioningTest { assertThat(cluster.getRootGroup().getNodes().get(0).getConfigId(), is("bar/storage/0")); } + @Test(expected = IllegalArgumentException.class) + public void testRequiringMoreNodesThanAreAvailable() throws ParseException { + String services = + "<?xml version='1.0' encoding='utf-8' ?>\n" + + "<services>" + + " <content version='1.0' id='bar'>" + + " <redundancy>1</redundancy>" + + " <documents>" + + " <document type='type1' mode='index'/>" + + " </documents>" + + " <nodes count='3' required='true'/>" + + " </content>" + + "</services>"; + + int numberOfHosts = 2; + VespaModelTester tester = new VespaModelTester(); + tester.addHosts(numberOfHosts); + tester.createModel(services, false); + } + @Test public void testUsingNodesCountAttributesAndGettingJustOneNode() { String services = diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java index 88ba6d885b8..3bec45279d9 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java @@ -35,6 +35,14 @@ public class ContainerRestartValidatorTest { assertTrue(result.isEmpty()); } + @Test + public void validator_returns_empty_list_for_containers_with_restart_on_deploy_disabled_where_previously_enabled() { + VespaModel current = createModel(true); + VespaModel next = createModel(false); + List<ConfigChangeAction> result = validateModel(current, next); + assertTrue(result.isEmpty()); + } + private static List<ConfigChangeAction> validateModel(VespaModel current, VespaModel next) { return new ContainerRestartValidator() .validate(current, next, new ValidationOverrides(Collections.emptyList())); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterTest.java index bcb113687ec..126fcf7a583 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/ClusterTest.java @@ -9,6 +9,7 @@ import com.yahoo.vespa.config.content.core.StorServerConfig; import com.yahoo.vespa.config.content.FleetcontrollerConfig; import com.yahoo.vespa.config.content.StorDistributionConfig; import com.yahoo.metrics.MetricsmanagerConfig; +import com.yahoo.vespa.config.search.core.ProtonConfig; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.content.cluster.ContentCluster; @@ -34,44 +35,99 @@ public class ClusterTest extends ContentBaseTest { } @Test - public void testRedundancy() { - StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder(); - parse("" + - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <engine>" + - " <proton>" + - " <searchable-copies>3</searchable-copies>" + - " </proton>" + - " </engine>" + - " <redundancy reply-after=\"4\">5</redundancy>\n" + - " <group>" + - " <node hostalias=\"mockhost\" distribution-key=\"0\"/>\"" + - " <node hostalias=\"mockhost\" distribution-key=\"1\"/>\"" + - " <node hostalias=\"mockhost\" distribution-key=\"2\"/>\"" + - " <node hostalias=\"mockhost\" distribution-key=\"3\"/>\"" + - " <node hostalias=\"mockhost\" distribution-key=\"4\"/>\"" + - " </group>" + - "</content>" - ).getConfig(builder); + public void testHierarchicRedundancy() { + ContentCluster cc = parse("" + + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <engine>" + + " <proton>" + + " <searchable-copies>3</searchable-copies>" + + " </proton>" + + " </engine>" + + " <redundancy>15</redundancy>\n" + + " <group name='root' distribution-key='0'>" + + " <distribution partitions='1|1|*'/>" + + " <group name='g-1' distribution-key='0'>" + + " <node hostalias='mockhost' distribution-key='0'/>" + + " <node hostalias='mockhost' distribution-key='1'/>" + + " <node hostalias='mockhost' distribution-key='2'/>" + + " <node hostalias='mockhost' distribution-key='3'/>" + + " <node hostalias='mockhost' distribution-key='4'/>" + + " </group>" + + " <group name='g-2' distribution-key='1'>" + + " <node hostalias='mockhost' distribution-key='5'/>" + + " <node hostalias='mockhost' distribution-key='6'/>" + + " <node hostalias='mockhost' distribution-key='7'/>" + + " <node hostalias='mockhost' distribution-key='8'/>" + + " <node hostalias='mockhost' distribution-key='9'/>" + + " </group>" + + " <group name='g-3' distribution-key='1'>" + + " <node hostalias='mockhost' distribution-key='10'/>" + + " <node hostalias='mockhost' distribution-key='11'/>" + + " <node hostalias='mockhost' distribution-key='12'/>" + + " <node hostalias='mockhost' distribution-key='13'/>" + + " <node hostalias='mockhost' distribution-key='14'/>" + + " </group>" + + " </group>" + + "</content>" + ); + StorDistributionConfig.Builder storBuilder = new StorDistributionConfig.Builder(); + cc.getConfig(storBuilder); + StorDistributionConfig storConfig = new StorDistributionConfig(storBuilder); + assertEquals(15, storConfig.initial_redundancy()); + assertEquals(15, storConfig.redundancy()); + assertEquals(3, storConfig.ready_copies()); + ProtonConfig.Builder protonBuilder = new ProtonConfig.Builder(); + cc.getSearch().getConfig(protonBuilder); + ProtonConfig protonConfig = new ProtonConfig(protonBuilder); + assertEquals(1, protonConfig.distribution().searchablecopies()); + assertEquals(5, protonConfig.distribution().redundancy()); + } - StorDistributionConfig config = new StorDistributionConfig(builder); - assertEquals(4, config.initial_redundancy()); - assertEquals(5, config.redundancy()); - assertEquals(3, config.ready_copies()); + @Test + public void testRedundancy() { + ContentCluster cc = parse("" + + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <engine>" + + " <proton>" + + " <searchable-copies>3</searchable-copies>" + + " </proton>" + + " </engine>" + + " <redundancy reply-after='4'>5</redundancy>\n" + + " <group>" + + " <node hostalias='mockhost' distribution-key='0'/>" + + " <node hostalias='mockhost' distribution-key='1'/>" + + " <node hostalias='mockhost' distribution-key='2'/>" + + " <node hostalias='mockhost' distribution-key='3'/>" + + " <node hostalias='mockhost' distribution-key='4'/>" + + " </group>" + + "</content>" + ); + StorDistributionConfig.Builder storBuilder = new StorDistributionConfig.Builder(); + cc.getConfig(storBuilder); + StorDistributionConfig storConfig = new StorDistributionConfig(storBuilder); + assertEquals(4, storConfig.initial_redundancy()); + assertEquals(5, storConfig.redundancy()); + assertEquals(3, storConfig.ready_copies()); + ProtonConfig.Builder protonBuilder = new ProtonConfig.Builder(); + cc.getSearch().getConfig(protonBuilder); + ProtonConfig protonConfig = new ProtonConfig(protonBuilder); + assertEquals(3, protonConfig.distribution().searchablecopies()); + assertEquals(5, protonConfig.distribution().redundancy()); } @Test public void testNoId() { ContentCluster c = parse( - "<content version=\"1.0\">\n" + - " <redundancy>1</redundancy>\n" + - " <documents/>" + - " <redundancy reply-after=\"4\">5</redundancy>\n" + - " <group>" + - " <node hostalias=\"mockhost\" distribution-key=\"0\"/>\"" + - " </group>" + - "</content>" + "<content version=\"1.0\">\n" + + " <redundancy>1</redundancy>\n" + + " <documents/>" + + " <redundancy reply-after=\"4\">5</redundancy>\n" + + " <group>" + + " <node hostalias=\"mockhost\" distribution-key=\"0\"/>\"" + + " </group>" + + "</content>" ); assertEquals("content", c.getName()); @@ -81,14 +137,14 @@ public class ClusterTest extends ContentBaseTest { public void testRedundancyDefaults() { StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder(); parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <group>" + - " <node hostalias=\"mockhost\" distribution-key=\"0\"/>\"" + - " <node hostalias=\"mockhost\" distribution-key=\"1\"/>\"" + - " <node hostalias=\"mockhost\" distribution-key=\"2\"/>\"" + - " </group>" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <group>" + + " <node hostalias=\"mockhost\" distribution-key=\"0\"/>\"" + + " <node hostalias=\"mockhost\" distribution-key=\"1\"/>\"" + + " <node hostalias=\"mockhost\" distribution-key=\"2\"/>\"" + + " </group>" + + "</content>" ).getConfig(builder); StorDistributionConfig config = new StorDistributionConfig(builder); @@ -99,39 +155,40 @@ public class ClusterTest extends ContentBaseTest { @Test public void testEndToEnd() throws Exception { - String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + - "<services>\n" + - "\n" + - " <admin version=\"2.0\">\n" + - " <adminserver hostalias=\"configserver\" />\n" + - " <logserver hostalias=\"logserver\" />\n" + - " <slobroks>\n" + - " <slobrok hostalias=\"configserver\" />\n" + - " <slobrok hostalias=\"logserver\" />\n" + - " </slobroks>\n" + - " <cluster-controllers>\n" + - " <cluster-controller hostalias=\"configserver\"/>" + - " <cluster-controller hostalias=\"configserver2\"/>" + - " <cluster-controller hostalias=\"configserver3\"/>" + - " </cluster-controllers>\n" + - " </admin>\n" + - " <content version='1.0' id='bar'>" + - " <redundancy>1</redundancy>\n" + - " <documents>" + - " <document type=\"type1\" mode=\"index\"/>\n" + - " <document type=\"type2\" mode=\"index\"/>\n" + - " </documents>\n" + - " <group>" + - " <node hostalias='node0' distribution-key='0' />" + - " </group>" + - " <tuning>" + - " <cluster-controller>\n" + - " <init-progress-time>34567</init-progress-time>" + - " </cluster-controller>" + - " </tuning>" + - " </content>" + - "\n" + - "</services>"; + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<services>\n" + + "\n" + + " <admin version=\"2.0\">\n" + + " <adminserver hostalias=\"configserver\" />\n" + + " <logserver hostalias=\"logserver\" />\n" + + " <slobroks>\n" + + " <slobrok hostalias=\"configserver\" />\n" + + " <slobrok hostalias=\"logserver\" />\n" + + " </slobroks>\n" + + " <cluster-controllers>\n" + + " <cluster-controller hostalias=\"configserver\"/>" + + " <cluster-controller hostalias=\"configserver2\"/>" + + " <cluster-controller hostalias=\"configserver3\"/>" + + " </cluster-controllers>\n" + + " </admin>\n" + + " <content version='1.0' id='bar'>" + + " <redundancy>1</redundancy>\n" + + " <documents>" + + " <document type=\"type1\" mode=\"index\"/>\n" + + " <document type=\"type2\" mode=\"index\"/>\n" + + " </documents>\n" + + " <group>" + + " <node hostalias='node0' distribution-key='0' />" + + " </group>" + + " <tuning>" + + " <cluster-controller>\n" + + " <init-progress-time>34567</init-progress-time>" + + " </cluster-controller>" + + " </tuning>" + + " </content>" + + "\n" + + "</services>"; List<String> sds = ApplicationPackageUtils.generateSearchDefinitions("type1", "type2"); VespaModel model = (new VespaModelCreatorWithMockPkg(null, xml, sds)).create(); @@ -183,32 +240,33 @@ public class ClusterTest extends ContentBaseTest { @Test public void testSearchTuning() throws Exception { - String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + - "<services>\n" + - "\n" + - " <admin version=\"2.0\">\n" + - " <adminserver hostalias=\"node0\" />\n" + - " <cluster-controllers>\n" + - " <cluster-controller hostalias=\"node0\"/>" + - " </cluster-controllers>\n" + - " </admin>\n" + - " <content version='1.0' id='bar'>" + - " <redundancy>1</redundancy>\n" + - " <documents>" + - " <document type=\"type1\" mode='index'/>\n" + - " <document type=\"type2\" mode='index'/>\n" + - " </documents>\n" + - " <group>" + - " <node hostalias='node0' distribution-key='0'/>" + - " </group>" + - " <tuning>\n" + - " <cluster-controller>" + - " <init-progress-time>34567</init-progress-time>" + - " </cluster-controller>" + - " </tuning>" + - " </content>" + - "\n" + - "</services>"; + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<services>\n" + + "\n" + + " <admin version=\"2.0\">\n" + + " <adminserver hostalias=\"node0\" />\n" + + " <cluster-controllers>\n" + + " <cluster-controller hostalias=\"node0\"/>" + + " </cluster-controllers>\n" + + " </admin>\n" + + " <content version='1.0' id='bar'>" + + " <redundancy>1</redundancy>\n" + + " <documents>" + + " <document type=\"type1\" mode='index'/>\n" + + " <document type=\"type2\" mode='index'/>\n" + + " </documents>\n" + + " <group>" + + " <node hostalias='node0' distribution-key='0'/>" + + " </group>" + + " <tuning>\n" + + " <cluster-controller>" + + " <init-progress-time>34567</init-progress-time>" + + " </cluster-controller>" + + " </tuning>" + + " </content>" + + "\n" + + "</services>"; List<String> sds = ApplicationPackageUtils.generateSearchDefinitions("type1", "type2"); VespaModel model = new VespaModelCreatorWithMockPkg(getHosts(), xml, sds).create(); @@ -232,21 +290,22 @@ public class ClusterTest extends ContentBaseTest { @Test public void testRedundancyRequired() throws Exception { - String xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + - "<services>\n" + - "\n" + - " <admin version=\"2.0\">\n" + - " <adminserver hostalias=\"node0\" />\n" + - " </admin>\n" + - " <content version='1.0' id='bar'>" + - " <documents>" + - " <document type=\"type1\" mode='index'/>\n" + - " </documents>\n" + - " <group>\n" + - " <node hostalias='node0' distribution-key='0'/>\n" + - " </group>\n" + - " </content>\n" + - "</services>\n"; + String xml = + "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + + "<services>\n" + + "\n" + + " <admin version=\"2.0\">\n" + + " <adminserver hostalias=\"node0\" />\n" + + " </admin>\n" + + " <content version='1.0' id='bar'>" + + " <documents>" + + " <document type=\"type1\" mode='index'/>\n" + + " </documents>\n" + + " <group>\n" + + " <node hostalias='node0' distribution-key='0'/>\n" + + " </group>\n" + + " </content>\n" + + "</services>\n"; List<String> sds = ApplicationPackageUtils.generateSearchDefinitions("type1", "type2"); try{ @@ -261,12 +320,12 @@ public class ClusterTest extends ContentBaseTest { public void testRedundancyFinalLessThanInitial() { try { parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <redundancy reply-after=\"4\">2</redundancy>\n" + - " <group>" + - " <node hostalias='node0' distribution-key='0' />" + - " </group>" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <redundancy reply-after=\"4\">2</redundancy>\n" + + " <group>" + + " <node hostalias='node0' distribution-key='0' />" + + " </group>" + + "</content>" ); fail("no exception thrown"); } catch (Exception e) { @@ -277,17 +336,17 @@ public class ClusterTest extends ContentBaseTest { public void testReadyTooHigh() { try { parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <engine>" + - " <proton>" + - " <searchable-copies>3</searchable-copies>" + - " </proton>" + - " </engine>" + - " <redundancy>2</redundancy>\n" + - " <group>" + - " <node hostalias='node0' distribution-key='0' />" + - " </group>" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <engine>" + + " <proton>" + + " <searchable-copies>3</searchable-copies>" + + " </proton>" + + " </engine>" + + " <redundancy>2</redundancy>\n" + + " <group>" + + " <node hostalias='node0' distribution-key='0' />" + + " </group>" + + "</content>" ); fail("no exception thrown"); } catch (Exception e) { @@ -308,12 +367,12 @@ public class ClusterTest extends ContentBaseTest { { { FleetcontrollerConfig config = getFleetControllerConfig( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + "</content>" ); assertEquals(0, config.min_storage_up_ratio(), 0.01); @@ -324,17 +383,17 @@ public class ClusterTest extends ContentBaseTest { { FleetcontrollerConfig config = getFleetControllerConfig( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"1\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"2\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"3\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"4\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"5\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"1\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"2\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"3\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"4\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"5\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + "</content>" ); assertNotSame(0, config.min_storage_up_ratio()); @@ -345,12 +404,12 @@ public class ClusterTest extends ContentBaseTest { public void testImplicitDistributionBits() { ContentCluster cluster = parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + "</content>" ); { @@ -368,15 +427,15 @@ public class ClusterTest extends ContentBaseTest { assertEquals(8, config.minsplitcount()); } cluster = parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <engine>" + - " <vds/>" + - " </engine>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <engine>" + + " <vds/>" + + " </engine>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + "</content>" ); { @@ -399,15 +458,15 @@ public class ClusterTest extends ContentBaseTest { public void testExplicitDistributionBits() { ContentCluster cluster = parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - " <tuning>\n" + - " <distribution type=\"strict\"/>\n" + - " </tuning>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + " <tuning>\n" + + " <distribution type=\"strict\"/>\n" + + " </tuning>\n" + + "</content>" ); { @@ -425,18 +484,18 @@ public class ClusterTest extends ContentBaseTest { assertEquals(8, config.minsplitcount()); } cluster = parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <engine>" + - " <vds/>" + - " </engine>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - " <tuning>\n" + - " <distribution type=\"loose\"/>\n" + - " </tuning>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <engine>" + + " <vds/>" + + " </engine>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + " <tuning>\n" + + " <distribution type=\"loose\"/>\n" + + " </tuning>\n" + + "</content>" ); { @@ -459,16 +518,16 @@ public class ClusterTest extends ContentBaseTest { public void testGenerateSearchNodes() { ContentCluster cluster = parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <engine>" + - " <proton/>" + - " </engine>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"1\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <engine>" + + " <proton/>" + + " </engine>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"1\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + "</content>" ); { @@ -492,16 +551,16 @@ public class ClusterTest extends ContentBaseTest { public void testAlternativeNodeSyntax() { ContentCluster cluster = parse( - "<content version=\"1.0\" id=\"test\">\n" + - " <documents/>" + - " <engine>" + - " <proton/>" + - " </engine>" + - " <nodes>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " <node distribution-key=\"1\" hostalias=\"mockhost\"/>\n" + - " </nodes>\n" + - "</content>" + "<content version=\"1.0\" id=\"test\">\n" + + " <documents/>" + + " <engine>" + + " <proton/>" + + " </engine>" + + " <nodes>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " <node distribution-key=\"1\" hostalias=\"mockhost\"/>\n" + + " </nodes>\n" + + "</content>" ); StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder(); @@ -519,13 +578,13 @@ public class ClusterTest extends ContentBaseTest { public void testReadyWhenInitialOne() { StorDistributionConfig.Builder builder = new StorDistributionConfig.Builder(); parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <redundancy>1</redundancy>\n" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + - " </group>" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <redundancy>1</redundancy>\n" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + + " </group>" + + "</content>" ).getConfig(builder); StorDistributionConfig config = new StorDistributionConfig(builder); @@ -536,16 +595,16 @@ public class ClusterTest extends ContentBaseTest { public void testProvider(String tagName, StorServerConfig.Persistence_provider.Type.Enum type) { ContentCluster cluster = parse( - "<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <redundancy>3</redundancy>" + - " <engine>\n" + - " <" + tagName + "/>\n" + - " </engine>\n" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + - " </group>" + - "</content>" + "<content version=\"1.0\" id=\"storage\">\n" + + " <documents/>" + + " <redundancy>3</redundancy>" + + " <engine>\n" + + " <" + tagName + "/>\n" + + " </engine>\n" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + + " </group>" + + "</content>" ); { @@ -582,11 +641,11 @@ public class ClusterTest extends ContentBaseTest { MetricsmanagerConfig.Builder builder = new MetricsmanagerConfig.Builder(); ContentCluster cluster = parse("<content version=\"1.0\" id=\"storage\">\n" + - " <documents/>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + - " </group>\n" + - "</content>" + " <documents/>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>\n" + + " </group>\n" + + "</content>" ); cluster.getConfig(builder); @@ -642,34 +701,34 @@ public class ClusterTest extends ContentBaseTest { @Test public void testConfiguredMetrics() throws Exception { String xml = "" + - "<services>" + - "<content version=\"1.0\" id=\"storage\">\n" + - " <redundancy>1</redundancy>\n" + - " <documents>" + - " <document type=\"type1\" mode='index'/>\n" + - " <document type=\"type2\" mode='index'/>\n" + - " </documents>" + - " <group>\n" + - " <node distribution-key=\"0\" hostalias=\"node0\"/>\n" + - " </group>\n" + - "</content>" + - "<admin version=\"2.0\">" + - " <logserver hostalias=\"node0\"/>" + - " <adminserver hostalias=\"node0\"/>" + - " <metric-consumers>" + - " <consumer name=\"foobar\">" + - " <metric name=\"storage.foo.bar\"/>" + - " </consumer>" + - " <consumer name=\"log\">" + - " <metric name=\"extralogmetric\"/>" + - " <metric name=\"extralogmetric3\"/>" + - " </consumer>" + - " <consumer name=\"fleetcontroller\">" + - " <metric name=\"extraextra\"/>" + - " </consumer>" + - " </metric-consumers>" + - "</admin>" + - "</services>"; + "<services>" + + "<content version=\"1.0\" id=\"storage\">\n" + + " <redundancy>1</redundancy>\n" + + " <documents>" + + " <document type=\"type1\" mode='index'/>\n" + + " <document type=\"type2\" mode='index'/>\n" + + " </documents>" + + " <group>\n" + + " <node distribution-key=\"0\" hostalias=\"node0\"/>\n" + + " </group>\n" + + "</content>" + + "<admin version=\"2.0\">" + + " <logserver hostalias=\"node0\"/>" + + " <adminserver hostalias=\"node0\"/>" + + " <metric-consumers>" + + " <consumer name=\"foobar\">" + + " <metric name=\"storage.foo.bar\"/>" + + " </consumer>" + + " <consumer name=\"log\">" + + " <metric name=\"extralogmetric\"/>" + + " <metric name=\"extralogmetric3\"/>" + + " </consumer>" + + " <consumer name=\"fleetcontroller\">" + + " <metric name=\"extraextra\"/>" + + " </consumer>" + + " </metric-consumers>" + + "</admin>" + + "</services>"; List<String> sds = ApplicationPackageUtils.generateSearchDefinitions("type1", "type2"); @@ -729,33 +788,33 @@ public class ClusterTest extends ContentBaseTest { @Test public void requireThatPreShutdownCommandIsSet() { ContentCluster cluster = parse( - "<content version=\"1.0\" id=\"storage\">" + - " <documents/>" + - " <engine>" + - " <proton>" + - " <flush-on-shutdown>true</flush-on-shutdown>" + - " </proton>" + - " </engine>" + - " <group>" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + - " </group>" + - "</content>"); + "<content version=\"1.0\" id=\"storage\">" + + " <documents/>" + + " <engine>" + + " <proton>" + + " <flush-on-shutdown>true</flush-on-shutdown>" + + " </proton>" + + " </engine>" + + " <group>" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + + " </group>" + + "</content>"); assertThat(cluster.getSearch().getSearchNodes().size(), is(1)); assertTrue(cluster.getSearch().getSearchNodes().get(0).getPreShutdownCommand().isPresent()); cluster = parse( - "<content version=\"1.0\" id=\"storage\">" + - " <documents/>" + - " <engine>" + - " <proton>" + - " <flush-on-shutdown> \n " + - " true </flush-on-shutdown>" + - " </proton>" + - " </engine>" + - " <group>" + - " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + - " </group>" + - "</content>"); + "<content version=\"1.0\" id=\"storage\">" + + " <documents/>" + + " <engine>" + + " <proton>" + + " <flush-on-shutdown> \n " + + " true </flush-on-shutdown>" + + " </proton>" + + " </engine>" + + " <group>" + + " <node distribution-key=\"0\" hostalias=\"mockhost\"/>" + + " </group>" + + "</content>"); assertThat(cluster.getSearch().getSearchNodes().size(), is(1)); assertTrue(cluster.getSearch().getSearchNodes().get(0).getPreShutdownCommand().isPresent()); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java b/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java index 6f4effe0319..2f83d3bc394 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/test/utils/VespaModelCreatorWithMockPkg.java @@ -55,12 +55,13 @@ public class VespaModelCreatorWithMockPkg { VespaModel model = new VespaModel(configModelRegistry, deployState); if (validate) { try { - SchemaValidator validator = SchemaValidator.createTestValidatorHosts(); if (appPkg.getHosts() != null) { - validator.validate(appPkg.getHosts()); + SchemaValidator.createTestValidatorHosts().validate(appPkg.getHosts()); } - validator = SchemaValidator.createTestValidatorServices(); - validator.validate(appPkg.getServices()); + if (appPkg.getDeployment().isPresent()) { + SchemaValidator.createTestValidatorDeployment().validate(appPkg.getDeployment().get()); + } + SchemaValidator.createTestValidatorServices().validate(appPkg.getServices()); } catch (Exception e) { System.err.println(e.getClass()); throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e); |