diff options
author | Jon Bratseth <bratseth@oath.com> | 2018-04-19 15:31:52 +0200 |
---|---|---|
committer | Jon Bratseth <bratseth@oath.com> | 2018-04-19 15:31:52 +0200 |
commit | 7ac8f3b0f6cd3ff3e6556e69cc5aa97aa9ae76b9 (patch) | |
tree | 1e35300d77b8c6cc0d73b0fc6fa6ccf616f7ec90 | |
parent | 1e0a2f24d4159edf46b5b457f07b33121d7e5bbf (diff) |
Load the minimal set of models needed in dev
22 files changed, 258 insertions, 50 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/provision/Host.java b/config-model/src/main/java/com/yahoo/config/model/provision/Host.java index 0374afe4e43..8c8debbae43 100644 --- a/config-model/src/main/java/com/yahoo/config/model/provision/Host.java +++ b/config-model/src/main/java/com/yahoo/config/model/provision/Host.java @@ -2,6 +2,7 @@ package com.yahoo.config.model.provision; import com.google.common.collect.ImmutableList; +import com.yahoo.component.Version; import com.yahoo.config.provision.Flavor; import java.util.ArrayList; @@ -18,6 +19,7 @@ public class Host { private final String hostname; private final ImmutableList<String> aliases; private final Optional<Flavor> flavor; + private final Optional<Version> version; public Host(String hostname) { this(hostname, ImmutableList.of(), Optional.empty()); @@ -28,9 +30,14 @@ public class Host { } public Host(String hostname, List<String> hostAliases, Optional<Flavor> flavor) { + this(hostname, hostAliases, flavor, Optional.empty()); + } + + public Host(String hostname, List<String> hostAliases, Optional<Flavor> flavor, Optional<Version> version) { this.hostname = hostname; this.aliases = ImmutableList.copyOf(hostAliases); this.flavor = flavor; + this.version = version; } public String hostname() { return hostname; } @@ -40,6 +47,9 @@ public class Host { public Optional<Flavor> flavor() { return flavor; } + /** The current Vespa version running on this host, or empty if not known */ + public Optional<Version> version() { return version; } + @Override public String toString() { return hostname + (aliases.size() > 0 ? " (aliases: " + aliases + ")" : "" ) + 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 2e1d507eea1..e6b89d7f390 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 @@ -103,7 +103,7 @@ public class InMemoryProvisioner implements HostProvisioner { List<Host> defaultHosts = freeNodes.get("default"); if (defaultHosts.isEmpty()) throw new IllegalArgumentException("No more hosts of default flavor available"); Host newHost = freeNodes.removeValue("default", 0); - HostSpec hostSpec = new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.empty()); + HostSpec hostSpec = new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.empty(), newHost.version()); legacyMapping.put(alias, hostSpec); return hostSpec; } @@ -148,7 +148,11 @@ public class InMemoryProvisioner implements HostProvisioner { } private HostSpec retire(HostSpec host) { - return new HostSpec(host.hostname(), host.aliases(), host.membership().get().retire()); + return new HostSpec(host.hostname(), + host.aliases(), + host.flavor(), + Optional.of(host.membership().get().retire()), + host.version()); } private List<HostSpec> allocateHostGroup(ClusterSpec clusterGroup, String flavor, int nodesInGroup, int startIndex) { @@ -160,7 +164,7 @@ public class InMemoryProvisioner implements HostProvisioner { 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(), newHost.flavor(), Optional.of(membership))); + allocation.add(new HostSpec(newHost.hostname(), newHost.aliases(), newHost.flavor(), Optional.of(membership), newHost.version())); } nextIndexInCluster.put(new Pair<>(clusterGroup.type(), clusterGroup.id()), nextIndex); 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 99c079739b4..0af11fdb941 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 @@ -14,7 +14,6 @@ import java.util.List; * application if one exists. * * @author hmusum - * @since 5.11 */ public class SingleNodeProvisioner implements HostProvisioner { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/HostResource.java b/config-model/src/main/java/com/yahoo/vespa/model/HostResource.java index 0f7c040bf02..5c5bbba301f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/HostResource.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/HostResource.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model; +import com.yahoo.component.Version; import com.yahoo.config.model.api.HostInfo; import com.yahoo.config.provision.ClusterMembership; import com.yahoo.config.provision.Flavor; @@ -44,13 +45,21 @@ public class HostResource implements Comparable<HostResource> { // Empty for self-hosted Vespa. private Optional<Flavor> flavor = Optional.empty(); + /** The current Vespa version running on this node, or empty if not known */ + private final Optional<Version> version; + /** * Create a new {@link HostResource} bound to a specific {@link com.yahoo.vespa.model.Host}. * * @param host {@link com.yahoo.vespa.model.Host} object to bind to. */ public HostResource(Host host) { + this(host, Optional.empty()); + } + + public HostResource(Host host, Optional<Version> version) { this.host = host; + this.version = version; } /** @@ -59,6 +68,9 @@ public class HostResource implements Comparable<HostResource> { */ public Host getHost() { return host; } + /** Returns the current Vespa version running on this node, or null if not known */ + public Optional<Version> version() { return version; } + /** * Returns the baseport of the first available port range of length numPorts, * or 0 if there is no range of that length available. 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 6ef6c208c0a..5f55755c5a4 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 @@ -111,7 +111,7 @@ public class HostSystem extends AbstractConfigProducer<Host> { private HostResource addNewHost(HostSpec hostSpec) { Host host = new Host(this, hostSpec.hostname()); - HostResource hostResource = new HostResource(host); + HostResource hostResource = new HostResource(host, hostSpec.version()); hostResource.setFlavor(hostSpec.flavor()); hostSpec.membership().ifPresent(hostResource::addClusterMembership); hostname2host.put(host.getHostname(), hostResource); @@ -162,7 +162,7 @@ public class HostSystem extends AbstractConfigProducer<Host> { Set<HostSpec> getHostSpecs() { return getHosts().stream() .map(host -> new HostSpec(host.getHostname(), Collections.emptyList(), - host.getFlavor(), host.primaryClusterMembership())) + host.getFlavor(), host.primaryClusterMembership(), host.version())) .collect(Collectors.toCollection(LinkedHashSet::new)); } diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java b/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java index 13efc2b3337..cc343821e0b 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/AllocatedHosts.java @@ -29,8 +29,13 @@ public class AllocatedHosts { private static final String hostSpecHostName = "hostName"; private static final String hostSpecMembership = "membership"; private static final String hostSpecFlavor = "flavor"; + + /** Wanted version */ private static final String hostSpecVespaVersion = "vespaVersion"; + /** Current version */ + private static final String hostSpecCurrentVespaVersion = "currentVespaVersion"; + private final ImmutableSet<HostSpec> hosts; AllocatedHosts(Set<HostSpec> hosts) { @@ -49,12 +54,12 @@ public class AllocatedHosts { private void toSlime(HostSpec host, Cursor cursor) { cursor.setString(hostSpecHostName, host.hostname()); - if (host.membership().isPresent()) { - cursor.setString(hostSpecMembership, host.membership().get().stringValue()); - cursor.setString(hostSpecVespaVersion, host.membership().get().cluster().vespaVersion().toString()); - } - if (host.flavor().isPresent()) - cursor.setString(hostSpecFlavor, host.flavor().get().name()); + host.membership().ifPresent(membership -> { + cursor.setString(hostSpecMembership, membership.stringValue()); + cursor.setString(hostSpecVespaVersion, membership.cluster().vespaVersion().toString()); + }); + host.flavor().ifPresent(flavor -> cursor.setString(hostSpecFlavor, flavor.name())); + host.version().ifPresent(version -> cursor.setString(hostSpecCurrentVespaVersion, version.toString())); } /** Returns the hosts of this allocation */ @@ -66,19 +71,21 @@ public class AllocatedHosts { array.traverse(new ArrayTraverser() { @Override public void entry(int i, Inspector inspector) { - hosts.add(hostsFromSlime(inspector.field(hostSpecKey), nodeFlavors)); + hosts.add(hostFromSlime(inspector.field(hostSpecKey), nodeFlavors)); } }); return new AllocatedHosts(hosts); } - static HostSpec hostsFromSlime(Inspector object, Optional<NodeFlavors> nodeFlavors) { + static HostSpec hostFromSlime(Inspector object, Optional<NodeFlavors> nodeFlavors) { Optional<ClusterMembership> membership = object.field(hostSpecMembership).valid() ? Optional.of(membershipFromSlime(object)) : Optional.empty(); Optional<Flavor> flavor = object.field(hostSpecFlavor).valid() ? flavorFromSlime(object, nodeFlavors) : Optional.empty(); + Optional<com.yahoo.component.Version> version = + optionalString(object.field(hostSpecCurrentVespaVersion)).map(com.yahoo.component.Version::new); - return new HostSpec(object.field(hostSpecHostName).asString(),Collections.emptyList(), flavor, membership); + return new HostSpec(object.field(hostSpecHostName).asString(), Collections.emptyList(), flavor, membership, version); } private static ClusterMembership membershipFromSlime(Inspector object) { @@ -91,6 +98,11 @@ public class AllocatedHosts { .orElse(Optional.empty()); } + private static Optional<String> optionalString(Inspector inspector) { + if ( ! inspector.valid()) return Optional.empty(); + return Optional.of(inspector.asString()); + } + public byte[] toJson() throws IOException { Slime slime = new Slime(); toSlime(slime.setObject()); diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java index a0df2547631..837e062e356 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java @@ -38,6 +38,7 @@ public final class ClusterSpec { /** Returns the cluster id */ public Id id() { return id; } + /** Returns the version of Vespa that we want this cluster to run */ public Version vespaVersion() { return vespaVersion; } /** Returns the group within the cluster this specifies, or empty to specify the whole cluster */ diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java index dd8bc311939..a6607092d8e 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/HostSpec.java @@ -27,14 +27,21 @@ public class HostSpec implements Comparable<HostSpec> { private final Optional<Flavor> flavor; + private final Optional<com.yahoo.component.Version> version; + public HostSpec(String hostname, Optional<ClusterMembership> membership) { this(hostname, new ArrayList<>(), Optional.empty(), membership); } + // TODO: Remove after May 2018 public HostSpec(String hostname, ClusterMembership membership, Flavor flavor) { this(hostname, new ArrayList<>(), Optional.of(flavor), Optional.of(membership)); } + public HostSpec(String hostname, ClusterMembership membership, Flavor flavor, Optional<com.yahoo.component.Version> version) { + this(hostname, new ArrayList<>(), Optional.of(flavor), Optional.of(membership), version); + } + public HostSpec(String hostname, List<String> aliases) { this(hostname, aliases, Optional.empty(), Optional.empty()); } @@ -44,11 +51,18 @@ public class HostSpec implements Comparable<HostSpec> { } public HostSpec(String hostname, List<String> aliases, Optional<Flavor> flavor, Optional<ClusterMembership> membership) { + this(hostname, aliases, flavor, membership, Optional.empty()); + } + + public HostSpec(String hostname, List<String> aliases, Optional<Flavor> flavor, + Optional<ClusterMembership> membership, Optional<com.yahoo.component.Version> version) { if (hostname == null || hostname.isEmpty()) throw new IllegalArgumentException("Hostname must be specified"); + Objects.requireNonNull(version, "Version cannot be null but can be empty"); this.hostname = hostname; this.aliases = ImmutableList.copyOf(aliases); this.flavor = flavor; this.membership = membership; + this.version = version; } /** Returns the name identifying this host */ @@ -59,6 +73,9 @@ public class HostSpec implements Comparable<HostSpec> { public Optional<Flavor> flavor() { return flavor; } + /** Returns the current version of Vespa running on this node, or empty if not known */ + public Optional<com.yahoo.component.Version> version() { return version; } + /** Returns the membership of this host, or an empty value if not present */ public Optional<ClusterMembership> membership() { return membership; } diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ProvisionInfo.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ProvisionInfo.java index 8444f2e10fc..ca8d531634b 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/ProvisionInfo.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ProvisionInfo.java @@ -39,7 +39,7 @@ public class ProvisionInfo extends AllocatedHosts { array.traverse(new ArrayTraverser() { @Override public void entry(int i, Inspector inspector) { - hosts.add(hostsFromSlime(inspector.field(hostSpecKey), nodeFlavors)); + hosts.add(hostFromSlime(inspector.field(hostSpecKey), nodeFlavors)); } }); return new ProvisionInfo(hosts); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java index 636ac7e7070..43be4e279f0 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/ApplicationRepository.java @@ -210,7 +210,7 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye } private Deployment deployFromPreparedSession(LocalSession session, Tenant tenant, Duration timeout) { - return Deployment.prepared(session, this, hostProvisioner, tenant,timeout, clock); + return Deployment.prepared(session, this, hostProvisioner, tenant, timeout, clock); } // ---------------- Application operations ---------------------------------------------------------------- diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java index 1301f24788f..08fd0a7afda 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java @@ -49,12 +49,12 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { private final ConfigDefinitionRepo configDefinitionRepo; private final Metrics metrics; private final Curator curator; - private final Zone zone; private final DeployLogger logger; public ActivatedModelsBuilder(TenantName tenant, long appGeneration, SessionZooKeeperClient zkClient, GlobalComponentRegistry globalComponentRegistry) { super(globalComponentRegistry.getModelFactoryRegistry(), - globalComponentRegistry.getHostProvisioner().isPresent()); + globalComponentRegistry.getHostProvisioner().isPresent(), + globalComponentRegistry.getZone()); this.tenant = tenant; this.appGeneration = appGeneration; this.zkClient = zkClient; @@ -63,7 +63,6 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { this.configDefinitionRepo = globalComponentRegistry.getConfigDefinitionRepo(); this.metrics = globalComponentRegistry.getMetrics(); this.curator = globalComponentRegistry.getCurator(); - this.zone = globalComponentRegistry.getZone(); this.logger = new SilentDeployLogger(); } @@ -109,7 +108,7 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { return createModelContextProperties( applicationId, configserverConfig, - zone, + zone(), new Rotations(curator, Tenants.getTenantPath(tenant)).readRotationsFromZooKeeper(applicationId)); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java index daff32198a3..04e0c9a2902 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java @@ -9,6 +9,7 @@ import com.yahoo.config.model.api.ModelFactory; import com.yahoo.config.provision.AllocatedHosts; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationLockException; +import com.yahoo.config.provision.Environment; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.OutOfCapacityException; import com.yahoo.config.provision.Rotation; @@ -49,11 +50,17 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { /** True if we are running in hosted mode */ private final boolean hosted; - protected ModelsBuilder(ModelFactoryRegistry modelFactoryRegistry, boolean hosted) { + private final Zone zone; + + protected ModelsBuilder(ModelFactoryRegistry modelFactoryRegistry, boolean hosted, Zone zone) { this.modelFactoryRegistry = modelFactoryRegistry; this.hosted = hosted; + this.zone = zone; } + /** Returns the zone this is running in */ + protected Zone zone() { return zone; } + /** * Builds all applicable model versions * @@ -137,6 +144,9 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { List<MODELRESULT> allApplicationVersions = new ArrayList<>(); allApplicationVersions.add(latestModelVersion); + if (zone().environment() == Environment.dev) + versions = keepThoseUsedOn(allocatedHosts.get(), versions); + // TODO: We use the allocated hosts from the newest version when building older model versions. // This is correct except for the case where an old model specifies a cluster which the new version // does not. In that case we really want to extend the set of allocated hosts to include those of that @@ -170,6 +180,17 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { return versionList.get(versionList.size() - 1); } + /** Returns the subset of the given versions which are in use on these hosts */ + private Set<Version> keepThoseUsedOn(AllocatedHosts hosts, Set<Version> versions) { + return versions.stream().filter(version -> mayBeUsedOn(hosts, version)).collect(Collectors.toSet()); + } + + private boolean mayBeUsedOn(AllocatedHosts hosts, Version version) { + com.yahoo.component.Version v = new com.yahoo.component.Version(version.toString()); + return hosts.getHosts().stream() + .anyMatch(host -> ! host.version().isPresent() || host.version().get().equals(v)); + } + protected abstract MODELRESULT buildModelVersion(ModelFactory modelFactory, ApplicationPackage applicationPackage, ApplicationId applicationId, com.yahoo.component.Version wantedNodeVespaVersion, diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java index c265e0f6c2e..d7b84d75b5c 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java @@ -62,7 +62,7 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P PrepareParams params, Optional<ApplicationSet> currentActiveApplicationSet, ModelContext.Properties properties) { - super(modelFactoryRegistry, properties.hostedVespa()); + super(modelFactoryRegistry, properties.hostedVespa(), properties.zone()); this.permanentApplicationPackage = permanentApplicationPackage; this.configDefinitionRepo = configDefinitionRepo; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactory.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactory.java index 3c05d491b35..172620a643a 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactory.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactory.java @@ -10,9 +10,9 @@ import java.io.File; * A session factory responsible for creating deploy sessions. * * @author lulf - * @since 5.1 */ public interface SessionFactory { + /** * Creates a new deployment session from an application package. * @@ -34,4 +34,5 @@ public interface SessionFactory { * @return a new session */ LocalSession createSessionFromExisting(LocalSession existingSession, DeployLogger logger, TimeoutBudget timeoutBudget); + } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java index fdc681b5fb6..9bbaf35bce9 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionFactoryImpl.java @@ -33,8 +33,7 @@ import java.util.logging.Logger; * Serves as the factory of sessions. Takes care of copying files to the correct folder and initializing the * session state. * - * @author lulf - * @since 5.1 + * @author Ulf Lilleengen */ public class SessionFactoryImpl implements SessionFactory, LocalSessionLoader { diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java index f7d6b8f05fe..de903b7f2dd 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java @@ -210,6 +210,7 @@ public class SessionZooKeeperClient { /** * Create necessary paths atomically for a new session. + * * @param createTime Time of session creation. * @param timeUnit Time unit of createTime. */ diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/TestComponentRegistry.java b/configserver/src/test/java/com/yahoo/vespa/config/server/TestComponentRegistry.java index 3b56b5b35bf..d026989a43e 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/TestComponentRegistry.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/TestComponentRegistry.java @@ -30,8 +30,7 @@ import java.util.Optional; import static com.yahoo.vespa.config.server.SuperModelRequestHandlerTest.emptyNodeFlavors; /** - * @author lulf - * @since 5.1 + * @author Ulf Lilleengen */ public class TestComponentRegistry implements GlobalComponentRegistry { @@ -50,6 +49,7 @@ public class TestComponentRegistry implements GlobalComponentRegistry { private final FileDistributionFactory fileDistributionFactory; private final ModelFactoryRegistry modelFactoryRegistry; private final Optional<Provisioner> hostProvisioner; + private final Zone zone; private final Clock clock; private TestComponentRegistry(Curator curator, ConfigCurator configCurator, Metrics metrics, @@ -65,6 +65,7 @@ public class TestComponentRegistry implements GlobalComponentRegistry { ConfigDefinitionRepo defRepo, ReloadListener reloadListener, TenantListener tenantListener, + Zone zone, Clock clock) { this.curator = curator; this.configCurator = configCurator; @@ -81,6 +82,7 @@ public class TestComponentRegistry implements GlobalComponentRegistry { this.modelFactoryRegistry = modelFactoryRegistry; this.hostProvisioner = hostProvisioner; this.sessionPreparer = sessionPreparer; + this.zone = zone; this.clock = clock; } @@ -101,6 +103,7 @@ public class TestComponentRegistry implements GlobalComponentRegistry { private Optional<FileDistributionFactory> fileDistributionFactory = Optional.empty(); private ModelFactoryRegistry modelFactoryRegistry = new ModelFactoryRegistry(Collections.singletonList(new VespaModelFactory(new NullConfigModelRegistry()))); private Optional<Provisioner> hostProvisioner = Optional.empty(); + private Zone zone = Zone.defaultZone(); private Clock clock = Clock.systemUTC(); public Builder configServerConfig(ConfigserverConfig configserverConfig) { @@ -138,6 +141,11 @@ public class TestComponentRegistry implements GlobalComponentRegistry { return this; } + public Builder zone(Zone zone) { + this.zone = zone; + return this; + } + public Builder clock(Clock clock) { this.clock = clock; return this; @@ -154,7 +162,7 @@ public class TestComponentRegistry implements GlobalComponentRegistry { SessionPreparer sessionPreparer = new SessionPreparer(modelFactoryRegistry, fileDistributionFactory, hostProvisionerProvider, permApp, configserverConfig, defRepo, curator, - new Zone(configserverConfig, emptyNodeFlavors())); + zone); return new TestComponentRegistry(curator, configCurator.orElse(ConfigCurator.create(curator)), metrics, modelFactoryRegistry, permApp, @@ -163,7 +171,7 @@ public class TestComponentRegistry implements GlobalComponentRegistry { new ConfigServerDB(configserverConfig), hostRegistries, configserverConfig, sessionPreparer, hostProvisioner, defRepo, reloadListener, - tenantListener, clock); + tenantListener, zone, clock); } } @@ -193,19 +201,17 @@ public class TestComponentRegistry implements GlobalComponentRegistry { public HostRegistries getHostRegistries() { return hostRegistries;} @Override public ModelFactoryRegistry getModelFactoryRegistry() { return modelFactoryRegistry; } - @Override public Optional<Provisioner> getHostProvisioner() { return hostProvisioner; } - @Override public Zone getZone() { - return Zone.defaultZone(); + return zone; } + @Override + public Clock getClock() { return clock;} public FileDistributionFactory getFileDistributionFactory() { return fileDistributionFactory; } - @Override - public Clock getClock() { return clock;} } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java index 95cfd17139d..2a57d85f3f7 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java @@ -25,6 +25,7 @@ import com.yahoo.config.provision.ProvisionLogger; import com.yahoo.config.provision.Provisioner; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Version; +import com.yahoo.config.provision.Zone; import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.config.server.ApplicationRepository; import com.yahoo.vespa.config.server.TestComponentRegistry; @@ -91,9 +92,18 @@ public class DeployTester { } public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock) { + this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone()); + } + + public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone) { + this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone(), createProvisioner()); + } + + public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone, HostProvisioner provisioner) { this.clock = clock; TestComponentRegistry componentRegistry = createComponentRegistry(new MockCurator(), Metrics.createTestMetrics(), - modelFactories, configserverConfig, clock); + modelFactories, configserverConfig, clock, zone, + provisioner); try { this.testApp = new File(appPath); this.tenants = new Tenants(componentRegistry, Collections.emptySet()); @@ -102,7 +112,7 @@ public class DeployTester { catch (Exception e) { throw new IllegalArgumentException(e); } - applicationRepository = new ApplicationRepository(tenants, createHostProvisioner(), clock); + applicationRepository = new ApplicationRepository(tenants, new ProvisionerAdapter(provisioner), clock); } public Tenant tenant() { @@ -110,13 +120,13 @@ public class DeployTester { } /** Create a model factory for the version of this source*/ - public static ModelFactory createModelFactory(Clock clock) { - return new VespaModelFactory(new NullConfigModelRegistry(), clock); + public static CountingModelFactory createModelFactory(Clock clock) { + return new CountingModelFactory(clock); } /** Create a model factory for a particular version */ - public static ModelFactory createModelFactory(Version version, Clock clock) { - return new VespaModelFactory(version, new NullConfigModelRegistry(), clock); + public static CountingModelFactory createModelFactory(Version version, Clock clock) { + return new CountingModelFactory(version, clock); } /** Create a model factory which always fails validation */ @@ -168,24 +178,26 @@ public class DeployTester { return applicationRepository; } - private Provisioner createHostProvisioner() { - return new ProvisionerAdapter(new InMemoryProvisioner(true, "host0", "host1", "host2", "host3", "host4", "host5")); + private static HostProvisioner createProvisioner() { + return new InMemoryProvisioner(true, "host0", "host1", "host2", "host3", "host4", "host5"); } private TestComponentRegistry createComponentRegistry(Curator curator, Metrics metrics, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, - Clock clock) { + Clock clock, + Zone zone, + HostProvisioner provisioner) { TestComponentRegistry.Builder builder = new TestComponentRegistry.Builder(); - if (configserverConfig.hostedVespa()) { - builder.provisioner(createHostProvisioner()); - } + if (configserverConfig.hostedVespa()) + builder.provisioner(new ProvisionerAdapter(provisioner)); builder.configServerConfig(configserverConfig) .curator(curator) .modelFactoryRegistry(new ModelFactoryRegistry(modelFactories)) .metrics(metrics) + .zone(zone) .clock(clock); return builder.build(); } @@ -252,4 +264,40 @@ public class DeployTester { } + /** A wrapper of the regular model factory which counts the number of models it has created */ + public static class CountingModelFactory implements ModelFactory { + + private final VespaModelFactory wrapped; + private int creationCount; + + public CountingModelFactory(Clock clock) { + this.wrapped = new VespaModelFactory(new NullConfigModelRegistry(), clock); + } + + public CountingModelFactory(Version version, Clock clock) { + this.wrapped = new VespaModelFactory(version, new NullConfigModelRegistry(), clock); + } + + /** Returns the number of models created successfully by this instance */ + public int creationCount() { return creationCount; } + + @Override + public Version getVersion() { return wrapped.getVersion(); } + + @Override + public Model createModel(ModelContext modelContext) { + Model model = wrapped.createModel(modelContext); + creationCount++; + return model; + } + + @Override + public ModelCreateResult createAndValidateModel(ModelContext modelContext, boolean ignoreValidationErrors) { + ModelCreateResult result = wrapped.createAndValidateModel(modelContext, ignoreValidationErrors); + creationCount++; + return result; + } + + } + } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java index bd9c6476ad6..8271d6de452 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java @@ -4,14 +4,22 @@ package com.yahoo.vespa.config.server.deploy; import com.google.common.io.Files; import com.yahoo.cloud.config.ConfigserverConfig; import com.yahoo.config.model.api.ModelFactory; +import com.yahoo.config.model.provision.Host; +import com.yahoo.config.model.provision.Hosts; +import com.yahoo.config.model.provision.InMemoryProvisioner; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.Version; +import com.yahoo.config.provision.Zone; import com.yahoo.test.ManualClock; +import static com.yahoo.vespa.config.server.deploy.DeployTester.CountingModelFactory; import org.junit.Test; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -54,9 +62,47 @@ public class HostedDeployTest { modelFactories.add(DeployTester.createModelFactory(Version.fromString("6.1.0"), clock)); modelFactories.add(DeployTester.createModelFactory(Version.fromString("6.2.0"), clock)); modelFactories.add(DeployTester.createModelFactory(Version.fromString("7.0.0"), clock)); - DeployTester tester = new DeployTester("src/test/apps/hosted/", modelFactories, createConfigserverConfig()); + DeployTester tester = new DeployTester("src/test/apps/hosted/", modelFactories, createConfigserverConfig(), clock, Zone.defaultZone()); ApplicationId app = tester.deployApp("myApp", Instant.now()); assertEquals(3, tester.getAllocatedHostsOf(app).getHosts().size()); + + } + + /** Test that unused versions are skipped in dev */ + @Test + public void testDeployMultipleVersionsInDev() { + List<Host> hosts = new ArrayList<>(); + hosts.add(createHost("host1", "6.0.0")); + hosts.add(createHost("host2", "6.0.2")); + hosts.add(createHost("host3", "7.1.0")); + InMemoryProvisioner provisioner = new InMemoryProvisioner(new Hosts(hosts), true); + ManualClock clock = new ManualClock("2016-10-09T00:00:00"); + + CountingModelFactory factory600 = DeployTester.createModelFactory(Version.fromString("6.0.0"), clock); + CountingModelFactory factory610 = DeployTester.createModelFactory(Version.fromString("6.1.0"), clock); + CountingModelFactory factory620 = DeployTester.createModelFactory(Version.fromString("6.2.0"), clock); + CountingModelFactory factory700 = DeployTester.createModelFactory(Version.fromString("7.0.0"), clock); + CountingModelFactory factory710 = DeployTester.createModelFactory(Version.fromString("7.1.0"), clock); + CountingModelFactory factory720 = DeployTester.createModelFactory(Version.fromString("7.2.0"), clock); + List<ModelFactory> modelFactories = new ArrayList<>(); + modelFactories.add(factory600); + modelFactories.add(factory610); + modelFactories.add(factory620); + modelFactories.add(factory700); + modelFactories.add(factory710); + modelFactories.add(factory720); + + DeployTester tester = new DeployTester("src/test/apps/hosted/", modelFactories, createConfigserverConfig(), + clock, new Zone(Environment.dev, RegionName.defaultName()), provisioner); + ApplicationId app = tester.deployApp("myApp", Instant.now()); + assertEquals(3, tester.getAllocatedHostsOf(app).getHosts().size()); + + assertEquals(1, factory600.creationCount()); + assertEquals(0, factory610.creationCount()); + assertEquals(1, factory620.creationCount()); + assertEquals(0, factory700.creationCount()); + assertEquals(1, factory710.creationCount()); + assertEquals("Newest is always included", 1, factory720.creationCount()); } @Test @@ -107,4 +153,8 @@ public class HostedDeployTest { .multitenant(true)); } + private Host createHost(String hostname, String version) { + return new Host(hostname, Collections.emptyList(), Optional.empty(), Optional.of(com.yahoo.component.Version.fromString(version))); + } + } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java index 56ef3f340e2..f0c74d19af9 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackageTest.java @@ -34,7 +34,8 @@ public class ZKApplicationPackageTest extends TestWithCurator { private static final String TEST_FLAVOR_NAME = "test-flavor"; private static final Optional<Flavor> TEST_FLAVOR = new MockNodeFlavors().getFlavor(TEST_FLAVOR_NAME); private static final AllocatedHosts ALLOCATED_HOSTS = AllocatedHosts.withHosts( - Collections.singleton(new HostSpec("foo.yahoo.com", Collections.emptyList(), TEST_FLAVOR, Optional.empty()))); + Collections.singleton(new HostSpec("foo.yahoo.com", Collections.emptyList(), TEST_FLAVOR, Optional.empty(), + Optional.of(com.yahoo.component.Version.fromString("6.0.1"))))); @Rule public TemporaryFolder tmpDir = new TemporaryFolder(); @@ -67,6 +68,7 @@ public class ZKApplicationPackageTest extends TestWithCurator { AllocatedHosts readInfo = zkApp.getAllocatedHosts().get(); assertThat(Utf8.toString(readInfo.toJson()), is(Utf8.toString(ALLOCATED_HOSTS.toJson()))); assertThat(readInfo.getHosts().iterator().next().flavor(), is(TEST_FLAVOR)); + assertEquals("6.0.1", readInfo.getHosts().iterator().next().version().get().toString()); assertTrue(zkApp.getDeployment().isPresent()); assertThat(DeploymentSpec.fromXml(zkApp.getDeployment().get()).globalServiceId().get(), is("mydisc")); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java index 304c867a886..3fa70b3242f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java @@ -123,7 +123,8 @@ public class NodeRepositoryProvisioner implements Provisioner { log.log(LogLevel.DEBUG, () -> "Prepared node " + node.hostname() + " - " + node.flavor()); hosts.add(new HostSpec(node.hostname(), node.allocation().orElseThrow(IllegalStateException::new).membership(), - node.flavor())); + node.flavor(), + node.status().vespaVersion())); } return hosts; } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java index e00f058efaa..2ffe23cea07 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/provisioning/ProvisioningTest.java @@ -140,6 +140,31 @@ public class ProvisioningTest { } @Test + public void nodeVersionIsReturnedIfSet() { + ProvisioningTester tester = new ProvisioningTester(new Zone(Environment.dev, RegionName.from("us-east"))); + + ApplicationId application1 = tester.makeApplicationId(); + + tester.makeReadyNodes(4, "default"); + + // deploy + SystemState state1 = prepare(application1, 1, 1, 1, 1, "default", tester); + tester.activate(application1, state1.allHosts); + + HostSpec host1 = state1.container0.iterator().next(); + assertFalse(host1.version().isPresent()); + Node node1 = tester.nodeRepository().getNode(host1.hostname()).get(); + tester.nodeRepository().write(node1.with(node1.status().withVespaVersion(Version.fromString("1.2.3")))); + + // redeploy + SystemState state2 = prepare(application1, 1, 1, 1, 1, "default", tester); + tester.activate(application1, state2.allHosts); + + host1 = state2.container0.iterator().next(); + assertEquals(Version.fromString("1.2.3"), host1.version().get()); + } + + @Test public void application_deployment_variable_application_size() { ProvisioningTester tester = new ProvisioningTester(new Zone(Environment.prod, RegionName.from("us-east"))); |