Skip to content

Commit

Permalink
[WFCORE-4758]: Community - Simple config export for a server as an at…
Browse files Browse the repository at this point in the history
…tachment for standalone or domain mode.

* Adding a new read-config-as-xml-file to replace read-config-as-xml.
* Adding more tests
* Fixing some tests that aren't cleaning up their changes.
* RBAC covering.
* Replacing \" in produced XML by '.

Jira: https://issues.redhat.com/browse/WFCORE-4758
Signed-off-by: Emmanuel Hugonnet <[email protected]>
  • Loading branch information
ehsavoie committed Dec 18, 2023
1 parent b14c563 commit 4295603
Show file tree
Hide file tree
Showing 28 changed files with 1,330 additions and 452 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ public class ModelDescriptionConstants {
public static final String READ_CHILDREN_RESOURCES_OPERATION = "read-children-resources";
public static final String READ_CONFIG_AS_FEATURES_OPERATION = "read-config-as-features";
public static final String READ_CONFIG_AS_XML_OPERATION = "read-config-as-xml";
public static final String READ_CONFIG_AS_XML_FILE_OPERATION = "read-config-as-xml-file";
public static final String READ_CONTENT = "read-content";
public static final String READ_FEATURE_DESCRIPTION_OPERATION = "read-feature-description";
public static final String READ_ONLY = "read-only";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.jboss.as.controller.operations.common;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.logging.ControllerLogger.MGMT_OP_LOGGER;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.access.Action;
import org.jboss.as.controller.access.AuthorizationResult;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.logging.ControllerLogger;
import org.jboss.as.controller.persistence.ConfigurationPersistenceException;
import org.jboss.as.controller.persistence.ConfigurationPersister;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;

/**
*
* @author Emmanuel Hugonnet (c) 2021 Red Hat, Inc.
*/
public abstract class AbstractXmlMarshallingHandler implements OperationStepHandler {

private static final Set<Action.ActionEffect> EFFECTS
= Collections.unmodifiableSet(EnumSet.of(Action.ActionEffect.ADDRESS, Action.ActionEffect.READ_CONFIG));

private final ConfigurationPersister configPersister;

protected AbstractXmlMarshallingHandler(final ConfigurationPersister configPersister) {
this.configPersister = configPersister;
}

@Override
public void execute(OperationContext context, ModelNode operation) {
final PathAddress pa = context.getCurrentAddress();

AuthorizationResult authResult = context.authorize(operation, EFFECTS);
if (authResult.getDecision() != AuthorizationResult.Decision.PERMIT) {
throw ControllerLogger.ROOT_LOGGER.unauthorized(operation.require(OP).asString(), pa, authResult.getExplanation());
}

final Resource resource = context.readResourceFromRoot(getBaseAddress());
// Get the model recursively
final ModelNode model = Resource.Tools.readModel(resource);
try {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedOutputStream output = new BufferedOutputStream(baos)) {
configPersister.marshallAsXml(model, output);
attachResult(context, baos);
}
} catch (RuntimeException e) {
throw e;
} catch (IOException | ConfigurationPersistenceException e) {
// Log this
MGMT_OP_LOGGER.failedExecutingOperation(e, operation.require(ModelDescriptionConstants.OP), pa);
context.getFailureDescription().set(e.toString());
}
}

protected abstract void attachResult(OperationContext context, ByteArrayOutputStream baos);

protected PathAddress getBaseAddress() {
return PathAddress.EMPTY_ADDRESS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.jboss.as.controller.operations.common;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UUID;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleOperationDefinition;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.descriptions.common.ControllerResolver;
import org.jboss.as.controller.persistence.ConfigurationPersister;
import org.jboss.as.version.Stability;
import org.jboss.dmr.ModelType;

/**
*
* A {@link org.jboss.as.controller.OperationStepHandler} that can output a model in XML file.
*
* @author Emmanuel Hugonnet (c) 2021 Red Hat, Inc.
*/
public class XmlFileMarshallingHandler extends AbstractXmlMarshallingHandler {

private static final String OPERATION_NAME = ModelDescriptionConstants.READ_CONFIG_AS_XML_FILE_OPERATION;

public static final SimpleOperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME, ControllerResolver.getResolver())
.addAccessConstraint(SensitiveTargetAccessConstraintDefinition.READ_WHOLE_CONFIG)
.setReplyParameters(new SimpleAttributeDefinitionBuilder(UUID, ModelType.STRING, false).build())
.setReadOnly()
.setRuntimeOnly()
.setStability(Stability.COMMUNITY)
.build();

public XmlFileMarshallingHandler(final ConfigurationPersister configPersister) {
super(configPersister);
}

@Override
protected void attachResult(OperationContext context, ByteArrayOutputStream baos) {
String uuid = context.attachResultStream("application/xml", new ByteArrayInputStream(baos.toByteArray()));
context.getResult().get(UUID).set(uuid);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,103 +2,43 @@
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.jboss.as.controller.operations.common;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.logging.ControllerLogger.MGMT_OP_LOGGER;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;

import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.SimpleOperationDefinition;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.access.Action;
import org.jboss.as.controller.access.AuthorizationResult;
import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.descriptions.common.ControllerResolver;
import org.jboss.as.controller.logging.ControllerLogger;
import org.jboss.as.controller.persistence.ConfigurationPersister;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;

/**
* A {@link org.jboss.as.controller.OperationStepHandler} that can output a model in XML form
*
* @author Brian Stansberry (c) 2011 Red Hat Inc.
*/
public class XmlMarshallingHandler implements OperationStepHandler{
public class XmlMarshallingHandler extends AbstractXmlMarshallingHandler {

private static final String OPERATION_NAME = ModelDescriptionConstants.READ_CONFIG_AS_XML_OPERATION;

public static final SimpleOperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME,ControllerResolver.getResolver())
public static final SimpleOperationDefinition DEFINITION = new SimpleOperationDefinitionBuilder(OPERATION_NAME, ControllerResolver.getResolver())
.addAccessConstraint(SensitiveTargetAccessConstraintDefinition.READ_WHOLE_CONFIG)
.setReplyType(ModelType.STRING)
.setReadOnly()
.setRuntimeOnly()
.build();

private static final Set<Action.ActionEffect> EFFECTS =
Collections.unmodifiableSet(EnumSet.of(Action.ActionEffect.ADDRESS, Action.ActionEffect.READ_CONFIG));

private final ConfigurationPersister configPersister;

public XmlMarshallingHandler(final ConfigurationPersister configPersister) {
this.configPersister = configPersister;
super(configPersister);
}

@Override
public void execute(OperationContext context, ModelNode operation) {
final PathAddress pa = context.getCurrentAddress();

AuthorizationResult authResult = context.authorize(operation, EFFECTS);
if (authResult.getDecision() != AuthorizationResult.Decision.PERMIT) {
throw ControllerLogger.ROOT_LOGGER.unauthorized(operation.require(OP).asString(), pa, authResult.getExplanation());
}

final Resource resource = context.readResourceFromRoot(getBaseAddress());
// Get the model recursively
final ModelNode model = Resource.Tools.readModel(resource);
try {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
BufferedOutputStream output = new BufferedOutputStream(baos);
configPersister.marshallAsXml(model, output);
output.close();
baos.close();
} finally {
safeClose(baos);
}
String xml = new String(baos.toByteArray(), StandardCharsets.UTF_8);
context.getResult().set(xml);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
// Log this
MGMT_OP_LOGGER.failedExecutingOperation(e, operation.require(ModelDescriptionConstants.OP), pa);
context.getFailureDescription().set(e.toString());
}
}

protected PathAddress getBaseAddress() {
return PathAddress.EMPTY_ADDRESS;
}

private void safeClose(final Closeable closeable) {
if (closeable != null) try {
closeable.close();
} catch (Throwable t) {
MGMT_OP_LOGGER.failedToCloseResource(t, closeable);
}
protected void attachResult(OperationContext context, ByteArrayOutputStream baos) {
String xml = new String(baos.toByteArray(), StandardCharsets.UTF_8);
context.getResult().set(xml.replace('\"', '\''));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -105,7 +106,7 @@ public List<ModelNode> load() throws ConfigurationPersistenceException {
XMLStreamReader streamReader = null;
try {
input = new BufferedInputStream(new FileInputStream(fileName));
streamReader = XMLInputFactoryUtil.create().createXMLStreamReader(input);
streamReader = XMLInputFactoryUtil.create().createXMLStreamReader(input, StandardCharsets.UTF_8.toString());
mapper.parseDocument(updates, streamReader);
} catch (XMLStreamException e) {
final boolean reported = reportValidationError(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -630,8 +630,14 @@ root.composite.reply=A composite operation response that consists of all the ste
# Common Operations
read-config-as-xml=Reads the current configuration and returns it in XML format.
read-config-as-xml.response=The XML form of the persistent configuration.
read-config-as-xml.deprecated=Use the operation 'read-config-as-xml-file' instead.
read-config-as-xml-file=Reads the current configuration and returns it as a file in XML format.
read-config-as-xml-file.response=The file if the XML form of the persistent configuration.
read-config-as-xml-file.reply.uuid= The uuid of the attachement for the file.
add-deployer-chains=Adds deployer chain



#Publish
publish.publish-configuration=Publish the configuration to some external location.
publish.publish-configuration.location=The location where the configuration is going to be published. This should be a valid remote git repository (either URL or alias).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.jboss.as.controller.operations.common.SnapshotListHandler;
import org.jboss.as.controller.operations.common.SnapshotTakeHandler;
import org.jboss.as.controller.operations.common.ValidateAddressOperationHandler;
import org.jboss.as.controller.operations.common.XmlFileMarshallingHandler;
import org.jboss.as.controller.operations.common.XmlMarshallingHandler;
import org.jboss.as.controller.operations.global.GlobalInstallationReportHandler;
import org.jboss.as.controller.operations.global.ReadConfigAsFeaturesOperationHandler;
Expand Down Expand Up @@ -249,6 +250,7 @@ public void registerOperations(ManagementResourceRegistration resourceRegistrati
// Other root resource operations
XmlMarshallingHandler xmh = new XmlMarshallingHandler(configurationPersister);
resourceRegistration.registerOperationHandler(XmlMarshallingHandler.DEFINITION, xmh);
resourceRegistration.registerOperationHandler(XmlFileMarshallingHandler.DEFINITION, new XmlFileMarshallingHandler(configurationPersister));

resourceRegistration.registerOperationHandler(NamespaceAddHandler.DEFINITION, NamespaceAddHandler.INSTANCE);
resourceRegistration.registerOperationHandler(NamespaceRemoveHandler.DEFINITION, NamespaceRemoveHandler.INSTANCE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DOMAIN_ORGANIZATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
import static org.jboss.as.controller.services.path.PathResourceDefinition.PATH_CAPABILITY;

import org.jboss.as.controller.BootErrorCollector;
import org.jboss.as.controller.ControlledProcessState;
Expand Down Expand Up @@ -55,6 +54,10 @@
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.services.path.PathManagerService;
import org.jboss.as.controller.services.path.PathResourceDefinition;

import static org.jboss.as.controller.services.path.PathResourceDefinition.PATH_CAPABILITY;

import org.jboss.as.controller.operations.common.XmlFileMarshallingHandler;
import org.jboss.as.domain.controller.DomainController;
import org.jboss.as.domain.controller.operations.DomainServerLifecycleHandlers;
import org.jboss.as.domain.controller.operations.HostProcessReloadHandler;
Expand All @@ -77,6 +80,7 @@
import org.jboss.as.host.controller.operations.HostShutdownHandler;
import org.jboss.as.host.controller.operations.HostSpecifiedInterfaceAddHandler;
import org.jboss.as.host.controller.operations.HostSpecifiedInterfaceRemoveHandler;
import org.jboss.as.host.controller.operations.HostXmlFileMarshallingHandler;
import org.jboss.as.host.controller.operations.HostXmlMarshallingHandler;
import org.jboss.as.host.controller.operations.InstallationReportHandler;
import org.jboss.as.host.controller.operations.IsMasterHandler;
Expand Down Expand Up @@ -345,8 +349,8 @@ public void registerOperations(ManagementResourceRegistration hostRegistration)
hostRegistration.registerOperationHandler(CleanObsoleteContentHandler.DEFINITION, CleanObsoleteContentHandler.createOperation(contentRepository));
hostRegistration.registerOperationHandler(WriteConfigHandler.DEFINITION, WriteConfigHandler.INSTANCE);

XmlMarshallingHandler xmh = new HostXmlMarshallingHandler(configurationPersister.getHostPersister(), hostControllerInfo);
hostRegistration.registerOperationHandler(XmlMarshallingHandler.DEFINITION, xmh);
hostRegistration.registerOperationHandler(XmlMarshallingHandler.DEFINITION, new HostXmlMarshallingHandler(configurationPersister.getHostPersister(), hostControllerInfo));
hostRegistration.registerOperationHandler(XmlFileMarshallingHandler.DEFINITION, new HostXmlFileMarshallingHandler(configurationPersister.getHostPersister(), hostControllerInfo));


StartServersHandler ssh = new StartServersHandler(environment, serverInventory, runningModeControl);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright The WildFly Authors
* SPDX-License-Identifier: Apache-2.0
*/

package org.jboss.as.host.controller.operations;

import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.XmlFileMarshallingHandler;
import org.jboss.as.controller.persistence.ConfigurationPersister;
import org.jboss.as.domain.controller.LocalHostControllerInfo;

/**
*
* @author Emmanuel Hugonnet (c) 2021 Red Hat, Inc.
*/
public class HostXmlFileMarshallingHandler extends XmlFileMarshallingHandler {

private final LocalHostControllerInfo hostControllerInfo;

public HostXmlFileMarshallingHandler(final ConfigurationPersister configPersister, final LocalHostControllerInfo hostControllerInfo) {
super(configPersister);
this.hostControllerInfo = hostControllerInfo;
}

@Override
protected PathAddress getBaseAddress() {
return PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.HOST, hostControllerInfo.getLocalHostName()));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.jboss.as.controller.operations.common.SnapshotTakeHandler;
import org.jboss.as.controller.operations.common.ValidateAddressOperationHandler;
import org.jboss.as.controller.operations.common.ValidateOperationHandler;
import org.jboss.as.controller.operations.common.XmlFileMarshallingHandler;
import org.jboss.as.controller.operations.common.XmlMarshallingHandler;
import org.jboss.as.controller.operations.global.GlobalInstallationReportHandler;
import org.jboss.as.controller.operations.global.GlobalNotifications;
Expand Down Expand Up @@ -337,6 +338,7 @@ public void registerOperations(ManagementResourceRegistration resourceRegistrati

XmlMarshallingHandler xmh = new XmlMarshallingHandler(extensibleConfigurationPersister);
resourceRegistration.registerOperationHandler(XmlMarshallingHandler.DEFINITION, xmh);
resourceRegistration.registerOperationHandler(XmlFileMarshallingHandler.DEFINITION, new XmlFileMarshallingHandler(extensibleConfigurationPersister));
resourceRegistration.registerOperationHandler(NamespaceAddHandler.DEFINITION, NamespaceAddHandler.INSTANCE);
resourceRegistration.registerOperationHandler(NamespaceRemoveHandler.DEFINITION, NamespaceRemoveHandler.INSTANCE);
resourceRegistration.registerOperationHandler(SchemaLocationAddHandler.DEFINITION, SchemaLocationAddHandler.INSTANCE);
Expand Down
Loading

0 comments on commit 4295603

Please sign in to comment.