Skip to content

Commit

Permalink
Added shared networking
Browse files Browse the repository at this point in the history
  • Loading branch information
melloware committed Oct 29, 2023
1 parent 1b93cec commit 1b4fc0f
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,35 @@ public interface ClamAVBuildConfig {
@WithDefault(DEFAULT_IMAGE)
String imageName();

/**
* Indicates if the ClamAV server managed by Quarkus Dev Services is shared.
* When shared, Quarkus looks for running containers using label-based service discovery.
* If a matching container is found, it is used, and so a second one is not started.
* Otherwise, Dev Services for ClamAV starts a new container.
* <p>
* The discovery uses the {@code quarkus-dev-service-clamav} label.
* The value is configured using the {@code service-name} property.
* <p>
* Container sharing is only used in dev mode.
*/
@WithName("clamav.devservice.shared")
@WithDefault("true")
boolean shared();

/**
* The value of the {@code quarkus-dev-service-clamav} label attached to the started container.
* This property is used when {@code shared} is set to {@code true}.
* In this case, before starting a container, Dev Services for Minio looks for a container with the
* {@code quarkus-dev-service-clamav} label
* set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it
* starts a new container with the {@code quarkus-dev-service-clamav} label set to the specified value.
* <p>
* This property is used when you need multiple shared ClamAV servers.
*/
@WithName("clamav.devservice.service-name")
@WithDefault("clamav")
String serviceName();

/**
* The ClamAV container image to use.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

import io.quarkus.devservices.common.ConfigureUtil;

/**
* Testcontainers implementation for ClamAV antivirus server.
* <p>
Expand All @@ -22,8 +24,6 @@
*/
public final class ClamAVContainer extends GenericContainer<ClamAVContainer> {

public static final String NAME = "clamav";

/**
* Logger which will be used to capture container STDOUT and STDERR.
*/
Expand All @@ -34,9 +34,15 @@ public final class ClamAVContainer extends GenericContainer<ClamAVContainer> {
*/
public static final Integer PORT_TCP = Integer.parseInt(ClamAVBuildConfig.PORT_TCP);

ClamAVContainer(ClamAVBuildConfig config) {
private final boolean useSharedNetwork;
private String hostName = null;
private final ClamAVBuildConfig config;

ClamAVContainer(ClamAVBuildConfig config, boolean useSharedNetwork) {
super(DockerImageName.parse(config.imageName()).asCompatibleSubstituteFor(ClamAVBuildConfig.DEFAULT_IMAGE));
super.withLabel(ClamAVDevServicesProcessor.DEV_SERVICE_LABEL, NAME);
this.useSharedNetwork = useSharedNetwork;
this.config = config;
super.withLabel(ClamAVDevServicesProcessor.DEV_SERVICE_LABEL, config.serviceName());
super.withNetwork(Network.SHARED);
super.waitingFor(Wait.forLogMessage(".*socket found, clamd started.*", 1));
super.withEnv("CLAMD_STARTUP_TIMEOUT", Integer.toString(config.startupTimeout()));
Expand All @@ -47,16 +53,26 @@ public final class ClamAVContainer extends GenericContainer<ClamAVContainer> {
MountableFile.forClasspathResource("/clamd.conf"),
"/etc/clamav/clamd.conf");

if (useSharedNetwork) {
super.withReuse(true);
}

// forward the container logs
if (config.logging()) {
super.withLogConsumer(new JbossContainerLogConsumer(log).withPrefix(NAME));
super.withLogConsumer(new JbossContainerLogConsumer(log).withPrefix(config.serviceName()));
}
}

@Override
protected void configure() {
super.configure();

if (useSharedNetwork) {
hostName = ConfigureUtil.configureSharedNetwork(this, this.config.serviceName());
} else {
withNetwork(Network.SHARED);
}

// this forces the TCP port to match quarkus.antivirus.clamav.port
addFixedExposedPort(getPort(), PORT_TCP);
}
Expand All @@ -68,11 +84,33 @@ protected void configure() {
*/
public Map<String, String> getExposedConfig() {
Map<String, String> exposed = new HashMap<>(1);
exposed.put(NAME + ".tcp.port", Objects.toString(getPort()));
exposed.put(this.config.serviceName() + ".tcp.port", Objects.toString(getEffectivePort()));
exposed.put(this.config.serviceName() + ".tcp.host", Objects.toString(getEffectiveHost()));
exposed.putAll(super.getEnvMap());
return exposed;
}

public String getEffectiveHost() {
if (useSharedNetwork) {
return hostName;
}

return getTcpHost();
}

/**
* Use "quarkus.antivirus.clamav.port" to configure ClamAV as its exposed TCP port.
*
* @return the port or 3310 if not found which will cause this service not to start
*/
public int getEffectivePort() {
if (useSharedNetwork) {
return PORT_TCP;
}

return getPort();
}

/**
* Use "quarkus.antivirus.clamav.port" to configure ClamAV as its exposed TCP port.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.quarkiverse.antivirus.deployment;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

import org.jboss.logging.Logger;

Expand All @@ -11,12 +14,16 @@
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.builditem.DevServicesResultBuildItem;
import io.quarkus.deployment.builditem.DevServicesSharedNetworkBuildItem;
import io.quarkus.deployment.builditem.DockerStatusBuildItem;
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
import io.quarkus.deployment.console.ConsoleInstalledBuildItem;
import io.quarkus.deployment.console.StartupLogCompressor;
import io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig;
import io.quarkus.deployment.logging.LoggingSetupBuildItem;
import io.quarkus.devservices.common.ContainerAddress;
import io.quarkus.devservices.common.ContainerLocator;
import io.quarkus.devservices.common.ContainerShutdownCloseable;

/**
* Starts a ClamAV server as dev service if needed.
Expand All @@ -32,6 +39,8 @@ public class ClamAVDevServicesProcessor {
*/
static final String DEV_SERVICE_LABEL = "quarkus-dev-service-clamav";

static final ContainerLocator containerLocator = new ContainerLocator(DEV_SERVICE_LABEL, ClamAVContainer.PORT_TCP);

static volatile DevServicesResultBuildItem.RunningDevService devService;
static volatile ClamAVBuildConfig cfg;
static volatile boolean first = true;
Expand All @@ -44,7 +53,8 @@ public DevServicesResultBuildItem startClamAVDevService(
Optional<ConsoleInstalledBuildItem> consoleInstalledBuildItem,
LoggingSetupBuildItem loggingSetupBuildItem,
GlobalDevServicesConfig devServicesConfig,
BuildProducer<ClamAVDevServicesConfigBuildItem> clamAvBuildItemBuildProducer) {
BuildProducer<ClamAVDevServicesConfigBuildItem> clamAvBuildItemBuildProducer,
List<DevServicesSharedNetworkBuildItem> devServicesSharedNetworkBuildItem) {

if (devService != null) {
boolean shouldShutdownTheBroker = !clamAVConfig.equals(cfg);
Expand All @@ -59,7 +69,8 @@ public DevServicesResultBuildItem startClamAVDevService(
(launchMode.isTest() ? "(test) " : "") + "ClamAV Dev Services Starting:",
consoleInstalledBuildItem, loggingSetupBuildItem);
try {
devService = startClamAV(dockerStatusBuildItem, clamAVConfig, devServicesConfig);
devService = startClamAV(dockerStatusBuildItem, clamAVConfig, devServicesConfig, launchMode,
!devServicesSharedNetworkBuildItem.isEmpty());
if (devService == null) {
compressor.closeAndDumpCaptured();
} else {
Expand Down Expand Up @@ -101,7 +112,9 @@ public DevServicesResultBuildItem startClamAVDevService(

private DevServicesResultBuildItem.RunningDevService startClamAV(DockerStatusBuildItem dockerStatusBuildItem,
ClamAVBuildConfig clamAVConfig,
GlobalDevServicesConfig devServicesConfig) {
GlobalDevServicesConfig devServicesConfig,
LaunchModeBuildItem launchMode,
boolean useSharedNetwork) {
if (!clamAVConfig.enabled()) {
// explicitly disabled
log.warn("Not starting dev services for ClamAV, as it has been disabled in the config.");
Expand All @@ -125,14 +138,27 @@ private DevServicesResultBuildItem.RunningDevService startClamAV(DockerStatusBui
return null;
}

final ClamAVContainer clamAV = new ClamAVContainer(clamAVConfig);
devServicesConfig.timeout.ifPresent(clamAV::withStartupTimeout);
clamAV.start();

return new DevServicesResultBuildItem.RunningDevService(ClamAVContainer.NAME,
clamAV.getContainerId(),
clamAV::close,
clamAV.getExposedConfig());
final Optional<ContainerAddress> maybeContainerAddress = containerLocator.locateContainer(clamAVConfig.serviceName(),
useSharedNetwork,
launchMode.getLaunchMode());

final Supplier<DevServicesResultBuildItem.RunningDevService> defaultClamAvSupplier = () -> {
final ClamAVContainer container = new ClamAVContainer(clamAVConfig, useSharedNetwork);
devServicesConfig.timeout.ifPresent(container::withStartupTimeout);
container.start();

return new DevServicesResultBuildItem.RunningDevService(clamAVConfig.serviceName(),
container.getContainerId(),
new ContainerShutdownCloseable(container, clamAVConfig.serviceName()),
container.getExposedConfig());
};

return maybeContainerAddress
.map(containerAddress -> new DevServicesResultBuildItem.RunningDevService(clamAVConfig.serviceName(),
containerAddress.getId(),
null,
new HashMap<>()))
.orElseGet(defaultClamAvSupplier);
}

private void shutdown() {
Expand All @@ -147,4 +173,4 @@ private void shutdown() {
}
}
}
}
}
40 changes: 40 additions & 0 deletions docs/modules/ROOT/pages/includes/quarkus-antivirus.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,46 @@ endif::add-copy-button-to-env-var[]
|`clamav/clamav`


a|icon:lock[title=Fixed at build time] [[quarkus-antivirus_quarkus.antivirus.clamav.devservice.shared]]`link:#quarkus-antivirus_quarkus.antivirus.clamav.devservice.shared[quarkus.antivirus.clamav.devservice.shared]`


[.description]
--
Indicates if the ClamAV server managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for ClamAV starts a new container.

The discovery uses the `quarkus-dev-service-clamav` label. The value is configured using the `service-name` property.

Container sharing is only used in dev mode.

ifdef::add-copy-button-to-env-var[]
Environment variable: env_var_with_copy_button:+++QUARKUS_ANTIVIRUS_CLAMAV_DEVSERVICE_SHARED+++[]
endif::add-copy-button-to-env-var[]
ifndef::add-copy-button-to-env-var[]
Environment variable: `+++QUARKUS_ANTIVIRUS_CLAMAV_DEVSERVICE_SHARED+++`
endif::add-copy-button-to-env-var[]
--|boolean
|`true`


a|icon:lock[title=Fixed at build time] [[quarkus-antivirus_quarkus.antivirus.clamav.devservice.service-name]]`link:#quarkus-antivirus_quarkus.antivirus.clamav.devservice.service-name[quarkus.antivirus.clamav.devservice.service-name]`


[.description]
--
The value of the `quarkus-dev-service-clamav` label attached to the started container. This property is used when `shared` is set to `true`. In this case, before starting a container, Dev Services for Minio looks for a container with the `quarkus-dev-service-clamav` label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise, it starts a new container with the `quarkus-dev-service-clamav` label set to the specified value.

This property is used when you need multiple shared ClamAV servers.

ifdef::add-copy-button-to-env-var[]
Environment variable: env_var_with_copy_button:+++QUARKUS_ANTIVIRUS_CLAMAV_DEVSERVICE_SERVICE_NAME+++[]
endif::add-copy-button-to-env-var[]
ifndef::add-copy-button-to-env-var[]
Environment variable: `+++QUARKUS_ANTIVIRUS_CLAMAV_DEVSERVICE_SERVICE_NAME+++`
endif::add-copy-button-to-env-var[]
--|string
|`clamav`


a|icon:lock[title=Fixed at build time] [[quarkus-antivirus_quarkus.antivirus.clamav.devservice.startup-timeout]]`link:#quarkus-antivirus_quarkus.antivirus.clamav.devservice.startup-timeout[quarkus.antivirus.clamav.devservice.startup-timeout]`


Expand Down

0 comments on commit 1b4fc0f

Please sign in to comment.