Skip to content

Commit

Permalink
[WFCORE-6503]:Add support for unmanaged deployments with YAML extension.
Browse files Browse the repository at this point in the history
* checking that the YAML deployment is unmanaged.
* adding the unmanaged deployment to the list of operations
* adding some light esting on this
* adding WARNING traces
* adding warning if YAML is adding an existing resource without any attribute
* failing if unexisting attribute is used
* better error messages

Jira: https://issues.redhat.com/browse/WFCORE-6503
Proposal: wildfly/wildfly-proposals#554

Signed-off-by: Emmanuel Hugonnet <[email protected]>
  • Loading branch information
ehsavoie committed Mar 12, 2024
1 parent eb092ef commit 2a50517
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3682,7 +3682,7 @@ OperationFailedRuntimeException capabilityAlreadyRegisteredInContext(String capa
IllegalArgumentException noResourceForUndefiningAttribute(String attribute, String address);

@LogMessage(level = WARN)
@Message(id = 490, value = "You have defined a resource for address %s without any attributes, doing nothing")
@Message(id = 490, value = " A YAML resource has been defined for the address %s without any attributes. No actions will be taken.")
void noAttributeSetForAddress(String address);

@LogMessage(level = WARN)
Expand Down Expand Up @@ -3744,12 +3744,28 @@ OperationFailedRuntimeException capabilityAlreadyRegisteredInContext(String capa
@Message(id = 501, value = "An invalid UUID string '%s' was found at '%s'. A new value will be generated.")
void uuidNotValid(String corruptedUuid, String path);

@Message(id = 502, value = "No child resource called %s could be found at address %s'.")
@Message(id = 502, value = "No child resource called '%s' could be found at address '%s'.")
IllegalArgumentException noChildResource(String name, String address);

@Message(id = 503, value = "Failed to publish configuration, because the remote name %s is not valid.")
ConfigurationPersistenceException failedToPublishConfigurationInvalidRemote(String name);

@Message(id = 504, value = "The operation %s is not defined for resource %s.")
UnsupportedOperationException missingOperationForResource(String op, String address);

@Message(id = 505, value = "Unsuported deployment yaml file %s with attributes %s")
IllegalArgumentException unsupportedDeployment(String deployment, Set<String> attribues);

@Message(id = 506, value = "The yaml element '%s' and its sub-elements are ignored.")
String ignoreYamlElement(String element);

@Message(id = NONE, value = " Thus ignoring element '%s'.")
String ignoreYamlSubElement(String element);

@Message(id = 507, value = "No attribute called '%s' is defined at address '%s'.")
IllegalArgumentException noAttributeDefined(String name, String address);

@Message(id = 508, value = "No operation %s can be executed for attribute called '%s' is defined at address '%s'.")
IllegalArgumentException illegalOperationForAttribute(String operationName, String attribute, String address);

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@

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.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 @@ -27,6 +33,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 @@ -74,7 +81,9 @@ public class YamlConfigurationExtension implements ConfigurationExtension {
private boolean needReload;
private Path[] files;
private final List<Map<String, Object>> configs = new ArrayList<>();
private static final String[] EXCLUDED_ELEMENTS = {" deployment", "extension", "deployment-overlay"};
private final Map<String, Object> deployments = new LinkedHashMap<>();
private static final String[] EXCLUDED_ELEMENTS = {"deployment", "extension", "deployment-overlay"};
public static final Set<String> MANAGED_CONTENT_ATTRIBUTES = Set.of(INPUT_STREAM_INDEX, HASH, BYTES, URL, EMPTY);

@SuppressWarnings("unchecked")
public YamlConfigurationExtension() {
Expand All @@ -94,16 +103,26 @@ private void load() {
for (Path file : files) {
if (file != null && Files.exists(file) && Files.isRegularFile(file)) {
Map<String, Object> yamlConfig = Collections.emptyMap();
Yaml yaml = new Yaml(new OperationConstructor(new LoaderOptions()));
try (InputStream inputStream = Files.newInputStream(file)) {
Yaml yaml = new Yaml(new OperationConstructor(new LoaderOptions()));
yamlConfig = yaml.load(inputStream);
} catch (IOException ioex) {
throw MGMT_OP_LOGGER.failedToParseYamlConfigurationFile(file.toAbsolutePath().toString(), ioex);
}
if (yamlConfig.containsKey(CONFIGURATION_ROOT_KEY)) {
Map<String, Object> config = (Map<String, Object>) yamlConfig.get(CONFIGURATION_ROOT_KEY);
for (String excluded : EXCLUDED_ELEMENTS) {
config.remove(excluded);
boolean isPresent = config.containsKey(excluded);
Object value = config.remove(excluded);
if(value != null && value instanceof Map && DEPLOYMENT.equals(excluded)) {
deployments.putAll((Map<String, Object>) value);
} else if (isPresent) {
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);
}
}
parsedFiles.add(file.toAbsolutePath().toString());
this.configs.add(config);
Expand Down Expand Up @@ -142,6 +161,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 @@ -217,8 +239,12 @@ private void processResource(PathAddress parentAddress, Map<String, Object> yaml
} else {
if (value != null && resourceRegistration.getAttributeNames(PathAddress.EMPTY_ADDRESS).contains(name)) {
//we are processing an attribute:
MGMT_OP_LOGGER.debugf("We are processing the attribute %s for address %s", name, address.getParent().toCLIStyleString());
MGMT_OP_LOGGER.debugf("We are processing the attribute %s for address %s", name, parentAddress.toCLIStyleString());
processAttribute(parentAddress, rootRegistration, name, value, postExtensionOps, xmlOperations);
} else if (value == null) {
MGMT_OP_LOGGER.noAttributeSetForAddress(address.toCLIStyleString());
} else {
throw MGMT_OP_LOGGER.noAttributeDefined(name, address.toCLIStyleString());
}
}
} else {
Expand Down Expand Up @@ -471,6 +497,22 @@ 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);
if (deployment.getValue() != null && deployment.getValue() instanceof Map) {
Map<String, Object> attributes = (Map<String, Object>) deployment.getValue();
Map<String, Object> content = (Map<String, Object>) (((Iterable<? extends Object>)attributes.get("content")).iterator().next());
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 {
void processOperation(ImmutableManagementResourceRegistration rootRegistration, Map<PathAddress, ParsedBootOp> xmlOperations, List<ParsedBootOp> postExtensionOps, PathAddress address, String name);
}
Expand Down Expand Up @@ -525,6 +567,8 @@ public void processOperation(ImmutableManagementResourceRegistration rootRegistr
op.get(OP_ADDR).set(address.toModelNode());
op.get(NAME).set(name);
postExtensionOps.add(new ParsedBootOp(op, operationEntry.getOperationHandler()));
} else {
throw MGMT_OP_LOGGER.illegalOperationForAttribute(UNDEFINE_ATTRIBUTE_OPERATION, name, address.toPathStyleString());
}
}

Expand All @@ -544,6 +588,9 @@ public void processOperation(ImmutableManagementResourceRegistration rootRegistr
OperationEntry operationEntry = rootRegistration.getOperationEntry(address, "list-add");
if (operationEntry != null) {
AttributeAccess access = rootRegistration.getAttributeAccess(address, name);
if(! (access.getAttributeDefinition() instanceof ListAttributeDefinition)) {
throw MGMT_OP_LOGGER.illegalOperationForAttribute("list-add", name, address.toPathStyleString());
}
ListAttributeDefinition att = (ListAttributeDefinition) access.getAttributeDefinition();
AttributeDefinition type = att.getValueAttributeDefinition();
if (type == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ public void testUnknownResource() throws URISyntaxException {
instance.processOperations(rootRegistration, postExtensionOps);
fail("Unknown resource should make the yaml extension fail");
} catch (java.lang.IllegalArgumentException ex) {
assertEquals("WFLYCTL0502: No child resource called system-propety could be found at address /'.", ex.getMessage());
assertEquals("WFLYCTL0502: No child resource called 'system-propety' could be found at address '/'.", ex.getMessage());
}
}

Expand Down Expand Up @@ -299,7 +299,7 @@ public void testUnknownChildResource() throws URISyntaxException {
try {
instance.processOperations(rootRegistration, postExtensionOps);fail("Unknown resource should make the yaml extension fail");
} catch (java.lang.IllegalArgumentException ex) {
assertEquals("WFLYCTL0502: No child resource called children could be found at address /parent=homer'.", ex.getMessage());
assertEquals("WFLYCTL0502: No child resource called 'children' could be found at address '/parent=homer'.", ex.getMessage());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading

0 comments on commit 2a50517

Please sign in to comment.