Skip to content

Commit

Permalink
WFLY-10489 Rename mod_cluster Tomcat/JBossWeb-era "connector" attribu…
Browse files Browse the repository at this point in the history
…te to listener
  • Loading branch information
rhusar committed Aug 15, 2018
1 parent 2c9f90e commit 3e1eb87
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 33 deletions.
Expand Up @@ -4,7 +4,7 @@
<feature spec="subsystem.modcluster.proxy"> <feature spec="subsystem.modcluster.proxy">
<param name="proxy" value="default"/> <param name="proxy" value="default"/>
<param name="advertise-socket" value="modcluster"/> <param name="advertise-socket" value="modcluster"/>
<param name="connector" value="ajp"/> <param name="listener" value="ajp"/>
<feature spec="subsystem.modcluster.proxy.dynamic-load-provider.configuration"> <feature spec="subsystem.modcluster.proxy.dynamic-load-provider.configuration">
<feature spec="subsystem.modcluster.proxy.dynamic-load-provider.configuration.load-metric"> <feature spec="subsystem.modcluster.proxy.dynamic-load-provider.configuration.load-metric">
<param name="load-metric" value="cpu"/> <param name="load-metric" value="cpu"/>
Expand Down
Expand Up @@ -33,5 +33,5 @@
* @author Radoslav Husar * @author Radoslav Husar
*/ */
public interface ContainerEventHandlerAdapterServiceConfiguratorProvider { public interface ContainerEventHandlerAdapterServiceConfiguratorProvider {
CapabilityServiceConfigurator getServiceConfigurator(String adapterName, String connector, Duration statusInterval); CapabilityServiceConfigurator getServiceConfigurator(String adapterName, String listenerName, Duration statusInterval);
} }
Expand Up @@ -23,7 +23,7 @@
package org.wildfly.extension.mod_cluster; package org.wildfly.extension.mod_cluster;


import static org.wildfly.extension.mod_cluster.ModClusterLogger.ROOT_LOGGER; import static org.wildfly.extension.mod_cluster.ModClusterLogger.ROOT_LOGGER;
import static org.wildfly.extension.mod_cluster.ProxyConfigurationResourceDefinition.Attribute.CONNECTOR; import static org.wildfly.extension.mod_cluster.ProxyConfigurationResourceDefinition.Attribute.LISTENER;
import static org.wildfly.extension.mod_cluster.ProxyConfigurationResourceDefinition.Attribute.STATUS_INTERVAL; import static org.wildfly.extension.mod_cluster.ProxyConfigurationResourceDefinition.Attribute.STATUS_INTERVAL;


import java.time.Duration; import java.time.Duration;
Expand Down Expand Up @@ -83,14 +83,14 @@ public void installServices(OperationContext context, ModelNode model) throws Op
LoadBalanceFactorProvider loadProvider = this.getLoadProvider(proxyName, metrics, context, proxyModel); LoadBalanceFactorProvider loadProvider = this.getLoadProvider(proxyName, metrics, context, proxyModel);
enabledMetrics.addAll(metrics); enabledMetrics.addAll(metrics);


String connector = CONNECTOR.resolveModelAttribute(context, proxyModel).asString(); String listenerName = LISTENER.resolveModelAttribute(context, proxyModel).asString();
int statusInterval = STATUS_INTERVAL.resolveModelAttribute(context, proxyModel).asInt(); int statusInterval = STATUS_INTERVAL.resolveModelAttribute(context, proxyModel).asInt();


new ContainerEventHandlerServiceConfigurator(proxyAddress, loadProvider).build(target).install(); new ContainerEventHandlerServiceConfigurator(proxyAddress, loadProvider).build(target).install();


