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 <ehugonne@redhat.com>
  • Loading branch information
ehsavoie committed Mar 13, 2024
1 parent eb092ef commit c6dcfa8
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 13 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 attribute. No actions will be taken.")
void noAttributeSetForAddress(String address);

@LogMessage(level = WARN)
Expand Down Expand Up @@ -3744,12 +3744,30 @@ 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);

@Message(id = 509, value = "No value is defined for attribute '%s' at address '%s'.")
IllegalArgumentException noAttributeValueDefined(String name, String address);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +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 @@ -27,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 @@ -74,7 +82,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 +104,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 +162,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 @@ -186,7 +209,10 @@ private void processResource(PathAddress parentAddress, Map<String, Object> yaml
} else if (yamlOperation instanceof RemoveOperation) {
//ignore
} else {
throw MGMT_OP_LOGGER.noResourceForUndefiningAttribute(name, address.toCLIStyleString());
if(yamlOperation instanceof UndefineOperation) {
throw MGMT_OP_LOGGER.noResourceForUndefiningAttribute(name, address.toCLIStyleString());
}
throw MGMT_OP_LOGGER.illegalOperationForAttribute(yamlOperation.getOperationName() ,name, address.toCLIStyleString());
}
} else {
if (!isExistingResource(xmlOperations, address)) {
Expand Down Expand Up @@ -217,8 +243,16 @@ 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) {
if (resourceRegistration.getAttributeNames(PathAddress.EMPTY_ADDRESS).contains(name)) {
throw MGMT_OP_LOGGER.noAttributeValueDefined(name, address.toCLIStyleString());
} else {
MGMT_OP_LOGGER.noAttributeSetForAddress(address.toCLIStyleString());
}
} else {
throw MGMT_OP_LOGGER.noAttributeDefined(name, address.toCLIStyleString());
}
}
} else {
Expand Down Expand Up @@ -471,7 +505,24 @@ 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 {
String getOperationName();
void processOperation(ImmutableManagementResourceRegistration rootRegistration, Map<PathAddress, ParsedBootOp> xmlOperations, List<ParsedBootOp> postExtensionOps, PathAddress address, String name);
}

Expand Down Expand Up @@ -509,6 +560,11 @@ public void processOperation(ImmutableManagementResourceRegistration rootRegistr
}
}

@Override
public String getOperationName() {
return REMOVE;
}

}

private class UndefineOperation implements Operation {
Expand All @@ -525,9 +581,16 @@ 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(getOperationName(), name, address.toPathStyleString());
}
}

@Override
public String getOperationName() {
return UNDEFINE_ATTRIBUTE_OPERATION;
}

}

private class ListAddOperation implements Operation {
Expand All @@ -541,9 +604,12 @@ private class ListAddOperation implements Operation {
@Override
@SuppressWarnings("unchecked")
public void processOperation(ImmutableManagementResourceRegistration rootRegistration, Map<PathAddress, ParsedBootOp> xmlOperations, List<ParsedBootOp> postExtensionOps, PathAddress address, String name) {
OperationEntry operationEntry = rootRegistration.getOperationEntry(address, "list-add");
OperationEntry operationEntry = rootRegistration.getOperationEntry(address, getOperationName());
if (operationEntry != null) {
AttributeAccess access = rootRegistration.getAttributeAccess(address, name);
if(! (access.getAttributeDefinition() instanceof ListAttributeDefinition)) {
throw MGMT_OP_LOGGER.illegalOperationForAttribute(getOperationName(), name, address.toPathStyleString());
}
ListAttributeDefinition att = (ListAttributeDefinition) access.getAttributeDefinition();
AttributeDefinition type = att.getValueAttributeDefinition();
if (type == null) {
Expand Down Expand Up @@ -613,6 +679,11 @@ public void processOperation(ImmutableManagementResourceRegistration rootRegistr
}
}

@Override
public String getOperationName() {
return "list-add";
}

}

private class OperationConstructor extends Constructor {
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 @@

0 comments on commit c6dcfa8

Please sign in to comment.