diff --git a/src/main/java/emissary/admin/Startup.java b/src/main/java/emissary/admin/Startup.java index 0e79dcc2f2..73ce8abdd8 100755 --- a/src/main/java/emissary/admin/Startup.java +++ b/src/main/java/emissary/admin/Startup.java @@ -60,7 +60,7 @@ public class Startup { protected final Set failedPlaces = ConcurrentHashMap.newKeySet(); // Collection of the places as they finish coming up - protected final Map places = new ConcurrentHashMap<>(); + protected static final Map places = new ConcurrentHashMap<>(); // Collection of places that are being started protected final Set placesToStart = ConcurrentHashMap.newKeySet(); @@ -70,8 +70,11 @@ public class Startup { protected final Map> pickupLists = new ConcurrentHashMap<>(); // sets to keep track of possible invisible place startup - protected Set activeDirPlaces = new LinkedHashSet<>(); - protected Set placeAlreadyStarted = new LinkedHashSet<>(); + protected static Set activeDirPlaces = new LinkedHashSet<>(); + protected static Set placeAlreadyStarted = new LinkedHashSet<>(); + + // invisible place startups occurred in strict mode + protected static boolean invisPlacesStartedInStrictMode = false; /** * n return the full DNS name and port without the protocol part @@ -169,8 +172,8 @@ public void start() throws EmissaryException { // the pickup places here. startPickUpPlaces(); - if (!verifyNoInvisiblePlacesStarted()) { - // TODO: If invisible places are started, shutdown the EmissaryServer + if (!verifyNoInvisiblePlacesStarted() && node.isStrictStartupMode()) { + invisPlacesStartedInStrictMode = true; } } @@ -245,7 +248,7 @@ void startMapOfPlaces(final Map> m) { if (hashListSize(m) > 0) { for (final List placeList : m.values()) { - final boolean status = placeSetup(directoryAction, this.localDirectories, this.places, placeList); + final boolean status = placeSetup(directoryAction, this.localDirectories, places, placeList); if (!status) { logger.warn("Startup: places setup failed!"); @@ -419,7 +422,7 @@ protected void stopAndWaitForPlaceCreation() { numPlacesExpected = this.placesToStart.size(); } - numPlacesFound = this.places.size(); + numPlacesFound = places.size(); if (numPlacesFound >= numPlacesExpected) { @@ -512,7 +515,7 @@ private void sortPickupOrPlace(String theLocation, Map> pla * * @return true if no invisible places started, false if yes */ - public boolean verifyNoInvisiblePlacesStarted() { + public static boolean verifyNoInvisiblePlacesStarted() { try { IDirectoryPlace dirPlace = DirectoryPlace.lookup(); List dirEntries = dirPlace.getEntries(); @@ -551,4 +554,14 @@ public boolean verifyNoInvisiblePlacesStarted() { return true; } + + // get invisibly started places + public static Set getInvisPlaces() { + return activeDirPlaces; + } + + // get if invisible places are started while in strict mode + public static boolean isInvisPlacesStartedInStrictMode() { + return invisPlacesStartedInStrictMode; + } } diff --git a/src/main/java/emissary/server/EmissaryServer.java b/src/main/java/emissary/server/EmissaryServer.java index 26b47efb29..16e9c697d8 100644 --- a/src/main/java/emissary/server/EmissaryServer.java +++ b/src/main/java/emissary/server/EmissaryServer.java @@ -1,5 +1,6 @@ package emissary.server; +import emissary.admin.Startup; import emissary.client.EmissaryClient; import emissary.client.EmissaryResponse; import emissary.client.HTTPConnectionFactory; @@ -194,6 +195,13 @@ public Server startServer() { } LOG.info("Started EmissaryServer at {}", serverLocation); + + // check if invisible place start-ups occurred on strict server start-up, and shut down server if so. + if (Startup.isInvisPlacesStartedInStrictMode() && this.server.isStarted()) { + EmissaryServer.stopServer(true); + LOG.info("Server shut down due to invisible place startups on strict-mode: {}", Startup.getInvisPlaces()); + } + return configuredServer; } catch (Throwable t) { String errorMsg = "Emissary server didn't start"; diff --git a/src/test/java/emissary/admin/StartupTest.java b/src/test/java/emissary/admin/StartupTest.java index 08bb9be47c..f5e0b7edcb 100644 --- a/src/test/java/emissary/admin/StartupTest.java +++ b/src/test/java/emissary/admin/StartupTest.java @@ -60,39 +60,34 @@ void testSortPlaces() throws IOException { void testInvisPlaceStart() throws IOException { // setup node, startup, and DirectoryPlace EmissaryNode node = new EmissaryNode(); - Startup startup = new Startup(node.getNodeConfigurator(), node); String location = "http://" + node.getNodeName() + ":" + node.getNodePort(); dirStartUp(); // test if place is already started before startup - startup.activeDirPlaces.add(location + "/PlaceAlreadyStartedTest"); - startup.placeAlreadyStarted.add(location + "/PlaceAlreadyStartedTest"); - assertTrue(startup.verifyNoInvisiblePlacesStarted()); - startup.activeDirPlaces.clear(); - startup.placeAlreadyStarted.clear(); + Startup.activeDirPlaces.add(location + "/PlaceAlreadyStartedTest"); + Startup.placeAlreadyStarted.add(location + "/PlaceAlreadyStartedTest"); + assertTrue(Startup.verifyNoInvisiblePlacesStarted()); + Startup.activeDirPlaces.clear(); + Startup.placeAlreadyStarted.clear(); // test if place is started up normally and is active dir - startup.places.put(location, DevNullPlace.class.getSimpleName()); - startup.activeDirPlaces.add(DevNullPlace.class.getSimpleName()); - assertTrue(startup.verifyNoInvisiblePlacesStarted()); - startup.activeDirPlaces.clear(); - startup.places.remove(location, DevNullPlace.class.getSimpleName()); + Startup.places.put(location, DevNullPlace.class.getSimpleName()); + Startup.activeDirPlaces.add(DevNullPlace.class.getSimpleName()); + assertTrue(Startup.verifyNoInvisiblePlacesStarted()); + Startup.activeDirPlaces.clear(); + Startup.places.remove(location, DevNullPlace.class.getSimpleName()); // test unannounced place with active dir - startup.activeDirPlaces.add(location + "/PlaceStartUnannouncedTest"); - assertFalse(startup.verifyNoInvisiblePlacesStarted()); - startup.activeDirPlaces.clear(); + Startup.activeDirPlaces.add(location + "/PlaceStartUnannouncedTest"); + assertFalse(Startup.verifyNoInvisiblePlacesStarted()); + Startup.activeDirPlaces.clear(); // teardown dirTeardown(); } @Test - void verifyNoInvisiblePlacesStartedHandlesNullLocalPlace() throws IOException { - // setup node, startup, and DirectoryPlace - EmissaryNode node = new EmissaryNode(); - Startup startup = new Startup(node.getNodeConfigurator(), node); - + void verifyNoInvisiblePlacesStartedHandlesNullLocalPlace() { try (MockedStatic dirPlace = Mockito.mockStatic(DirectoryPlace.class)) { DirectoryEntry entry = mock(DirectoryEntry.class); @@ -106,7 +101,7 @@ void verifyNoInvisiblePlacesStartedHandlesNullLocalPlace() throws IOException { dirPlace.when(DirectoryPlace::lookup).thenReturn(directoryPlace); - assertTrue(startup.verifyNoInvisiblePlacesStarted()); + assertTrue(Startup.verifyNoInvisiblePlacesStarted()); } } diff --git a/src/test/java/emissary/server/EmissaryServerIT.java b/src/test/java/emissary/server/EmissaryServerIT.java index 1ede3f7793..dd262379c1 100644 --- a/src/test/java/emissary/server/EmissaryServerIT.java +++ b/src/test/java/emissary/server/EmissaryServerIT.java @@ -1,8 +1,11 @@ package emissary.server; +import emissary.admin.Startup; import emissary.client.EmissaryClient; import emissary.client.response.MapResponseEntity; import emissary.command.ServerCommand; +import emissary.core.EmissaryException; +import emissary.directory.EmissaryNode; import emissary.test.core.junit5.UnitTest; import emissary.util.Version; @@ -15,6 +18,7 @@ import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; class EmissaryServerIT extends UnitTest { @@ -49,4 +53,15 @@ void testSSLWorks() throws Exception { } } + @Test + void testInvisPlacesOnStrictStartUp() throws EmissaryException { + ServerCommand cmd = ServerCommand.parse(ServerCommand.class, "--strict"); + EmissaryServer server = new EmissaryServer(cmd); + EmissaryNode node = new EmissaryNode(); + String location = "http://" + node.getNodeName() + ":" + node.getNodePort(); + Startup.getInvisPlaces().add(location + "/PlaceStartUnannouncedTest"); + server.startServer(); + // make sure server is shutdown due to invis places on strict startup + assertFalse(server.isServerRunning()); + } }