This is an automated email from the ASF dual-hosted git repository. heneveld pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git
commit 840f6f8b840faebbd702663a162828a4601a7b78 Author: Alex Heneveld <[email protected]> AuthorDate: Wed Jul 13 12:02:31 2022 +0100 add failing test for import not allowing bundles in unusual orders --- .../catalog/internal/BasicBrooklynCatalog.java | 5 +- .../apache/brooklyn/core/mgmt/ha/OsgiManager.java | 11 ++- .../BrooklynBomYamlCatalogBundleResolver.java | 3 +- .../brooklyn/rest/resources/ServerResource.java | 1 + .../rest/resources/ApplicationResourceTest.java | 10 +-- .../rest/resources/ServerResourceTest.java | 96 +++++++++++++++++++++- 6 files changed, 116 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java index ce10b25a80..8e742eb6cf 100644 --- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java +++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java @@ -1607,8 +1607,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog { itemSpecInstantiated = internalCreateSpecLegacy(mgmt, itemToAttempt, MutableSet.<String>of(), true); if (!candidateYaml.contains("services:")) { - // 'services:' blueprints still need legacy plan-to-spec converter - log.warn("Instantiation of this blueprint was only possible with legacy plan-to-spec converter, will likely not be supported in future versions:\n" + candidateYaml); + // 'services:' blueprints still need legacy plan-to-spec converter, don't even debug on that. + // for others + log.debug("Instantiation of this blueprint was only possible with legacy plan-to-spec converter, may not be supported in future versions:\n" + candidateYaml); } } diff --git a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java index 65b81e5ada..edd4349396 100644 --- a/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java +++ b/core/src/main/java/org/apache/brooklyn/core/mgmt/ha/OsgiManager.java @@ -440,7 +440,7 @@ public class OsgiManager { @Nullable ManagedBundle knownBundleMetadata, @Nullable Supplier<InputStream> zipIn, boolean validateTypes) { BundleInstallationOptions options = new BundleInstallationOptions(); options.setDeferredStart(true); - options.setFormat(knownBundleMetadata.getFormat()); + if (knownBundleMetadata!=null) options.setFormat(knownBundleMetadata.getFormat()); options.setValidateTypes(validateTypes); options.setKnownBundleMetadata(knownBundleMetadata); return BrooklynCatalogBundleResolvers.install(getManagementContext(), zipIn, options); @@ -464,11 +464,20 @@ public class OsgiManager { public ReferenceWithError<OsgiBundleInstallationResult> installBrooklynBomBundle( @Nullable ManagedBundle knownBundleMetadata, Supplier<InputStream> input, boolean start, boolean loadCatalogBom, boolean forceUpdateOfNonSnapshots) { + return installBrooklynBomBundle(knownBundleMetadata, input, start, loadCatalogBom, forceUpdateOfNonSnapshots, true, false); + } + + @Beta + public ReferenceWithError<OsgiBundleInstallationResult> installBrooklynBomBundle( + @Nullable ManagedBundle knownBundleMetadata, Supplier<InputStream> input, + boolean start, boolean loadCatalogBom, boolean forceUpdateOfNonSnapshots, boolean validate, boolean deferredStart) { BundleInstallationOptions options = new BundleInstallationOptions(); options.setKnownBundleMetadata(knownBundleMetadata); options.setStart(start); options.setLoadCatalogBom(loadCatalogBom); options.setForceUpdateOfNonSnapshots(forceUpdateOfNonSnapshots); + options.setValidateTypes(validate); + options.setDeferredStart(deferredStart); return BrooklynCatalogBundleResolvers.install(getManagementContext(), input, options); } diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java index 72ae2dc361..f4ed4b02aa 100644 --- a/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java +++ b/core/src/main/java/org/apache/brooklyn/core/typereg/BrooklynBomYamlCatalogBundleResolver.java @@ -134,7 +134,8 @@ public class BrooklynBomYamlCatalogBundleResolver extends AbstractCatalogBundleR basicManagedBundle.tags().addTags((Iterable<?>)cm.get("tags")); } result = ((ManagementContextInternal)mgmt).getOsgiManager().get().installBrooklynBomBundle( - basicManagedBundle, InputStreamSource.of("ZIP generated for "+vn+": "+bf, bf), options.isStart(), options.isLoadCatalogBom(), options.isForceUpdateOfNonSnapshots()).get(); + basicManagedBundle, InputStreamSource.of("ZIP generated for "+vn+": "+bf, bf), options.isStart(), options.isLoadCatalogBom(), options.isForceUpdateOfNonSnapshots(), + options.isValidateTypes(), options.isDeferredStart()).get(); } finally { bf.delete(); } diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java index 0c7739a404..812ede244d 100644 --- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java +++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/ServerResource.java @@ -661,6 +661,7 @@ public class ServerResource extends AbstractBrooklynRestResource implements Serv } catch (Exception e){ Exceptions.propagateIfFatal(e); ApiError.Builder error = ApiError.builder().errorCode(Response.Status.BAD_REQUEST); + log.warn("Error importing persisted state: "+e, e); error.message(e.getMessage()); return error.build().asJsonResponse(); } finally { diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java index 701a09194b..1882fdf42e 100644 --- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ApplicationResourceTest.java @@ -213,7 +213,7 @@ public class ApplicationResourceTest extends BrooklynRestResourceTest { .build(); Response response = clientDeploy(spec); - assertTrue(response.getStatus() / 100 == 2, "response is " + response); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); // Expect app to be running URI appUri = response.getLocation(); @@ -227,7 +227,7 @@ public class ApplicationResourceTest extends BrooklynRestResourceTest { Response response = client().path("/applications") .post(Entity.entity(yaml, "application/x-yaml")); - assertTrue(response.getStatus()/100 == 2, "response is "+response); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); // Expect app to be running URI appUri = response.getLocation(); @@ -250,7 +250,7 @@ public class ApplicationResourceTest extends BrooklynRestResourceTest { " static.value: " + SENSOR_TEXT_VALUE); Response response = client().path("/applications") .post(Entity.entity(yaml, "application/x-yaml")); - assertTrue(response.getStatus()/100 == 2, "response is "+response); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); // Fetch applications, find 'simple-app-yaml-with-invalid-sensor-type' application and inspect details. Collection apps = client().path("/applications/fetch").get(Collection.class); @@ -275,7 +275,7 @@ public class ApplicationResourceTest extends BrooklynRestResourceTest { Response response = client().path("/applications") .header(HttpHeaders.CONTENT_TYPE, ContentType.MULTIPART_FORM_DATA) .post(body); - assertTrue(response.getStatus()/100 == 2, "response is "+response); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); // Expect app to be running URI appUri = response.getLocation(); @@ -297,7 +297,7 @@ public class ApplicationResourceTest extends BrooklynRestResourceTest { Response response = client().path("/applications") .post(Entity.entity(yaml, "application/x-yaml")); - assertTrue(response.getStatus()/100 == 2, "response is "+response); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); // Expect app to be running URI appUri = response.getLocation(); diff --git a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceTest.java b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceTest.java index 786f8dbfd4..d08dad477d 100644 --- a/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceTest.java +++ b/rest/rest-resources/src/test/java/org/apache/brooklyn/rest/resources/ServerResourceTest.java @@ -23,6 +23,7 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import java.io.ByteArrayInputStream; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -30,6 +31,8 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.brooklyn.api.entity.EntitySpec; @@ -37,10 +40,18 @@ import org.apache.brooklyn.api.entity.ImplementedBy; import org.apache.brooklyn.api.location.Location; import org.apache.brooklyn.api.location.LocationSpec; import org.apache.brooklyn.api.mgmt.ManagementContext; +import org.apache.brooklyn.api.mgmt.ha.HighAvailabilityMode; import org.apache.brooklyn.api.mgmt.ha.ManagementNodeState; +import org.apache.brooklyn.camp.brooklyn.BrooklynCampPlatformLauncherNoServer; import org.apache.brooklyn.core.BrooklynVersion; +import org.apache.brooklyn.core.entity.Entities; import org.apache.brooklyn.core.internal.BrooklynProperties; +import org.apache.brooklyn.core.mgmt.ha.OsgiBundleInstallationResult; import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal; +import org.apache.brooklyn.core.mgmt.rebind.RebindTestUtils; +import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.core.typereg.BrooklynBomYamlCatalogBundleResolver; import org.apache.brooklyn.entity.software.base.EmptySoftwareProcess; import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessDriver; import org.apache.brooklyn.entity.software.base.EmptySoftwareProcessImpl; @@ -49,8 +60,15 @@ import org.apache.brooklyn.location.ssh.SshMachineLocation; import org.apache.brooklyn.rest.domain.HighAvailabilitySummary; import org.apache.brooklyn.rest.domain.VersionSummary; import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest; +import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.guava.Suppliers; +import org.apache.brooklyn.util.http.HttpAsserts; +import org.apache.brooklyn.util.os.Os; +import org.apache.brooklyn.util.text.Identifiers; import org.apache.brooklyn.util.text.StringPredicates; +import org.apache.brooklyn.util.text.Strings; +import org.apache.brooklyn.util.time.Duration; import org.apache.cxf.jaxrs.client.WebClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,7 +83,10 @@ import com.google.common.collect.Iterables; public class ServerResourceTest extends BrooklynRestResourceTest { private static final Logger log = LoggerFactory.getLogger(ServerResourceTest.class); - + + @Override + protected boolean useOsgi() { return true; } + @Test public void testGetVersion() throws Exception { VersionSummary version = client().path("/server/version").get(VersionSummary.class); @@ -93,6 +114,79 @@ public class ServerResourceTest extends BrooklynRestResourceTest { List<String> entryNames = listEntryNames(zip); assertTrue(Iterables.tryFind(entryNames, StringPredicates.containsLiteral(app.getId())).isPresent(), "entries="+entryNames); assertTrue(Iterables.tryFind(entryNames, StringPredicates.containsLiteral(loc.getId())).isPresent(), "entries="+entryNames); + + Entities.unmanage(app); + } + + @Test + public void testExportPersistedStateWithBundlesThenReimport() throws Exception { + // export seems to preserve install order probably to minimise conflicts, so use deferred start to get the problematic order + OsgiBundleInstallationResult r2 = ((ManagementContextInternal) manager).getOsgiManager().get().installDeferredStart(null, + () -> new ByteArrayInputStream(Strings.lines( + "brooklyn.catalog:", + " bundle: b2", + " version: 1", + " id: b2", + " itemType: entity", + " item:", + " type: b1" + ).getBytes()), + false).get(); + + ((ManagementContextInternal) manager).getOsgiManager().get().install( + () -> new ByteArrayInputStream(Strings.lines( + "brooklyn.catalog:", + " bundle: b1", + " version: 1", + " id: b1", + " itemType: entity", + " item:", + " type: org.apache.brooklyn.core.test.entity.TestEntity" + ).getBytes()), + BrooklynBomYamlCatalogBundleResolver.FORMAT, false, null).get(); + + r2.getDeferredStart().run(); + + String yaml = "services: [ { type: b2 } ]"; + Response response = client().path("/applications") + .post(Entity.entity(yaml, "application/x-yaml")); + HttpAsserts.assertHealthyStatusCode(response.getStatus()); + + org.apache.brooklyn.api.entity.Entity b2 = Iterables.getOnlyElement(Iterables.getOnlyElement(manager.getApplications()).getChildren()); + Asserts.assertInstanceOf(b2, TestEntity.class); + + byte[] zip = client().path("/server/ha/persist/export").get(byte[].class); + + // restart the server, so it has nothing, then try importing + destroyClass(); + + File mementoDir = Os.newTempDir(getClass()); + manager = RebindTestUtils.managementContextBuilder(mementoDir, getClass().getClassLoader()) + .persistPeriodMillis(Duration.ONE_MINUTE.toMilliseconds()) + .haMode(HighAvailabilityMode.MASTER) + .forLive(true) + .enablePersistenceBackups(false) + .emptyCatalog(true) +// .properties(false) + .setOsgiEnablementAndReuse(useOsgi(), true) + .buildStarted(); + new BrooklynCampPlatformLauncherNoServer() + .useManagementContext(manager) + .launch(); + + initClass(); + + Asserts.assertNull(manager.getTypeRegistry().get("b2")); + Asserts.assertSize(manager.getApplications(), 0); + + Response importResponse = client().path("/server/ha/persist/import").post(Entity.entity(zip, MediaType.APPLICATION_OCTET_STREAM_TYPE)); + HttpAsserts.assertHealthyStatusCode(importResponse.getStatus()); + + Asserts.assertNotNull(manager.getTypeRegistry().get("b1")); + Asserts.assertNotNull(manager.getTypeRegistry().get("b2")); + org.apache.brooklyn.api.entity.Entity b2b = Iterables.getOnlyElement(Iterables.getOnlyElement(manager.getApplications()).getChildren()); + Asserts.assertInstanceOf(b2b, TestEntity.class); + Asserts.assertEquals(b2b.getId(), b2.getId()); } private List<String> listEntryNames(byte[] zip) throws Exception {
