Skip to content

Commit

Permalink
WFLY-11807 Auto-configure external address/port for FD_SOCK protocol …
Browse files Browse the repository at this point in the history
…based on socket binding's client mappings.
  • Loading branch information
pferraro committed Mar 29, 2019
1 parent 6c5d487 commit 6f5dddf
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 28 deletions.
Expand Up @@ -36,9 +36,10 @@ public enum JGroupsModel implements Model {
VERSION_4_0_0(4, 0, 0), // WildFly 10, EAP 7.0 VERSION_4_0_0(4, 0, 0), // WildFly 10, EAP 7.0
VERSION_4_1_0(4, 1, 0), // WildFly 10.1 VERSION_4_1_0(4, 1, 0), // WildFly 10.1
VERSION_5_0_0(5, 0, 0), // WildFly 11, EAP 7.1 VERSION_5_0_0(5, 0, 0), // WildFly 11, EAP 7.1
VERSION_6_0_0(6, 0, 0), // WildFly 12-15, EAP 7.2 VERSION_6_0_0(6, 0, 0), // WildFly 12-16, EAP 7.2
VERSION_7_0_0(7, 0, 0), // WildFly 17
; ;
static final JGroupsModel CURRENT = VERSION_6_0_0; static final JGroupsModel CURRENT = VERSION_7_0_0;


private final ModelVersion version; private final ModelVersion version;


Expand Down
Expand Up @@ -32,7 +32,6 @@
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;


import org.jboss.as.clustering.controller.Attribute; import org.jboss.as.clustering.controller.Attribute;
import org.jboss.as.clustering.controller.Operations;
import org.jboss.as.controller.AttributeDefinition; import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.AttributeParser; import org.jboss.as.controller.AttributeParser;
import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.PathAddress;
Expand Down Expand Up @@ -635,15 +634,7 @@ private void parseProtocolAttribute(XMLExtendedStreamReader reader, int index, M
break; break;
} }
case SOCKET_BINDING: { case SOCKET_BINDING: {
String protocol = Operations.getPathAddress(operation).getLastElement().getValue(); readAttribute(reader, index, operation, GenericProtocolResourceDefinition.DeprecatedAttribute.SOCKET_BINDING);
Attribute socketBindingAttribute = GenericProtocolResourceDefinition.DeprecatedAttribute.SOCKET_BINDING;
for (ProtocolRegistration.MulticastProtocol multicastProtocol : EnumSet.allOf(ProtocolRegistration.MulticastProtocol.class)) {
if (protocol.equals(multicastProtocol.name())) {
socketBindingAttribute = SocketBindingProtocolResourceDefinition.Attribute.SOCKET_BINDING;
break;
}
}
readAttribute(reader, index, operation, socketBindingAttribute);
break; break;
} }
case DATA_SOURCE: { case DATA_SOURCE: {
Expand Down
Expand Up @@ -117,7 +117,7 @@ private static void writeTransport(XMLExtendedStreamWriter writer, Property prop
} }


private static void writeProtocol(XMLExtendedStreamWriter writer, Property property) throws XMLStreamException { private static void writeProtocol(XMLExtendedStreamWriter writer, Property property) throws XMLStreamException {
writer.writeStartElement(XMLElement.forProtocolName(property.getName()).getLocalName()); writer.writeStartElement(XMLElement.forProtocolName(property).getLocalName());
writeProtocolAttributes(writer, property); writeProtocolAttributes(writer, property);
writeElement(writer, property.getValue(), AbstractProtocolResourceDefinition.Attribute.PROPERTIES); writeElement(writer, property.getValue(), AbstractProtocolResourceDefinition.Attribute.PROPERTIES);
writer.writeEndElement(); writer.writeEndElement();
Expand All @@ -135,6 +135,8 @@ private static void writeProtocolAttributes(XMLExtendedStreamWriter writer, Prop
String protocol = property.getName(); String protocol = property.getName();
if (containsName(ProtocolRegistration.MulticastProtocol.class, protocol)) { if (containsName(ProtocolRegistration.MulticastProtocol.class, protocol)) {
writeAttributes(writer, property.getValue(), SocketBindingProtocolResourceDefinition.Attribute.class); writeAttributes(writer, property.getValue(), SocketBindingProtocolResourceDefinition.Attribute.class);
} else if (containsName(ProtocolRegistration.SocketProtocol.class, protocol)) {
writeAttributes(writer, property.getValue(), OptionalSocketBindingProtocolResourceDefinition.Attribute.class);
} else if (containsName(ProtocolRegistration.JdbcProtocol.class, protocol)) { } else if (containsName(ProtocolRegistration.JdbcProtocol.class, protocol)) {
writeAttributes(writer, property.getValue(), JDBCProtocolResourceDefinition.Attribute.class); writeAttributes(writer, property.getValue(), JDBCProtocolResourceDefinition.Attribute.class);
} else if (containsName(ProtocolRegistration.EncryptProtocol.class, protocol)) { } else if (containsName(ProtocolRegistration.EncryptProtocol.class, protocol)) {
Expand Down
Expand Up @@ -22,6 +22,8 @@


package org.jboss.as.clustering.jgroups.subsystem; package org.jboss.as.clustering.jgroups.subsystem;


import static org.jboss.as.clustering.jgroups.subsystem.SocketBindingProtocolResourceDefinition.Attribute.SOCKET_BINDING;

import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;


Expand Down Expand Up @@ -56,7 +58,7 @@ public <T> ServiceBuilder<T> register(ServiceBuilder<T> builder) {


@Override @Override
public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException { public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException {
String bindingName = SocketBindingProtocolResourceDefinition.Attribute.SOCKET_BINDING.resolveModelAttribute(context, model).asString(); String bindingName = SOCKET_BINDING.resolveModelAttribute(context, model).asString();
this.binding = new ServiceSupplierDependency<>(CommonUnaryRequirement.SOCKET_BINDING.getServiceName(context, bindingName)); this.binding = new ServiceSupplierDependency<>(CommonUnaryRequirement.SOCKET_BINDING.getServiceName(context, bindingName));
return super.configure(context, model); return super.configure(context, model);
} }
Expand Down
@@ -0,0 +1,92 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.jgroups.subsystem;

import java.util.function.UnaryOperator;

import org.jboss.as.clustering.controller.CapabilityReference;
import org.jboss.as.clustering.controller.CommonUnaryRequirement;
import org.jboss.as.clustering.controller.ResourceDescriptor;
import org.jboss.as.clustering.controller.ResourceServiceConfiguratorFactory;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.access.management.SensitiveTargetAccessConstraintDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.transform.description.ResourceTransformationDescriptionBuilder;
import org.jboss.dmr.ModelType;

/**
* Resource definition override for protocols that have an optional socket-binding.
* @author Paul Ferraro
*/
public class OptionalSocketBindingProtocolResourceDefinition extends ProtocolResourceDefinition {

enum Attribute implements org.jboss.as.clustering.controller.Attribute, UnaryOperator<SimpleAttributeDefinitionBuilder> {
SOCKET_BINDING(ModelDescriptionConstants.SOCKET_BINDING, ModelType.STRING) {
@Override
public SimpleAttributeDefinitionBuilder apply(SimpleAttributeDefinitionBuilder builder) {
return builder.setAccessConstraints(SensitiveTargetAccessConstraintDefinition.SOCKET_BINDING_REF)
.setCapabilityReference(new CapabilityReference(Capability.PROTOCOL, CommonUnaryRequirement.SOCKET_BINDING))
;
}
},
;
private final AttributeDefinition definition;

Attribute(String name, ModelType type) {
this.definition = this.apply(new SimpleAttributeDefinitionBuilder(name, type)
.setRequired(false)
.setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
).build();
}

@Override
public AttributeDefinition getDefinition() {
return this.definition;
}
}

static void addTransformations(ModelVersion version, ResourceTransformationDescriptionBuilder builder) {

ProtocolResourceDefinition.addTransformations(version, builder);
}

private static class ResourceDescriptorConfigurator implements UnaryOperator<ResourceDescriptor> {
private final UnaryOperator<ResourceDescriptor> configurator;

ResourceDescriptorConfigurator(UnaryOperator<ResourceDescriptor> configurator) {
this.configurator = configurator;
}

@Override
public ResourceDescriptor apply(ResourceDescriptor descriptor) {
return this.configurator.apply(descriptor).addAttributes(Attribute.class);
}
}

OptionalSocketBindingProtocolResourceDefinition(String name, UnaryOperator<ResourceDescriptor> configurator, ResourceServiceConfiguratorFactory serviceConfiguratorFactory, ResourceServiceConfiguratorFactory parentServiceConfiguratorFactory) {
super(pathElement(name), new ResourceDescriptorConfigurator(configurator), serviceConfiguratorFactory, parentServiceConfiguratorFactory);
}
}
Expand Up @@ -84,6 +84,10 @@ enum MulticastProtocol {
MPING; MPING;
} }


enum SocketProtocol {
FD_SOCK;
}

enum LegacyProtocol { enum LegacyProtocol {
MERGE2(MERGE3.class, JGroupsModel.VERSION_6_0_0), MERGE2(MERGE3.class, JGroupsModel.VERSION_6_0_0),
NAKACK("pbcast.NAKACK", NAKACK2.class, JGroupsModel.VERSION_6_0_0), NAKACK("pbcast.NAKACK", NAKACK2.class, JGroupsModel.VERSION_6_0_0),
Expand All @@ -107,6 +111,13 @@ enum LegacyProtocol {
static void buildTransformation(ModelVersion version, ResourceTransformationDescriptionBuilder parent) { static void buildTransformation(ModelVersion version, ResourceTransformationDescriptionBuilder parent) {
ProtocolResourceDefinition.addTransformations(version, parent.addChildResource(ProtocolResourceDefinition.WILDCARD_PATH)); ProtocolResourceDefinition.addTransformations(version, parent.addChildResource(ProtocolResourceDefinition.WILDCARD_PATH));


for (SocketProtocol protocol : EnumSet.allOf(SocketProtocol.class)) {
PathElement path = ProtocolResourceDefinition.pathElement(protocol.name());
if (!JGroupsModel.VERSION_7_0_0.requiresTransformation(version)) {
OptionalSocketBindingProtocolResourceDefinition.addTransformations(version, parent.addChildResource(path));
}
}

for (MulticastProtocol protocol : EnumSet.allOf(MulticastProtocol.class)) { for (MulticastProtocol protocol : EnumSet.allOf(MulticastProtocol.class)) {
PathElement path = ProtocolResourceDefinition.pathElement(protocol.name()); PathElement path = ProtocolResourceDefinition.pathElement(protocol.name());
if (!JGroupsModel.VERSION_5_0_0.requiresTransformation(version)) { if (!JGroupsModel.VERSION_5_0_0.requiresTransformation(version)) {
Expand Down Expand Up @@ -182,6 +193,9 @@ public void register(ManagementResourceRegistration registration) {
new GenericProtocolResourceDefinition(this.configurator, this.parentServiceConfiguratorFactory).register(registration); new GenericProtocolResourceDefinition(this.configurator, this.parentServiceConfiguratorFactory).register(registration);


// Override definitions for protocol types // Override definitions for protocol types
for (SocketProtocol protocol : EnumSet.allOf(SocketProtocol.class)) {
new OptionalSocketBindingProtocolResourceDefinition(protocol.name(), this.configurator, SocketProtocolConfigurationServiceConfigurator::new, this.parentServiceConfiguratorFactory).register(registration);
}
for (MulticastProtocol protocol : EnumSet.allOf(MulticastProtocol.class)) { for (MulticastProtocol protocol : EnumSet.allOf(MulticastProtocol.class)) {
new SocketBindingProtocolResourceDefinition(protocol.name(), this.configurator, MulticastSocketProtocolConfigurationServiceConfigurator::new, this.parentServiceConfiguratorFactory).register(registration); new SocketBindingProtocolResourceDefinition(protocol.name(), this.configurator, MulticastSocketProtocolConfigurationServiceConfigurator::new, this.parentServiceConfiguratorFactory).register(registration);
} }
Expand Down
@@ -0,0 +1,97 @@
/*
* JBoss, Home of Professional Open Source.
* Copyright 2019, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.as.clustering.jgroups.subsystem;

import static org.jboss.as.clustering.jgroups.subsystem.OptionalSocketBindingProtocolResourceDefinition.Attribute.SOCKET_BINDING;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.jboss.as.clustering.controller.CommonUnaryRequirement;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.network.ClientMapping;
import org.jboss.as.network.SocketBinding;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceBuilder;
import org.jgroups.protocols.FD_SOCK;
import org.wildfly.clustering.service.ServiceConfigurator;
import org.wildfly.clustering.service.ServiceSupplierDependency;
import org.wildfly.clustering.service.SimpleSupplierDependency;
import org.wildfly.clustering.service.SupplierDependency;

/**
* Configures a service that provides a FD_SOCK protocol.
* @author Paul Ferraro
*/
public class SocketProtocolConfigurationServiceConfigurator extends ProtocolConfigurationServiceConfigurator<FD_SOCK> {

private volatile SupplierDependency<SocketBinding> binding;

public SocketProtocolConfigurationServiceConfigurator(PathAddress address) {
super(address);
}

@Override
public <T> ServiceBuilder<T> register(ServiceBuilder<T> builder) {
return super.register(this.binding.register(builder));
}

@Override
public ServiceConfigurator configure(OperationContext context, ModelNode model) throws OperationFailedException {
String bindingName = SOCKET_BINDING.resolveModelAttribute(context, model).asString(null);
this.binding = (bindingName != null) ? new ServiceSupplierDependency<>(CommonUnaryRequirement.SOCKET_BINDING.getServiceName(context, bindingName)) : new SimpleSupplierDependency<>(null);
return super.configure(context, model);
}

@Override
public Map<String, SocketBinding> getSocketBindings() {
return Collections.singletonMap("jgroups.fd_sock.srv_sock", this.binding.get());
}

@Override
public void accept(FD_SOCK protocol) {
// If binding is undefined, protocol will use bind address of transport and a random ephemeral port
SocketBinding binding = this.binding.get();
if (binding != null) {
protocol.setValue("bind_addr", binding.getAddress());
protocol.setValue("start_port", binding.getPort());

List<ClientMapping> clientMappings = binding.getClientMappings();
if (!clientMappings.isEmpty()) {
// JGroups cannot select a client mapping based on the source address, so just use the first one
ClientMapping mapping = clientMappings.get(0);
try {
this.setValue(protocol, "external_addr", InetAddress.getByName(mapping.getDestinationAddress()));
this.setValue(protocol, "external_port", mapping.getDestinationPort());
} catch (UnknownHostException e) {
throw new IllegalArgumentException(e);
}
}
}
}
}
Expand Up @@ -24,10 +24,13 @@
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Function;


import org.jboss.as.clustering.controller.Attribute; import org.jboss.as.clustering.controller.Attribute;
import org.jboss.as.controller.PathElement; import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants; import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;


/** /**
* @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a> * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
Expand Down Expand Up @@ -90,8 +93,28 @@ public String toString() {
return this.name; return this.name;
} }


private enum XMLElementFunction implements Function<ModelNode, XMLElement> {
PROTOCOL(XMLElement.PROTOCOL),
SOCKET_PROTOCOL(XMLElement.SOCKET_PROTOCOL),
JDBC_PROTOCOL(XMLElement.JDBC_PROTOCOL),
ENCRYPT_PROTOCOL(XMLElement.ENCRYPT_PROTOCOL),
SOCKET_DISCOVERY_PROTOCOL(XMLElement.SOCKET_DISCOVERY_PROTOCOL),
AUTH_PROTOCOL(XMLElement.AUTH_PROTOCOL),
;
private final XMLElement element;

XMLElementFunction(XMLElement element) {
this.element = element;
}

@Override
public XMLElement apply(ModelNode ignored) {
return this.element;
}
}

private static final Map<String, XMLElement> elements = new HashMap<>(); private static final Map<String, XMLElement> elements = new HashMap<>();
private static final Map<String, XMLElement> protocols = new HashMap<>(); private static final Map<String, Function<ModelNode, XMLElement>> protocols = new HashMap<>();
private static final Map<String, XMLElement> tokens = new HashMap<>(); private static final Map<String, XMLElement> tokens = new HashMap<>();


static { static {
Expand All @@ -102,20 +125,30 @@ public String toString() {
} }
} }


Function<ModelNode, XMLElement> function = new Function<ModelNode, XMLElement>() {
@Override
public XMLElement apply(ModelNode model) {
// Use socket-protocol element only if optional socket-binding was defined
return model.hasDefined(OptionalSocketBindingProtocolResourceDefinition.Attribute.SOCKET_BINDING.getName()) ? XMLElement.SOCKET_PROTOCOL : XMLElement.PROTOCOL;
}
};
for (ProtocolRegistration.SocketProtocol protocol : EnumSet.allOf(ProtocolRegistration.SocketProtocol.class)) {
protocols.put(protocol.name(), function);
}
for (ProtocolRegistration.MulticastProtocol protocol : EnumSet.allOf(ProtocolRegistration.MulticastProtocol.class)) { for (ProtocolRegistration.MulticastProtocol protocol : EnumSet.allOf(ProtocolRegistration.MulticastProtocol.class)) {
protocols.put(protocol.name(), XMLElement.SOCKET_PROTOCOL); protocols.put(protocol.name(), XMLElementFunction.SOCKET_PROTOCOL);
} }
for (ProtocolRegistration.JdbcProtocol protocol : EnumSet.allOf(ProtocolRegistration.JdbcProtocol.class)) { for (ProtocolRegistration.JdbcProtocol protocol : EnumSet.allOf(ProtocolRegistration.JdbcProtocol.class)) {
protocols.put(protocol.name(), XMLElement.JDBC_PROTOCOL); protocols.put(protocol.name(), XMLElementFunction.JDBC_PROTOCOL);
} }
for (ProtocolRegistration.EncryptProtocol protocol : EnumSet.allOf(ProtocolRegistration.EncryptProtocol.class)) { for (ProtocolRegistration.EncryptProtocol protocol : EnumSet.allOf(ProtocolRegistration.EncryptProtocol.class)) {
protocols.put(protocol.name(), XMLElement.ENCRYPT_PROTOCOL); protocols.put(protocol.name(), XMLElementFunction.ENCRYPT_PROTOCOL);
} }
for (ProtocolRegistration.InitialHostsProtocol protocol : EnumSet.allOf(ProtocolRegistration.InitialHostsProtocol.class)) { for (ProtocolRegistration.InitialHostsProtocol protocol : EnumSet.allOf(ProtocolRegistration.InitialHostsProtocol.class)) {
protocols.put(protocol.name(), XMLElement.SOCKET_DISCOVERY_PROTOCOL); protocols.put(protocol.name(), XMLElementFunction.SOCKET_DISCOVERY_PROTOCOL);
} }
for (ProtocolRegistration.AuthProtocol protocol : EnumSet.allOf(ProtocolRegistration.AuthProtocol.class)) { for (ProtocolRegistration.AuthProtocol protocol : EnumSet.allOf(ProtocolRegistration.AuthProtocol.class)) {
protocols.put(protocol.name(), XMLElement.AUTH_PROTOCOL); protocols.put(protocol.name(), XMLElementFunction.AUTH_PROTOCOL);
} }


tokens.put(PlainAuthTokenResourceDefinition.PATH.getValue(), XMLElement.PLAIN_TOKEN); tokens.put(PlainAuthTokenResourceDefinition.PATH.getValue(), XMLElement.PLAIN_TOKEN);
Expand All @@ -124,13 +157,11 @@ public String toString() {
} }


public static XMLElement forName(String localName) { public static XMLElement forName(String localName) {
XMLElement element = elements.get(localName); return elements.getOrDefault(localName, UNKNOWN);
return (element != null) ? element : UNKNOWN;
} }


public static XMLElement forProtocolName(String protocol) { public static XMLElement forProtocolName(Property protocol) {
XMLElement element = protocols.get(protocol); return protocols.getOrDefault(protocol.getName(), XMLElementFunction.PROTOCOL).apply(protocol.getValue());
return (element != null) ? element : XMLElement.PROTOCOL;
} }


public static XMLElement forAuthTokenName(String token) { public static XMLElement forAuthTokenName(String token) {
Expand Down

0 comments on commit 6f5dddf

Please sign in to comment.