// Install services for web container integration // Install services for web container integration
for (ContainerEventHandlerAdapterServiceConfiguratorProvider provider : ServiceLoader.load(ContainerEventHandlerAdapterServiceConfiguratorProvider.class, ContainerEventHandlerAdapterServiceConfiguratorProvider.class.getClassLoader())) { for (ContainerEventHandlerAdapterServiceConfiguratorProvider provider : ServiceLoader.load(ContainerEventHandlerAdapterServiceConfiguratorProvider.class, ContainerEventHandlerAdapterServiceConfiguratorProvider.class.getClassLoader())) {
provider.getServiceConfigurator(proxyName, connector, Duration.ofSeconds(statusInterval)).configure(context).build(target).setInitialMode(Mode.PASSIVE).install(); provider.getServiceConfigurator(proxyName, listenerName, Duration.ofSeconds(statusInterval)).configure(context).build(target).setInitialMode(Mode.PASSIVE).install();
} }
} }


Expand Down
Expand Up @@ -197,9 +197,11 @@ private void parseProxy(XMLExtendedStreamReader reader, List<ModelNode> list, Pa
} }
} }
case CONNECTOR: { case CONNECTOR: {
if (schema.since(ModClusterSchema.MODCLUSTER_1_1)) { if (schema.since(ModClusterSchema.MODCLUSTER_1_1) && !schema.since(ModClusterSchema.MODCLUSTER_4_0)) {
readAttribute(reader, i, operation, ProxyConfigurationResourceDefinition.Attribute.CONNECTOR); readAttribute(reader, i, operation, ProxyConfigurationResourceDefinition.Attribute.LISTENER);
break; break;
} else {
throw unexpectedAttribute(reader, i);
} }
} }
// 1.2 // 1.2
Expand Down Expand Up @@ -236,6 +238,12 @@ private void parseProxy(XMLExtendedStreamReader reader, List<ModelNode> list, Pa
break; break;
} }
} }
case LISTENER: {
if (schema.since(ModClusterSchema.MODCLUSTER_4_0)) {
readAttribute(reader, i, operation, ProxyConfigurationResourceDefinition.Attribute.LISTENER);
break;
}
}
default: { default: {
throw unexpectedAttribute(reader, i); throw unexpectedAttribute(reader, i);
} }
Expand All @@ -244,7 +252,7 @@ private void parseProxy(XMLExtendedStreamReader reader, List<ModelNode> list, Pa


if (schema == ModClusterSchema.MODCLUSTER_1_0) { if (schema == ModClusterSchema.MODCLUSTER_1_0) {
// This is a required attribute - so set it to something reasonable // This is a required attribute - so set it to something reasonable
setAttribute(reader, "ajp", operation, ProxyConfigurationResourceDefinition.Attribute.CONNECTOR); setAttribute(reader, "ajp", operation, ProxyConfigurationResourceDefinition.Attribute.LISTENER);
} }


while (reader.hasNext() && reader.nextTag() != END_ELEMENT) { while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
Expand Down
Expand Up @@ -124,15 +124,6 @@ public SimpleAttributeDefinitionBuilder apply(SimpleAttributeDefinitionBuilder b
}, },
AUTO_ENABLE_CONTEXTS("auto-enable-contexts", ModelType.BOOLEAN, new ModelNode(true)), AUTO_ENABLE_CONTEXTS("auto-enable-contexts", ModelType.BOOLEAN, new ModelNode(true)),
BALANCER("balancer", ModelType.STRING, null), BALANCER("balancer", ModelType.STRING, null),
CONNECTOR("connector", ModelType.STRING, null) {
@Override
public SimpleAttributeDefinitionBuilder apply(SimpleAttributeDefinitionBuilder builder) {
return builder
.setCapabilityReference(UNDERTOW_LISTENER_CAPABILITY_NAME)
.setRequired(true)
;
}
},
EXCLUDED_CONTEXTS("excluded-contexts", ModelType.STRING, null), EXCLUDED_CONTEXTS("excluded-contexts", ModelType.STRING, null),
FLUSH_PACKETS("flush-packets", ModelType.BOOLEAN, new ModelNode(false)), FLUSH_PACKETS("flush-packets", ModelType.BOOLEAN, new ModelNode(false)),
FLUSH_WAIT("flush-wait", ModelType.INT, new ModelNode(-1)) { FLUSH_WAIT("flush-wait", ModelType.INT, new ModelNode(-1)) {
Expand All @@ -145,6 +136,15 @@ public SimpleAttributeDefinitionBuilder apply(SimpleAttributeDefinitionBuilder b
; ;
} }
}, },
LISTENER("listener", ModelType.STRING, null) {
@Override
public SimpleAttributeDefinitionBuilder apply(SimpleAttributeDefinitionBuilder builder) {
return builder
.setCapabilityReference(UNDERTOW_LISTENER_CAPABILITY_NAME)
.setRequired(true)
;
}
},
LOAD_BALANCING_GROUP("load-balancing-group", ModelType.STRING, null), LOAD_BALANCING_GROUP("load-balancing-group", ModelType.STRING, null),
MAX_ATTEMPTS("max-attempts", ModelType.INT, new ModelNode(1)) { MAX_ATTEMPTS("max-attempts", ModelType.INT, new ModelNode(1)) {
@Override @Override
Expand Down Expand Up @@ -333,6 +333,23 @@ public SimpleAttributeDefinitionBuilder apply(SimpleAttributeDefinitionBuilder b
} }
} }


