Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WFCORE-6503]:Add support for unmanaged deployments with YAML extension. #5860

Merged
merged 1 commit into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -77,7 +84,9 @@ public class YamlConfigurationExtension implements ConfigurationExtension {
private boolean needReload;
private Path[] files;
private final List<Map<String, Object>> configs = new ArrayList<>();
private final Map<String, Object> deployments = new LinkedHashMap<>();
private static final String[] EXCLUDED_ELEMENTS = {"deployment", "extension", "deployment-overlay", "path"};
public static final Set<String> MANAGED_CONTENT_ATTRIBUTES = Set.of(INPUT_STREAM_INDEX, HASH, BYTES, URL, EMPTY);

@SuppressWarnings("unchecked")
public YamlConfigurationExtension() {
Expand Down Expand Up @@ -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<String, Object>) 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());
Expand Down Expand Up @@ -160,6 +173,9 @@ public void processOperations(ImmutableManagementResourceRegistration rootRegist
for (Map<String, Object> config : configs) {
processResource(PathAddress.EMPTY_ADDRESS, new HashMap<>(config), rootRegistration, rootRegistration, xmlOperations, postExtensionOps, false);
}
for (Map.Entry<String, Object> deployment : deployments.entrySet()) {
processUnmanagedDeployments(rootRegistration, deployment, xmlOperations, postExtensionOps);
}
this.configs.clear();
needReload = true;
}
Expand Down Expand Up @@ -395,16 +411,25 @@ private void processAttribute(PathAddress address, ImmutableManagementResourceRe
@SuppressWarnings("unchecked")
private void processAttributes(PathAddress address, ImmutableManagementResourceRegistration rootRegistration, OperationEntry operationEntry, Map<String, Object> map, List<ParsedBootOp> postExtensionOps, Map<PathAddress, ParsedBootOp> xmlOperations) {
Set<AttributeDefinition> attributes = new HashSet<>();
Set<String> 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) {
Expand Down Expand Up @@ -524,6 +549,23 @@ public String getCommandLineInstructions() {
return MGMT_OP_LOGGER.argYaml();
}

@SuppressWarnings("unchecked")
private void processUnmanagedDeployments(ImmutableManagementResourceRegistration rootRegistration, Map.Entry<String, Object> deployment, Map<PathAddress, ParsedBootOp> xmlOperations, List<ParsedBootOp> postExtensionOps) {
String name = deployment.getKey();
OperationEntry operationEntry = rootRegistration.getOperationEntry(PathAddress.pathAddress("deployment", name), ADD);
assert deployment.getValue() instanceof Map;
Map<String, Object> attributes = (Map<String, Object>) deployment.getValue();
if (attributes.get("content") instanceof Iterable) {
Map<String, Object> content = (Map<String, Object>) (((Iterable<? extends Object>) attributes.get("content")).iterator().next());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can NPE if there is no 'content' and fail in other confusing ways if it's not a list or an empty list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing that as it is only for validation purpose

Set<String> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to reviewers:

The configInteractionPolicy var is never read in this branch, making the assignment here pointless and thus the other removed lines pointless as well.

There are uses of the var in other branches.

}
homeDir = new File(WildFlySecurityManager.getPropertyPrivileged("user.dir", "."));
serverBaseDir = new File(WildFlySecurityManager.getPropertyPrivileged("user.dir", "."));
serverLogDir = new File(WildFlySecurityManager.getPropertyPrivileged("user.dir", "."));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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");
Expand All @@ -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("\"", "'");
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ wildfly-configuration:
standard-sockets:
socket-binding:
management-https: !remove

subsystem:
elytron:
disallowed-providers: !undefine
Expand Down