diff options
author | gjoranv <gjoranv@gmail.com> | 2018-07-04 11:51:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-04 11:51:50 +0200 |
commit | ec7dedf2f618b2e3aeb8019877565c1bfbec6047 (patch) | |
tree | a9b54e3272b192663609bb9852d19734aa01a0e2 /configserver | |
parent | 2e2028e2374a83ad6bbac01b0f95e0c64dde567a (diff) | |
parent | 6c8f72662bd0c026453bca8626473dc303c3cfe8 (diff) |
Merge pull request #6327 from vespa-engine/hmusum/fix-access-control-validator
Fix AccessControlValidator not working when loading minimal set of config model versions
Diffstat (limited to 'configserver')
10 files changed, 121 insertions, 51 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index 28dc0cc8414..914d6963ff0 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -124,6 +124,7 @@ public class ModelContextImpl implements ModelContext { private final Zone zone; private final Set<Rotation> rotations; private final boolean isBootstrap; + private final boolean isFirstTimeDeployment; public Properties(ApplicationId applicationId, boolean multitenant, @@ -134,7 +135,8 @@ public class ModelContextImpl implements ModelContext { boolean hostedVespa, Zone zone, Set<Rotation> rotations, - boolean isBootstrap) { + boolean isBootstrap, + boolean isFirstTimeDeployment) { this.applicationId = applicationId; this.multitenant = multitenant; this.configServerSpecs = configServerSpecs; @@ -145,6 +147,7 @@ public class ModelContextImpl implements ModelContext { this.zone = zone; this.rotations = rotations; this.isBootstrap = isBootstrap; + this.isFirstTimeDeployment = isFirstTimeDeployment; } @Override @@ -181,6 +184,8 @@ public class ModelContextImpl implements ModelContext { @Override public boolean isBootstrap() { return isBootstrap; } + @Override + public boolean isFirstTimeDeployment() { return isFirstTimeDeployment; } } } 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 314b6d78ae3..2955d948d69 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 @@ -116,7 +116,8 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { configserverConfig.hostedVespa(), zone(), new Rotations(curator, TenantRepository.getTenantPath(tenant)).readRotationsFromZooKeeper(applicationId), - false); // We may be bootstrapping, but we only know and care during prepare + false, // We may be bootstrapping, but we only know and care during prepare + false); // Always false, assume no one uses it when activating } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java index 0d9f8ce64b1..6a240806004 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java @@ -158,7 +158,8 @@ public class SessionPreparer { configserverConfig.hostedVespa(), zone, rotationsSet, - params.isBootstrap()); + params.isBootstrap(), + ! currentActiveApplicationSet.isPresent()); this.preparedModelsBuilder = new PreparedModelsBuilder(modelFactoryRegistry, permanentApplicationPackage, configDefinitionRepo, diff --git a/configserver/src/test/apps/hosted-no-write-access-control/searchdefinitions/music.sd b/configserver/src/test/apps/hosted-no-write-access-control/searchdefinitions/music.sd new file mode 100644 index 00000000000..78d58b27d4a --- /dev/null +++ b/configserver/src/test/apps/hosted-no-write-access-control/searchdefinitions/music.sd @@ -0,0 +1,10 @@ +# Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +search music { + document music { + field title type string { + indexing: index | summary + # index-to: default + } + } +} + diff --git a/configserver/src/test/apps/hosted-no-write-access-control/services.xml b/configserver/src/test/apps/hosted-no-write-access-control/services.xml new file mode 100644 index 00000000000..c2257ab34f7 --- /dev/null +++ b/configserver/src/test/apps/hosted-no-write-access-control/services.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!-- Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> +<services version="1.0"> + + <admin version="3.0"> + <nodes count='1'/> + </admin> + + <jdisc version="1.0"> + <http> + <server id="foo" port="4080" /> + </http> + <search/> + <nodes count='1'/> + </jdisc> + + <content id="music" version="1.0"> + <redundancy>1</redundancy> + <documents> + <document type="music" mode="index" /> + </documents> + <nodes count="2" groups="2"/> + </content> + +</services> diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java index f9c99b323af..dbb02e367a7 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ConfigServerBootstrapTest.java @@ -2,10 +2,8 @@ package com.yahoo.vespa.config.server; import com.yahoo.cloud.config.ConfigserverConfig; -import com.yahoo.config.model.api.HostProvisioner; import com.yahoo.config.model.provision.InMemoryProvisioner; import com.yahoo.config.provision.ClusterSpec; -import com.yahoo.config.provision.Version; import com.yahoo.container.handler.VipStatus; import com.yahoo.container.jdisc.config.HealthMonitorConfig; import com.yahoo.container.jdisc.state.StateMonitor; @@ -41,8 +39,8 @@ public class ConfigServerBootstrapTest { public void testBootstrap() throws Exception { ConfigserverConfig configserverConfig = createConfigserverConfig(temporaryFolder); InMemoryProvisioner provisioner = new InMemoryProvisioner(true, "host0", "host1", "host3"); - DeployTester tester = new DeployTester("src/test/apps/hosted/", configserverConfig, provisioner); - tester.deployApp("myApp", "4.5.6", Instant.now()); + DeployTester tester = new DeployTester(configserverConfig, provisioner); + tester.deployApp("src/test/apps/hosted/", "myApp", "4.5.6", Instant.now()); File versionFile = temporaryFolder.newFile(); VersionState versionState = new VersionState(versionFile); @@ -72,8 +70,8 @@ public class ConfigServerBootstrapTest { @Test public void testBootstrapWhenRedeploymentFails() throws Exception { ConfigserverConfig configserverConfig = createConfigserverConfig(temporaryFolder); - DeployTester tester = new DeployTester("src/test/apps/hosted/", configserverConfig); - tester.deployApp("myApp", "4.5.6", Instant.now()); + DeployTester tester = new DeployTester(configserverConfig); + tester.deployApp("src/test/apps/hosted/", "myApp", "4.5.6", Instant.now()); File versionFile = temporaryFolder.newFile(); VersionState versionState = new VersionState(versionFile); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java index ce53dc3f2fb..28fc179770a 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java @@ -51,6 +51,7 @@ public class ModelContextImplTest { false, Zone.defaultZone(), rotations, + false, false), Optional.empty(), new Version(6), @@ -67,5 +68,6 @@ public class ModelContextImplTest { assertTrue(context.properties().zone() instanceof Zone); assertFalse(context.properties().hostedVespa()); assertThat(context.properties().rotations(), equalTo(rotations)); + assertThat(context.properties().isFirstTimeDeployment(), equalTo(false)); } } 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 b15356a172e..e92276dabde 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 @@ -62,58 +62,56 @@ public class DeployTester { private final Clock clock; private final TenantRepository tenantRepository; - private final File testApp; private final ApplicationRepository applicationRepository; private ApplicationId id; - public DeployTester(String appPath) { - this(appPath, Collections.singletonList(createModelFactory(Clock.systemUTC()))); + public DeployTester() { + this(Collections.singletonList(createModelFactory(Clock.systemUTC()))); } - public DeployTester(String appPath, List<ModelFactory> modelFactories) { - this(appPath, modelFactories, + public DeployTester(List<ModelFactory> modelFactories) { + this(modelFactories, new ConfigserverConfig(new ConfigserverConfig.Builder() .configServerDBDir(Files.createTempDir().getAbsolutePath()) .configDefinitionsDir(Files.createTempDir().getAbsolutePath())), Clock.systemUTC()); } - public DeployTester(String appPath, ConfigserverConfig configserverConfig) { - this(appPath, Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC()); + public DeployTester(ConfigserverConfig configserverConfig) { + this(Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC()); } - public DeployTester(String appPath, ConfigserverConfig configserverConfig, HostProvisioner provisioner) { - this(appPath, Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC(), provisioner); + public DeployTester(ConfigserverConfig configserverConfig, HostProvisioner provisioner) { + this(Collections.singletonList(createModelFactory(Clock.systemUTC())), configserverConfig, Clock.systemUTC(), provisioner); } - public DeployTester(String appPath, ConfigserverConfig configserverConfig, Clock clock) { - this(appPath, Collections.singletonList(createModelFactory(clock)), configserverConfig, clock); + public DeployTester(ConfigserverConfig configserverConfig, Clock clock) { + this(Collections.singletonList(createModelFactory(clock)), configserverConfig, clock); } - public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig) { - this(appPath, modelFactories, configserverConfig, Clock.systemUTC()); + public DeployTester(List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig) { + this(modelFactories, configserverConfig, Clock.systemUTC()); } - public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock) { - this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone()); + public DeployTester(List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock) { + this(modelFactories, configserverConfig, clock, Zone.defaultZone()); } - public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, HostProvisioner provisioner) { - this(appPath, modelFactories, configserverConfig, clock, Zone.defaultZone(), provisioner); + public DeployTester(List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, HostProvisioner provisioner) { + this(modelFactories, configserverConfig, clock, Zone.defaultZone(), provisioner); } - public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone) { - this(appPath, modelFactories, configserverConfig, clock, zone, createProvisioner()); + public DeployTester(List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone) { + this(modelFactories, configserverConfig, clock, zone, createProvisioner()); } - public DeployTester(String appPath, List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone, HostProvisioner provisioner) { + public DeployTester(List<ModelFactory> modelFactories, ConfigserverConfig configserverConfig, Clock clock, Zone zone, HostProvisioner provisioner) { this.clock = clock; TestComponentRegistry componentRegistry = createComponentRegistry(new MockCurator(), Metrics.createTestMetrics(), modelFactories, configserverConfig, clock, zone, provisioner); try { - this.testApp = new File(appPath); this.tenantRepository = new TenantRepository(componentRegistry); tenantRepository.addTenant(tenantName); } @@ -133,6 +131,11 @@ public class DeployTester { } /** Create a model factory for a particular version */ + public static CountingModelFactory createModelFactory(Version version) { + return new CountingModelFactory(version, Clock.systemUTC()); + } + + /** Create a model factory for a particular version */ public static CountingModelFactory createModelFactory(Version version, Clock clock) { return new CountingModelFactory(version, clock); } @@ -143,14 +146,14 @@ public class DeployTester { /** * Do the initial "deploy" with the existing API-less code as the deploy API doesn't support first deploys yet. */ - public ApplicationId deployApp(String appName, Instant now) { - return deployApp(appName, null, now); + public ApplicationId deployApp(String applicationPath, String appName, Instant now) { + return deployApp(applicationPath, appName, null, now); } /** * Do the initial "deploy" with the existing API-less code as the deploy API doesn't support first deploys yet. */ - public ApplicationId deployApp(String appName, String vespaVersion, Instant now) { + public ApplicationId deployApp(String applicationPath, String appName, String vespaVersion, Instant now) { Tenant tenant = tenant(); TimeoutBudget timeoutBudget = new TimeoutBudget(clock, Duration.ofSeconds(60)); ApplicationId id = ApplicationId.from(tenant.getName(), ApplicationName.from(appName), InstanceName.defaultName()); @@ -158,7 +161,7 @@ public class DeployTester { if (vespaVersion != null) paramsBuilder.vespaVersion(vespaVersion); - long sessionId = applicationRepository.createSession(id, timeoutBudget, testApp); + long sessionId = applicationRepository.createSession(id, timeoutBudget, new File(applicationPath)); applicationRepository.prepare(tenant, sessionId, paramsBuilder.build(), now); applicationRepository.activate(tenant, sessionId, timeoutBudget, false, false); this.id = id; 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 6ee4720b6b0..a184a461ce1 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 @@ -22,9 +22,12 @@ import java.time.Clock; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -39,8 +42,8 @@ public class HostedDeployTest { @Test public void testRedeployWithVersion() { CountingModelFactory modelFactory = DeployTester.createModelFactory(Version.fromString("4.5.6"), Clock.systemUTC()); - DeployTester tester = new DeployTester("src/test/apps/hosted/", Collections.singletonList(modelFactory), createConfigserverConfig()); - tester.deployApp("myApp", "4.5.6", Instant.now()); + DeployTester tester = new DeployTester(Collections.singletonList(modelFactory), createConfigserverConfig()); + tester.deployApp("src/test/apps/hosted/", "myApp", "4.5.6", Instant.now()); Optional<com.yahoo.config.provision.Deployment> deployment = tester.redeployFromLocalActive(); assertTrue(deployment.isPresent()); @@ -51,8 +54,8 @@ public class HostedDeployTest { @Test public void testRedeploy() { - DeployTester tester = new DeployTester("src/test/apps/hosted/", createConfigserverConfig()); - ApplicationId appId = tester.deployApp("myApp", Instant.now()); + DeployTester tester = new DeployTester(createConfigserverConfig()); + ApplicationId appId = tester.deployApp("src/test/apps/hosted/", "myApp", Instant.now()); LocalSession s1 = tester.applicationRepository().getActiveSession(appId); System.out.println("First session: " + s1.getSessionId()); assertFalse(tester.applicationRepository().getActiveSession(appId).getMetaData().isInternalRedeploy()); @@ -73,10 +76,9 @@ 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(), clock, Zone.defaultZone()); - ApplicationId app = tester.deployApp("myApp", "6.2.0", Instant.now()); + DeployTester tester = new DeployTester(modelFactories, createConfigserverConfig(), clock, Zone.defaultZone()); + ApplicationId app = tester.deployApp("src/test/apps/hosted/", "myApp", "6.2.0", Instant.now()); assertEquals(3, tester.getAllocatedHostsOf(app).getHosts().size()); - } /** Test that only the minimal set of models are created (model versions used on hosts, the wanted version and the latest version) */ @@ -103,10 +105,10 @@ public class HostedDeployTest { modelFactories.add(factory710); modelFactories.add(factory720); - DeployTester tester = new DeployTester("src/test/apps/hosted/", modelFactories, createConfigserverConfig(), + DeployTester tester = new DeployTester(modelFactories, createConfigserverConfig(), clock, new Zone(Environment.dev, RegionName.defaultName()), provisioner); // Deploy with version that does not exist on hosts, the model for this version should also be created - ApplicationId app = tester.deployApp("myApp", "7.0.0", Instant.now()); + ApplicationId app = tester.deployApp("src/test/apps/hosted/", "myApp", "7.0.0", Instant.now()); assertEquals(3, tester.getAllocatedHostsOf(app).getHosts().size()); // Check >0 not ==0 as the session watcher thread is running and will redeploy models in the background @@ -119,14 +121,37 @@ public class HostedDeployTest { } @Test + public void testAccessControlIsOnlyCheckedWhenNoProdDeploymentExists() { + // Provisioner does not reuse hosts, so need twice as many hosts as app requires + List<Host> hosts = IntStream.rangeClosed(1,6).mapToObj(i -> createHost("host" + i, "6.0.0")).collect(Collectors.toList()); + InMemoryProvisioner provisioner = new InMemoryProvisioner(new Hosts(hosts), true); + + CountingModelFactory factory600 = DeployTester.createModelFactory(Version.fromString("6.0.0")); + CountingModelFactory factory610 = DeployTester.createModelFactory(Version.fromString("6.1.0")); + CountingModelFactory factory620 = DeployTester.createModelFactory(Version.fromString("6.2.0")); + List<ModelFactory> modelFactories = Arrays.asList(factory600, factory610, factory620); + + DeployTester tester = new DeployTester(modelFactories, createConfigserverConfig(), + Clock.systemUTC(), new Zone(Environment.prod, RegionName.defaultName()), provisioner); + // Deploy with oldest version + ApplicationId app = tester.deployApp("src/test/apps/hosted/", "myApp", "6.0.0", Instant.now()); + assertEquals(3, tester.getAllocatedHostsOf(app).getHosts().size()); + + // Deploy with version that does not exist on hosts and with app package that has no write access control, + // validation of access control should not be done, since the app is already deployed in prod + app = tester.deployApp("src/test/apps/hosted-no-write-access-control", "myApp", "6.1.0", Instant.now()); + assertEquals(3, tester.getAllocatedHostsOf(app).getHosts().size()); + } + + @Test public void testRedeployAfterExpiredValidationOverride() { // Old version of model fails, but application disables loading old models until 2016-10-10, so deployment works ManualClock clock = new ManualClock("2016-10-09T00:00:00"); List<ModelFactory> modelFactories = new ArrayList<>(); modelFactories.add(DeployTester.createModelFactory(clock)); modelFactories.add(DeployTester.createFailingModelFactory(Version.fromIntValues(1, 0, 0))); // older than default - DeployTester tester = new DeployTester("src/test/apps/validationOverride/", modelFactories, createConfigserverConfig()); - tester.deployApp("myApp", clock.instant()); + DeployTester tester = new DeployTester(modelFactories, createConfigserverConfig()); + tester.deployApp("src/test/apps/validationOverride/", "myApp", clock.instant()); // Redeployment from local active works { @@ -149,7 +174,7 @@ public class HostedDeployTest { // However, redeployment from the outside fails after this date { try { - tester.deployApp("myApp", Instant.now()); + tester.deployApp("src/test/apps/validationOverride/", "myApp", Instant.now()); fail("Expected redeployment to fail"); } catch (Exception expected) { diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/RedeployTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/RedeployTest.java index fd023a19617..9bc9a93e9fa 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/RedeployTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/RedeployTest.java @@ -34,8 +34,8 @@ public class RedeployTest { @Test public void testRedeploy() { - DeployTester tester = new DeployTester("src/test/apps/app"); - tester.deployApp("myapp", Instant.now()); + DeployTester tester = new DeployTester(); + tester.deployApp("src/test/apps/app", "myapp", Instant.now()); Optional<com.yahoo.config.provision.Deployment> deployment = tester.redeployFromLocalActive(); assertTrue(deployment.isPresent()); @@ -54,7 +54,7 @@ public class RedeployTest { List<ModelFactory> modelFactories = new ArrayList<>(); modelFactories.add(DeployTester.createModelFactory(Clock.systemUTC())); modelFactories.add(DeployTester.createFailingModelFactory(Version.fromIntValues(1, 0, 0))); - DeployTester tester = new DeployTester("ignored/app/path", modelFactories); + DeployTester tester = new DeployTester(modelFactories); ApplicationId id = ApplicationId.from(tester.tenant().getName(), ApplicationName.from("default"), InstanceName.from("default")); @@ -70,8 +70,8 @@ public class RedeployTest { .configDefinitionsDir(Files.createTempDir() .getAbsolutePath()) .sessionLifetime(60)); - DeployTester tester = new DeployTester("src/test/apps/app", configserverConfig, clock); - tester.deployApp("myapp", Instant.now()); // session 2 (numbering starts at 2) + DeployTester tester = new DeployTester(configserverConfig, clock); + tester.deployApp("src/test/apps/app", "myapp", Instant.now()); // session 2 (numbering starts at 2) clock.advance(Duration.ofSeconds(10)); Optional<com.yahoo.config.provision.Deployment> deployment2 = tester.redeployFromLocalActive(); |