enum DeprecatedAttribute implements org.jboss.as.clustering.controller.Attribute {
CONNECTOR("connector", ModelType.STRING, ModClusterModel.VERSION_6_0_0),
SIMPLE_LOAD_PROVIDER("simple-load-provider", ModelType.INT, ModClusterModel.VERSION_6_0_0),
;

private final AttributeDefinition definition;

DeprecatedAttribute(String name, ModelType type, ModClusterModel deprecation) {
this.definition = new SimpleAttributeDefinitionBuilder(name, type, true).setDeprecated(deprecation.getVersion()).build();
}

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

public ProxyConfigurationResourceDefinition() { public ProxyConfigurationResourceDefinition() {
super(WILDCARD_PATH, ModClusterExtension.SUBSYSTEM_RESOLVER.createChildResolver(WILDCARD_PATH)); super(WILDCARD_PATH, ModClusterExtension.SUBSYSTEM_RESOLVER.createChildResolver(WILDCARD_PATH));
} }
Expand All @@ -345,7 +362,9 @@ public ManagementResourceRegistration register(ManagementResourceRegistration pa
ResourceDescriptor descriptor = new ResourceDescriptor(this.getResourceDescriptionResolver()) ResourceDescriptor descriptor = new ResourceDescriptor(this.getResourceDescriptionResolver())
.addAttributes(EnumSet.complementOf(EnumSet.of(Attribute.SSL_CONTEXT))) .addAttributes(EnumSet.complementOf(EnumSet.of(Attribute.SSL_CONTEXT)))
.addExtraParameters(Attribute.SSL_CONTEXT) .addExtraParameters(Attribute.SSL_CONTEXT)
.addCapabilities(Capability.class); .addAlias(DeprecatedAttribute.CONNECTOR, Attribute.LISTENER)
.addCapabilities(Capability.class)
;
registration.registerReadWriteAttribute(Attribute.SSL_CONTEXT.getDefinition(), null, new ReloadRequiredWriteAttributeHandler() { registration.registerReadWriteAttribute(Attribute.SSL_CONTEXT.getDefinition(), null, new ReloadRequiredWriteAttributeHandler() {
@Override @Override
protected void validateUpdatedModel(OperationContext context, Resource model) { protected void validateUpdatedModel(OperationContext context, Resource model) {
Expand Down Expand Up @@ -408,6 +427,12 @@ public PathAddress convertToTargetAddress(PathAddress aliasAddress, AliasContext
static void buildTransformation(ModelVersion version, ResourceTransformationDescriptionBuilder parent) { static void buildTransformation(ModelVersion version, ResourceTransformationDescriptionBuilder parent) {
ResourceTransformationDescriptionBuilder builder = ModClusterModel.VERSION_6_0_0.requiresTransformation(version) ? parent.addChildRedirection(WILDCARD_PATH, new PathAddressTransformer.BasicPathAddressTransformer(LEGACY_PATH), new ProxyConfigurationDynamicDiscardPolicy()) : parent.addChildResource(WILDCARD_PATH); ResourceTransformationDescriptionBuilder builder = ModClusterModel.VERSION_6_0_0.requiresTransformation(version) ? parent.addChildRedirection(WILDCARD_PATH, new PathAddressTransformer.BasicPathAddressTransformer(LEGACY_PATH), new ProxyConfigurationDynamicDiscardPolicy()) : parent.addChildResource(WILDCARD_PATH);


if (ModClusterModel.VERSION_6_0_0.requiresTransformation(version)) {
builder.getAttributeBuilder()
.addRename(Attribute.LISTENER.getDefinition(), DeprecatedAttribute.CONNECTOR.getName())
.end();
}

if (ModClusterModel.VERSION_5_0_0.requiresTransformation(version)) { if (ModClusterModel.VERSION_5_0_0.requiresTransformation(version)) {
builder.getAttributeBuilder() builder.getAttributeBuilder()
.setDiscard(DiscardAttributeChecker.UNDEFINED, Attribute.SSL_CONTEXT.getDefinition()) .setDiscard(DiscardAttributeChecker.UNDEFINED, Attribute.SSL_CONTEXT.getDefinition())
Expand Down
Expand Up @@ -44,11 +44,12 @@ enum XMLAttribute {
ADVERTISE_SOCKET(ProxyConfigurationResourceDefinition.Attribute.ADVERTISE_SOCKET), ADVERTISE_SOCKET(ProxyConfigurationResourceDefinition.Attribute.ADVERTISE_SOCKET),
AUTO_ENABLE_CONTEXTS(ProxyConfigurationResourceDefinition.Attribute.AUTO_ENABLE_CONTEXTS), AUTO_ENABLE_CONTEXTS(ProxyConfigurationResourceDefinition.Attribute.AUTO_ENABLE_CONTEXTS),
BALANCER(ProxyConfigurationResourceDefinition.Attribute.BALANCER), BALANCER(ProxyConfigurationResourceDefinition.Attribute.BALANCER),
CONNECTOR(ProxyConfigurationResourceDefinition.Attribute.CONNECTOR), @Deprecated CONNECTOR(ProxyConfigurationResourceDefinition.DeprecatedAttribute.CONNECTOR),
@Deprecated DOMAIN("domain"),
EXCLUDED_CONTEXTS(ProxyConfigurationResourceDefinition.Attribute.EXCLUDED_CONTEXTS), EXCLUDED_CONTEXTS(ProxyConfigurationResourceDefinition.Attribute.EXCLUDED_CONTEXTS),
FLUSH_PACKETS(ProxyConfigurationResourceDefinition.Attribute.FLUSH_PACKETS), FLUSH_PACKETS(ProxyConfigurationResourceDefinition.Attribute.FLUSH_PACKETS),
FLUSH_WAIT(ProxyConfigurationResourceDefinition.Attribute.FLUSH_WAIT), FLUSH_WAIT(ProxyConfigurationResourceDefinition.Attribute.FLUSH_WAIT),
@Deprecated DOMAIN("domain"), LISTENER(ProxyConfigurationResourceDefinition.Attribute.LISTENER),
LOAD_BALANCING_GROUP(ProxyConfigurationResourceDefinition.Attribute.LOAD_BALANCING_GROUP), LOAD_BALANCING_GROUP(ProxyConfigurationResourceDefinition.Attribute.LOAD_BALANCING_GROUP),
MAX_ATTEMPTS(ProxyConfigurationResourceDefinition.Attribute.MAX_ATTEMPTS), MAX_ATTEMPTS(ProxyConfigurationResourceDefinition.Attribute.MAX_ATTEMPTS),
NAME(ModelDescriptionConstants.NAME), NAME(ModelDescriptionConstants.NAME),
Expand Down
Expand Up @@ -14,9 +14,11 @@ modcluster.proxy.advertise-socket=Name of socket binding to use for the advertis
modcluster.proxy.auto-enable-contexts=If false, the contexts are registered with the reverse proxy as disabled, they need to be enabled manually by 'enable-context' operation or via mod_cluster_manager console (if available). modcluster.proxy.auto-enable-contexts=If false, the contexts are registered with the reverse proxy as disabled, they need to be enabled manually by 'enable-context' operation or via mod_cluster_manager console (if available).
modcluster.proxy.balancer=The name of the balancer on the reverse proxy to register with. modcluster.proxy.balancer=The name of the balancer on the reverse proxy to register with.
modcluster.proxy.connector=The name of Undertow listener that will be registered with the reverse proxy. modcluster.proxy.connector=The name of Undertow listener that will be registered with the reverse proxy.
modcluster.connector.deprecated=Deprecated. Functions as alias for the 'listener' attribute.
modcluster.proxy.excluded-contexts=List of contexts to exclude from registration with the reverse proxies. modcluster.proxy.excluded-contexts=List of contexts to exclude from registration with the reverse proxies.
modcluster.proxy.flush-packets=Whether to enable packet flushing on the reverse proxy. modcluster.proxy.flush-packets=Whether to enable packet flushing on the reverse proxy.
modcluster.proxy.flush-wait=Time to wait before flushing packets on the reverse proxy. modcluster.proxy.flush-wait=Time to wait before flushing packets on the reverse proxy.
modcluster.proxy.listener=The name of Undertow listener that will be registered with the reverse proxy.
modcluster.proxy.load-balancing-group=Name of the load balancing group this node belongs to. modcluster.proxy.load-balancing-group=Name of the load balancing group this node belongs to.
modcluster.proxy.max-attempts=Maximum number of failover attempts by reverse proxy when sending the request to the backend server. modcluster.proxy.max-attempts=Maximum number of failover attempts by reverse proxy when sending the request to the backend server.
modcluster.proxy.node-timeout=Timeout (in seconds) for proxy connections to a node. That is the time mod_cluster will wait for the back-end response before returning an error. modcluster.proxy.node-timeout=Timeout (in seconds) for proxy connections to a node. That is the time mod_cluster will wait for the back-end response before returning an error.
Expand Down
Expand Up @@ -108,13 +108,6 @@
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="connector" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The name of Undertow listener that will be registered with the reverse proxy.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="excluded-contexts" type="xs:string"> <xs:attribute name="excluded-contexts" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
Expand All @@ -136,6 +129,13 @@
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
</xs:attribute> </xs:attribute>
<xs:attribute name="listener" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The name of Undertow listener that will be registered with the reverse proxy.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="load-balancing-group" type="xs:string"> <xs:attribute name="load-balancing-group" type="xs:string">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
Expand Down
Expand Up @@ -8,7 +8,7 @@
<socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/> <socket-binding name="modcluster" multicast-address="${jboss.modcluster.multicast.address:224.0.1.105}" multicast-port="23364"/>
<supplement name="default"> <supplement name="default">
<replacement placeholder="SUBSYSTEM"> <replacement placeholder="SUBSYSTEM">
<proxy name="default" advertise-socket="modcluster" connector="ajp"> <proxy name="default" advertise-socket="modcluster" listener="ajp">
<dynamic-load-provider> <dynamic-load-provider>
<load-metric type="cpu"/> <load-metric type="cpu"/>
</dynamic-load-provider> </dynamic-load-provider>
Expand All @@ -17,7 +17,7 @@
</supplement> </supplement>
<supplement name="no-multicast"> <supplement name="no-multicast">
<replacement placeholder="SUBSYSTEM"> <replacement placeholder="SUBSYSTEM">
<proxy name="default" advertise="false" connector="ajp" proxies=""> <proxy name="default" advertise="false" listener="ajp" proxies="">
<dynamic-load-provider> <dynamic-load-provider>
<load-metric type="cpu"/> <load-metric type="cpu"/>
</dynamic-load-provider> </dynamic-load-provider>
Expand Down
Expand Up @@ -129,6 +129,23 @@ public void testLegacyMetricOperations() throws Exception {
Assert.assertEquals(result.get(FAILURE_DESCRIPTION).asString(), FAILED, result.get(OUTCOME).asString()); Assert.assertEquals(result.get(FAILURE_DESCRIPTION).asString(), FAILED, result.get(OUTCOME).asString());
} }



@Test
public void testLegacyConnectorOperations() throws Exception {
KernelServices services = this.buildKernelServices();

String testListenerName = "default";

ModelNode op = Operations.createWriteAttributeOperation(getLegacyModClusterConfigAddress(), ProxyConfigurationResourceDefinition.DeprecatedAttribute.CONNECTOR, new ModelNode(testListenerName));
ModelNode result = services.executeOperation(op);
Assert.assertEquals(result.get(FAILURE_DESCRIPTION).asString(), SUCCESS, result.get(OUTCOME).asString());

op = Operations.createReadAttributeOperation(getProxyAddress("default"), ProxyConfigurationResourceDefinition.Attribute.LISTENER);
result = services.executeOperation(op);
Assert.assertEquals(result.get(FAILURE_DESCRIPTION).asString(), SUCCESS, result.get(OUTCOME).asString());
Assert.assertEquals(testListenerName, result.get(RESULT).asString());
}

// Addresses // Addresses


private static PathAddress getSubsystemAddress() { private static PathAddress getSubsystemAddress() {
Expand Down
Expand Up @@ -26,7 +26,7 @@
advertise-socket="modcluster" advertise-socket="modcluster"
auto-enable-contexts="${modcluster.auto-enable-contexts:true}" auto-enable-contexts="${modcluster.auto-enable-contexts:true}"
balancer="${modcluster.balancer:mybalancer}" balancer="${modcluster.balancer:mybalancer}"
connector="ajp" listener="ajp"
excluded-contexts="${modcluster.excluded-contexts:contextA,contextB,contextC}" excluded-contexts="${modcluster.excluded-contexts:contextA,contextB,contextC}"
flush-packets="${modcluster.flush-packets:true}" flush-packets="${modcluster.flush-packets:true}"
flush-wait="${modcluster.flush-wait:10}" flush-wait="${modcluster.flush-wait:10}"
Expand Down
Expand Up @@ -27,7 +27,7 @@
advertise-socket="modcluster" advertise-socket="modcluster"
auto-enable-contexts="${modcluster.auto-enable-contexts:true}" auto-enable-contexts="${modcluster.auto-enable-contexts:true}"
balancer="${modcluster.balancer:mybalancer}" balancer="${modcluster.balancer:mybalancer}"
connector="ajp" listener="ajp"
excluded-contexts="${modcluster.excluded-contexts:contextA,contextB,contextC}" excluded-contexts="${modcluster.excluded-contexts:contextA,contextB,contextC}"
flush-packets="${modcluster.flush-packets:true}" flush-packets="${modcluster.flush-packets:true}"
flush-wait="${modcluster.flush-wait:10}" flush-wait="${modcluster.flush-wait:10}"
Expand Down
Expand Up @@ -27,7 +27,7 @@
advertise-socket="modcluster" advertise-socket="modcluster"
auto-enable-contexts="${modcluster.auto-enable-contexts:true}" auto-enable-contexts="${modcluster.auto-enable-contexts:true}"
balancer="${modcluster.balancer:mybalancer}" balancer="${modcluster.balancer:mybalancer}"
connector="ajp" listener="ajp"
excluded-contexts="${modcluster.excluded-contexts:contextA,contextB,contextC}" excluded-contexts="${modcluster.excluded-contexts:contextA,contextB,contextC}"
flush-packets="${modcluster.flush-packets:true}" flush-packets="${modcluster.flush-packets:true}"
flush-wait="${modcluster.flush-wait:10}" flush-wait="${modcluster.flush-wait:10}"
Expand Down Expand Up @@ -79,7 +79,7 @@
</dynamic-load-provider> </dynamic-load-provider>
</proxy> </proxy>
<proxy name="other" <proxy name="other"
connector="default"> listener="default">
<simple-load-provider factor="${modcluster.simple-load-provider.factor:15}"/> <simple-load-provider factor="${modcluster.simple-load-provider.factor:15}"/>
<ssl ca-certificate-file="${modcluster.ca-certificate-file:/home/rhusar/client-keystore.jks}" <ssl ca-certificate-file="${modcluster.ca-certificate-file:/home/rhusar/client-keystore.jks}"
ca-revocation-url="${modcluster.ca-revocation-url:/home/rhusar/revocations}" ca-revocation-url="${modcluster.ca-revocation-url:/home/rhusar/revocations}"
Expand Down

0 comments on commit 3e1eb87

Please sign in to comment.