diff options
author | Harald Musum <musum@yahooinc.com> | 2022-04-27 09:44:54 +0200 |
---|---|---|
committer | Harald Musum <musum@yahooinc.com> | 2022-04-27 09:44:54 +0200 |
commit | 90402e33fe73f74e38f77d6a1ddc5b892aaf03f2 (patch) | |
tree | ae9ff8d0fc6568ec1eaa34c667077e860dcffdc0 /configserver | |
parent | e45cd30a0cf9e99be02af029dbb5c8517ba8ce4b (diff) |
Validate file extension for files in application package
Start validating file extension for files application package subdirectories,
only a subset of subdirectories handled for now
Diffstat (limited to 'configserver')
3 files changed, 34 insertions, 25 deletions
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 32422889b48..e4b1bf8ae58 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 @@ -360,9 +360,9 @@ public class ApplicationRepository implements com.yahoo.config.provision.Deploye return deploy(applicationPackage, prepareParams, DeployHandlerLogger.forPrepareParams(prepareParams)); } - private PrepareResult deploy(File applicationPackage, PrepareParams prepareParams, DeployHandlerLogger logger) { + private PrepareResult deploy(File applicationDir, PrepareParams prepareParams, DeployHandlerLogger logger) { ApplicationId applicationId = prepareParams.getApplicationId(); - long sessionId = createSession(applicationId, prepareParams.getTimeoutBudget(), applicationPackage); + long sessionId = createSession(applicationId, prepareParams.getTimeoutBudget(), applicationDir); Deployment deployment = prepare(sessionId, prepareParams, logger); if ( ! prepareParams.isDryRun()) diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java index d292e1c2c0e..120a75bdd72 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java @@ -43,7 +43,9 @@ import com.yahoo.vespa.config.server.zookeeper.SessionCounter; import com.yahoo.vespa.config.server.zookeeper.ZKApplication; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.defaults.Defaults; +import com.yahoo.vespa.flags.BooleanFlag; import com.yahoo.vespa.flags.FlagSource; +import com.yahoo.vespa.flags.Flags; import com.yahoo.yolean.Exceptions; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.recipes.cache.ChildData; @@ -127,6 +129,7 @@ public class SessionRepository { private final ModelFactoryRegistry modelFactoryRegistry; private final ConfigDefinitionRepo configDefinitionRepo; private final int maxNodeSize; + private final BooleanFlag failDeploymentForFilesWithUnknownExtension; public SessionRepository(TenantName tenantName, TenantApplications applicationRepo, @@ -170,6 +173,7 @@ public class SessionRepository { this.modelFactoryRegistry = modelFactoryRegistry; this.configDefinitionRepo = configDefinitionRepo; this.maxNodeSize = maxNodeSize; + this.failDeploymentForFilesWithUnknownExtension = Flags.FAIL_DEPLOYMENT_FOR_FILES_WITH_UNKNOWN_EXTENSION.bindTo(flagSource); loadSessions(); // Needs to be done before creating cache below this.directoryCache = curator.createDirectoryCache(sessionsPath.getAbsolute(), false, false, zkCacheExecutor); @@ -673,17 +677,19 @@ public class SessionRepository { } DeployData deployData = new DeployData(user, userDir.getAbsolutePath(), applicationId, deployTimestamp, internalRedeploy, sessionId, currentlyActiveSessionId.orElse(nonExistingActiveSessionId)); - return FilesApplicationPackage.fromFileWithDeployData(configApplicationDir, deployData); + FilesApplicationPackage app = FilesApplicationPackage.fromFileWithDeployData(configApplicationDir, deployData); + app.validateFileExtensions(failDeploymentForFilesWithUnknownExtension.value()); + return app; } - private LocalSession createSessionFromApplication(File applicationFile, + private LocalSession createSessionFromApplication(File applicationDirectory, ApplicationId applicationId, boolean internalRedeploy, TimeoutBudget timeoutBudget) { long sessionId = getNextSessionId(); try { ensureSessionPathDoesNotExist(sessionId); - ApplicationPackage app = createApplicationPackage(applicationFile, applicationId, sessionId, internalRedeploy); + ApplicationPackage app = createApplicationPackage(applicationDirectory, applicationId, sessionId, internalRedeploy); log.log(Level.FINE, () -> TenantRepository.logPre(tenantName) + "Creating session " + sessionId + " in ZooKeeper"); SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId); sessionZKClient.createNewSession(clock.instant()); @@ -697,7 +703,7 @@ public class SessionRepository { } } - private ApplicationPackage createApplicationPackage(File applicationFile, + private ApplicationPackage createApplicationPackage(File applicationDirectory, ApplicationId applicationId, long sessionId, boolean internalRedeploy) throws IOException { @@ -706,8 +712,8 @@ public class SessionRepository { synchronized (monitor) { Optional<Long> activeSessionId = getActiveSessionId(applicationId); File userApplicationDir = getSessionAppDir(sessionId); - copyApp(applicationFile, userApplicationDir); - ApplicationPackage applicationPackage = createApplication(applicationFile, + copyApp(applicationDirectory, userApplicationDir); + ApplicationPackage applicationPackage = createApplication(applicationDirectory, userApplicationDir, applicationId, sessionId, @@ -751,7 +757,7 @@ public class SessionRepository { log.log(Level.FINE, "Moving " + tempDestinationDir + " to " + destinationDir.getAbsolutePath()); Files.move(tempDestinationDir, destinationDir.toPath(), StandardCopyOption.ATOMIC_MOVE); } finally { - // In case some of the operations above fail + // In case some operations above fail if (tempDestinationDir != null) IOUtils.recursiveDeleteDir(tempDestinationDir.toFile()); } @@ -812,7 +818,7 @@ public class SessionRepository { sessionDir = fileDirectory.getFile(fileReference); } catch (IllegalArgumentException e) { // We cannot be guaranteed that the file reference exists (it could be that it has not - // been downloaded yet), and e.g when bootstrapping we cannot throw an exception in that case + // been downloaded yet), and e.g. when bootstrapping we cannot throw an exception in that case log.log(Level.FINE, () -> "File reference for session id " + sessionId + ": " + fileReference + " not found in " + fileDirectory); return; } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java index 9071b12507e..cb4b0e9d5bd 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/SessionPrepareHandlerTest.java @@ -29,7 +29,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; - import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -123,7 +122,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void require_that_activate_url_is_returned_on_success() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); HttpResponse response = request(HttpRequest.Method.PUT, sessionId); assertNotNull(response); assertEquals(OK, response.getStatus()); @@ -141,7 +140,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void require_verbose() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); HttpResponse response = createHandler().handle( createTestRequest(pathPrefix, HttpRequest.Method.PUT, Cmd.PREPARED, sessionId, "?verbose=true")); System.out.println(getRenderedString(response)); @@ -151,7 +150,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void require_get_response_activate_url_on_ok() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); request(HttpRequest.Method.PUT, sessionId); HttpResponse getResponse = request(HttpRequest.Method.GET, sessionId); assertResponseContains(getResponse, "\"activate\":\"http://foo:1337" + pathPrefix + @@ -160,7 +159,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void require_get_response_error_on_not_prepared() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); HttpResponse getResponse = request(HttpRequest.Method.GET, sessionId); assertHttpStatusCodeErrorCodeAndMessage(getResponse, BAD_REQUEST, @@ -186,7 +185,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void require_that_tenant_is_in_response() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); HttpResponse response = request(HttpRequest.Method.PUT, sessionId); assertNotNull(response); assertEquals(OK, response.getStatus()); @@ -200,7 +199,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { TenantName defaultTenant = TenantName.from("test2"); tenantRepository.addTenant(defaultTenant); ApplicationId applicationId1 = ApplicationId.from(defaultTenant, ApplicationName.from("app"), InstanceName.defaultName()); - long sessionId = applicationRepository.createSession(applicationId1, timeoutBudget, app); + long sessionId = createSession(applicationId1); pathPrefix = "/application/v2/tenant/" + defaultTenant + "/session/"; HttpResponse response = request(HttpRequest.Method.PUT, sessionId); @@ -209,7 +208,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { String applicationName = "myapp"; ApplicationId applicationId2 = ApplicationId.from(tenant.value(), applicationName, "default"); - long sessionId2 = applicationRepository.createSession(applicationId2, timeoutBudget, app); + long sessionId2 = createSession(applicationId2); assertEquals(sessionId, sessionId2); // Want to test when they are equal (but for different tenants) pathPrefix = "/application/v2/tenant/" + tenant + "/session/" + sessionId2 + @@ -219,7 +218,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { assertEquals(SessionHandlerTest.getRenderedString(response), OK, response.getStatus()); ApplicationId applicationId3 = ApplicationId.from(tenant.value(), applicationName, "quux"); - long sessionId3 = applicationRepository.createSession(applicationId3, timeoutBudget, app); + long sessionId3 = createSession(applicationId3); pathPrefix = "/application/v2/tenant/" + tenant + "/session/" + sessionId3 + "/prepared?applicationName=" + applicationName + "&instance=quux"; response = handler.handle(SessionHandlerTest.createTestRequest(pathPrefix)); @@ -229,14 +228,14 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void require_that_config_change_actions_are_in_response() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); HttpResponse response = request(HttpRequest.Method.PUT, sessionId); assertResponseContains(response, "\"configChangeActions\":{\"restart\":[],\"refeed\":[],\"reindex\":[]}"); } @Test public void require_that_config_change_actions_are_not_logged_if_not_existing() throws Exception { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); HttpResponse response = request(HttpRequest.Method.PUT, sessionId); assertResponseNotContains(response, "Change(s) between active and new application that may require restart"); assertResponseNotContains(response, "Change(s) between active and new application that may require re-feed"); @@ -245,7 +244,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void test_out_of_capacity_response() throws IOException { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); String exceptionMessage = "Node allocation failure"; FailingSessionPrepareHandler handler = new FailingSessionPrepareHandler(SessionPrepareHandler.testContext(), applicationRepository, @@ -260,7 +259,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void test_that_nullpointerexception_gives_internal_server_error() throws IOException { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); String exceptionMessage = "nullpointer thrown in test handler"; FailingSessionPrepareHandler handler = new FailingSessionPrepareHandler(SessionPrepareHandler.testContext(), applicationRepository, @@ -276,7 +275,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void test_application_lock_failure() throws IOException { String exceptionMessage = "Timed out after waiting PT1M to acquire lock '/provision/v1/locks/foo/bar/default'"; - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); FailingSessionPrepareHandler handler = new FailingSessionPrepareHandler(SessionPrepareHandler.testContext(), applicationRepository, configserverConfig, @@ -290,7 +289,7 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { @Test public void test_docker_image_repository() { - long sessionId = applicationRepository.createSession(applicationId(), timeoutBudget, app); + long sessionId = createSession(applicationId()); String dockerImageRepository = "foo.bar.com:4443/baz"; request(HttpRequest.Method.PUT, sessionId, Map.of("dockerImageRepository", dockerImageRepository, "applicationName", applicationId().application().value())); @@ -329,6 +328,10 @@ public class SessionPrepareHandlerTest extends SessionHandlerTest { return ApplicationId.from(tenant.value(), "app", "default"); } + private long createSession(ApplicationId applicationId) { + return applicationRepository.createSession(applicationId, timeoutBudget, app); + } + private static class FailingSessionPrepareHandler extends SessionPrepareHandler { private final RuntimeException exceptionToBeThrown; |