From b7b8caccaf902eee887001ba9fddc1ee761fcc41 Mon Sep 17 00:00:00 2001 From: Emmanuel Hugonnet Date: Wed, 26 Jun 2024 11:25:03 +0200 Subject: [PATCH] [WFCORE-6503]: Add support for unmanaged deployments with YAML extension. * checking that the YAML deployment is unmanaged. * adding the unmanaged deployment to the list of operations * adding some light testing on this * fixing issue WFCORE-6857 where you couldn't enable an unmanaged deployment with yaml Jira: https://issues.redhat.com/browse/WFCORE-6503 https://issues.redhat.com/browse/WFCORE-6857 Proposal: https://github.com/wildfly/wildfly-proposals/pull/554 Signed-off-by: Emmanuel Hugonnet --- .../yaml/YamlConfigurationExtension.java | 50 +++++++++++++++++-- .../jboss/as/server/ServerEnvironment.java | 5 -- .../yaml/YamlExtensionTestCase.java | 45 +++++++++++++++++ .../persistence/yaml/test-deployment.yml | 15 ++++++ .../yaml/test-managed-deployment.yml | 12 +++++ .../persistence/yaml/test-operations.yml | 1 - 6 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-deployment.yml create mode 100644 testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-managed-deployment.yml diff --git a/controller/src/main/java/org/jboss/as/controller/persistence/yaml/YamlConfigurationExtension.java b/controller/src/main/java/org/jboss/as/controller/persistence/yaml/YamlConfigurationExtension.java index 4794322b94d..f243173ba33 100644 --- a/controller/src/main/java/org/jboss/as/controller/persistence/yaml/YamlConfigurationExtension.java +++ b/controller/src/main/java/org/jboss/as/controller/persistence/yaml/YamlConfigurationExtension.java @@ -6,11 +6,17 @@ import static org.jboss.as.controller.client.impl.AdditionalBootCliScriptInvoker.CLI_SCRIPT_PROPERTY; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.BYTES; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.EMPTY; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HASH; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INPUT_STREAM_INDEX; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UNDEFINE_ATTRIBUTE_OPERATION; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.URL; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.WRITE_ATTRIBUTE_OPERATION; import static org.jboss.as.controller.logging.ControllerLogger.MGMT_OP_LOGGER; @@ -28,6 +34,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -77,7 +84,9 @@ public class YamlConfigurationExtension implements ConfigurationExtension { private boolean needReload; private Path[] files; private final List> configs = new ArrayList<>(); + private final Map deployments = new LinkedHashMap<>(); private static final String[] EXCLUDED_ELEMENTS = {"deployment", "extension", "deployment-overlay", "path"}; + public static final Set MANAGED_CONTENT_ATTRIBUTES = Set.of(INPUT_STREAM_INDEX, HASH, BYTES, URL, EMPTY); @SuppressWarnings("unchecked") public YamlConfigurationExtension() { @@ -114,11 +123,15 @@ private void load() { boolean isPresent = config.containsKey(excluded); if (isPresent) { Object value = config.remove(excluded); - String message = MGMT_OP_LOGGER.ignoreYamlElement(excluded); - if (value != null) { - message = message + MGMT_OP_LOGGER.ignoreYamlSubElement(yaml.dump(value).trim()); + if (value instanceof Map && DEPLOYMENT.equals(excluded)) { + deployments.putAll((Map) value); + } else { + String message = MGMT_OP_LOGGER.ignoreYamlElement(excluded); + if (value != null) { + message = message + MGMT_OP_LOGGER.ignoreYamlSubElement(yaml.dump(value).trim()); + } + MGMT_OP_LOGGER.warn(message); } - MGMT_OP_LOGGER.warn(message); } } parsedFiles.add(file.toAbsolutePath().toString()); @@ -160,6 +173,9 @@ public void processOperations(ImmutableManagementResourceRegistration rootRegist for (Map config : configs) { processResource(PathAddress.EMPTY_ADDRESS, new HashMap<>(config), rootRegistration, rootRegistration, xmlOperations, postExtensionOps, false); } + for (Map.Entry deployment : deployments.entrySet()) { + processUnmanagedDeployments(rootRegistration, deployment, xmlOperations, postExtensionOps); + } this.configs.clear(); needReload = true; } @@ -395,16 +411,25 @@ private void processAttribute(PathAddress address, ImmutableManagementResourceRe @SuppressWarnings("unchecked") private void processAttributes(PathAddress address, ImmutableManagementResourceRegistration rootRegistration, OperationEntry operationEntry, Map map, List postExtensionOps, Map xmlOperations) { Set attributes = new HashSet<>(); + Set attributeNames = new HashSet<>(); for (AttributeAccess attributeAccess : rootRegistration.getAttributes(address).values()) { if (attributeAccess.getStorageType() == AttributeAccess.Storage.CONFIGURATION) { AttributeDefinition def = attributeAccess.getAttributeDefinition(); if (def != null) { if (!def.isResourceOnly()) { attributes.add(def); + attributeNames.add(def.getName()); } } } } + for (AttributeDefinition def : operationEntry.getOperationDefinition().getParameters()) { + if (def != null && ! attributeNames.contains(def.getName())) { + if (!def.isResourceOnly()) { + attributes.add(def); + } + } + } attributes.addAll(Arrays.asList(operationEntry.getOperationDefinition().getParameters())); ModelNode op = createOperation(address, operationEntry); if (map != null) { @@ -524,6 +549,23 @@ public String getCommandLineInstructions() { return MGMT_OP_LOGGER.argYaml(); } + @SuppressWarnings("unchecked") + private void processUnmanagedDeployments(ImmutableManagementResourceRegistration rootRegistration, Map.Entry deployment, Map xmlOperations, List postExtensionOps) { + String name = deployment.getKey(); + OperationEntry operationEntry = rootRegistration.getOperationEntry(PathAddress.pathAddress("deployment", name), ADD); + assert deployment.getValue() instanceof Map; + Map attributes = (Map) deployment.getValue(); + if (attributes.get("content") instanceof Iterable) { + Map content = (Map) (((Iterable) attributes.get("content")).iterator().next()); + Set result = content.keySet().stream().distinct().filter(MANAGED_CONTENT_ATTRIBUTES::contains).collect(Collectors.toSet()); + if (!result.isEmpty()) { + throw MGMT_OP_LOGGER.unsupportedDeployment(name, result); + } + } + PathAddress address = PathAddress.pathAddress(DEPLOYMENT, name); + processAttributes(address, rootRegistration, operationEntry, attributes, postExtensionOps, xmlOperations); + } + private interface Operation { String getOperationName(); diff --git a/server/src/main/java/org/jboss/as/server/ServerEnvironment.java b/server/src/main/java/org/jboss/as/server/ServerEnvironment.java index 35646ff3eea..718b80bc24c 100644 --- a/server/src/main/java/org/jboss/as/server/ServerEnvironment.java +++ b/server/src/main/java/org/jboss/as/server/ServerEnvironment.java @@ -347,11 +347,6 @@ public ServerEnvironment(final String hostControllerName, final Properties props javaExtDirs = getFilesFromProperty(JAVA_EXT_DIRS, props); if (launchType.equals(LaunchType.SELF_CONTAINED)) { - Path[] supplementalConfigurationFiles = findSupplementalConfigurationFiles(null, supplementalConfiguration); - ConfigurationExtension configurationExtension = ConfigurationExtensionFactory.createConfigurationExtension(supplementalConfigurationFiles); - if (configurationExtension != null) { - configInteractionPolicy = configurationExtension.shouldProcessOperations(runningModeControl) ? ConfigurationFile.InteractionPolicy.READ_ONLY : configInteractionPolicy; - } homeDir = new File(WildFlySecurityManager.getPropertyPrivileged("user.dir", ".")); serverBaseDir = new File(WildFlySecurityManager.getPropertyPrivileged("user.dir", ".")); serverLogDir = new File(WildFlySecurityManager.getPropertyPrivileged("user.dir", ".")); diff --git a/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/management/persistence/yaml/YamlExtensionTestCase.java b/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/management/persistence/yaml/YamlExtensionTestCase.java index 7094d2f656f..39f735abc45 100644 --- a/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/management/persistence/yaml/YamlExtensionTestCase.java +++ b/testsuite/manualmode/src/test/java/org/jboss/as/test/manualmode/management/persistence/yaml/YamlExtensionTestCase.java @@ -6,9 +6,16 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.hamcrest.MatcherAssert.assertThat; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARCHIVE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATH; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RELATIVE_TO; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNNING_MODE; +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RUNTIME_NAME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UUID; @@ -145,6 +152,8 @@ public static void setup() throws Exception { testRemoveSocketYaml = getResourceFilePath("test-remove-socket.yml"); testAddingExtensionPathDeploymentOverlayIgnored = getResourceFilePath("test-adding-extension-path-deployment-overlay-ignored.yml"); testAddingEmptyExtensionFailYaml = getResourceFilePath("test-adding-empty-extension.yml"); + testDeploymentYaml = getResourceFilePath("test-deployment.yml"); + testManagedDeploymentYaml = getResourceFilePath("test-managed-deployment.yml"); testReplacingByEmptyResourceYaml = getResourceFilePath("test-replacing-by-empty-resource.yml"); testWrongIndentationYaml = getResourceFilePath("test-indentation-wrong.yml"); testNonExistentAttributeYaml = getResourceFilePath("test-setting-non-existent-attribute.yml"); @@ -154,6 +163,7 @@ public static void setup() throws Exception { testRemoveNonExistentResource = getResourceFilePath("test-remove-non-existent-resource.yml"); testListAddOperationToStringFails = getResourceFilePath("test-list-add-operation-to-string-fails.yml"); testListAddOperationToNonExistentResourceFails = getResourceFilePath("test-list-add-operation-to-non-existent-resource.yml"); + createDeployment(configurationDir.getParent().resolve("test.jar")); cliScript = getResourceFilePath("test.cli"); defaultXml = loadFile(configurationDir.resolve("standalone.xml")).replace("\"", "'"); expectedXml = loadFile(referenceConfiguration).replace("\"", "'"); @@ -248,6 +258,41 @@ public void testEmptyExtensionInYamlLogsWarnings() throws Exception { assertThat("Information that adding path is ignored is missing in log.", byteArrayOutputStream.toString(), CoreMatchers.containsString("WFLYCTL0508: The yaml element 'extension' and its sub-elements are ignored.")); } + @Test + public void testDeploymentYaml() throws Exception { + container.startYamlExtension(new Path[]{testDeploymentYaml}); + try (ModelControllerClient client = container.getClient().getControllerClient()) { + ModelNode deployment = readDeployment(client, "test.jar"); + Assert.assertEquals("test.jar", deployment.get(NAME).asString()); + Assert.assertEquals("test.jar", deployment.get(RUNTIME_NAME).asString()); + Assert.assertEquals("true", deployment.get(ENABLED).asString()); + ModelNode contentItemNode = deployment.get(CONTENT).get(0); + Assert.assertEquals("test.jar", contentItemNode.get(PATH).asString()); + Assert.assertEquals("jboss.server.base.dir", contentItemNode.get(RELATIVE_TO).asString()); + Assert.assertTrue(contentItemNode.get(ARCHIVE).asBoolean()); + deployment = readDeployment(client, "hello.jar"); + Assert.assertEquals("hello.jar", deployment.get(NAME).asString()); + Assert.assertEquals("hello.jar", deployment.get(RUNTIME_NAME).asString()); + contentItemNode = deployment.get(CONTENT).get(0); + Assert.assertEquals("test.jar", contentItemNode.get(PATH).asString()); + Assert.assertEquals("jboss.server.base.dir", contentItemNode.get(RELATIVE_TO).asString()); + Assert.assertTrue(contentItemNode.get(ARCHIVE).asBoolean()); + } + } + + /** + * Managed deployments are not supported. We should fail + */ + @Test + public void testServerStartFailedForManagedDeployment() { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + try { + container.startYamlExtension(new PrintStream(byteArrayOutputStream), new Path[]{testManagedDeploymentYaml}); + Assert.assertFalse(container.isStarted()); + } catch (RuntimeException ex) { + Assert.assertFalse(container.isStarted()); + } + } private static void createDeployment(Path deployment) throws IOException { final JavaArchive archive = ShrinkWrap.create(JavaArchive.class); diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-deployment.yml b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-deployment.yml new file mode 100644 index 00000000000..556a79c052a --- /dev/null +++ b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-deployment.yml @@ -0,0 +1,15 @@ +wildfly-configuration: + deployment: + test.jar: + content: + - + path: test.jar + relative-to: jboss.server.base.dir + archive: true + enabled: true + hello.jar: + content: + - + path: test.jar + relative-to: jboss.server.base.dir + archive: true \ No newline at end of file diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-managed-deployment.yml b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-managed-deployment.yml new file mode 100644 index 00000000000..61c84f5ee03 --- /dev/null +++ b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-managed-deployment.yml @@ -0,0 +1,12 @@ +wildfly-configuration: + deployment: + test.jar: + content: + - + path: test.jar + relative-to: jboss.server.base.dir + archive: true + hello.jar: + content: + - + empty: true \ No newline at end of file diff --git a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-operations.yml b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-operations.yml index 4e1d7f7ddbd..520782bff56 100644 --- a/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-operations.yml +++ b/testsuite/manualmode/src/test/resources/org/jboss/as/test/manualmode/management/persistence/yaml/test-operations.yml @@ -4,7 +4,6 @@ wildfly-configuration: standard-sockets: socket-binding: management-https: !remove - subsystem: elytron: disallowed-providers: !undefine