Skip to content

Commit

Permalink
feat: Container network configuration support (#3983)
Browse files Browse the repository at this point in the history
* feat: add network config support to kura api's

* feat: add network config support to container orch impl

* fix: added lint fixes - and minor implimentation changes

* fix: removed requirement on container ports. Ports can now be left empty

* test: added test coverage for the new class

* fix: api versioning to match api package

* fix: turned networkMode into a optional string

* fix: changed .get .getOptional

* fix: networkMode javaDoc refractor
  • Loading branch information
GregoryIvo authored May 17, 2022
1 parent c2662bf commit 972cfd8
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Objects;
import java.util.Optional;

import org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder;
import org.eclipse.kura.container.orchestration.ImageConfiguration.ImageConfigurationBuilder;
import org.osgi.annotation.versioning.ProviderType;

Expand All @@ -48,6 +49,7 @@ public class ContainerConfiguration {
private Map<String, String> containerLoggerParameters;
private String containerLoggingType;
private ImageConfiguration imageConfig;
private ContainerNetworkConfiguration networkConfiguration;
private List<String> entryPoint;

private ContainerConfiguration() {
Expand Down Expand Up @@ -201,11 +203,22 @@ public int getImageDownloadTimeoutSeconds() {
return this.imageConfig.getimageDownloadTimeoutSeconds();
}

/**
* return the container's network configuration as a
* {@link ContainerNetworkConfiguration}.
*
* @return
* @since 2.4
*/
public ContainerNetworkConfiguration getContainerNetworkConfiguration() {
return this.networkConfiguration;
}

/**
* Returns a List<String> of container entry points. An empty list can be returned if no entrypoints are specified.
*
* @return
* @since 2.6
* @since 2.4
*/
public List<String> getEntryPoint() {
return this.entryPoint;
Expand Down Expand Up @@ -264,6 +277,7 @@ public static final class ContainerConfigurationBuilder {
private Map<String, String> containerLoggerParameters;
private String containerLoggingType;
private ImageConfigurationBuilder imageConfigBuilder = new ImageConfiguration.ImageConfigurationBuilder();
private ContainerNetworkConfigurationBuilder networkConfigurationBuilder = new ContainerNetworkConfigurationBuilder();
private List<String> entryPoint = new LinkedList<>();

public ContainerConfigurationBuilder setContainerName(String serviceName) {
Expand Down Expand Up @@ -341,6 +355,17 @@ public ContainerConfigurationBuilder setEntryPoint(List<String> entryPoint) {
return this;
}

/**
* Set the {@link NetworkConfiguration}
*
* @since 2.4
*/
public ContainerConfigurationBuilder setContainerNetowrkConfiguration(
ContainerNetworkConfiguration networkConfiguration) {
this.networkConfigurationBuilder.setNetworkMode(networkConfiguration.getNetworkMode());
return this;
}

/**
* Set the {@link ImageConfiguration}
*
Expand Down Expand Up @@ -368,6 +393,7 @@ public ContainerConfiguration build() {
result.containerLoggerParameters = this.containerLoggerParameters;
result.containerLoggingType = this.containerLoggingType;
result.imageConfig = this.imageConfigBuilder.build();
result.networkConfiguration = this.networkConfigurationBuilder.build();
result.entryPoint = requireNonNull(this.entryPoint, "Container EntryPoint list must not be null");

return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright (c) 2022 Eurotech and/or its affiliates and others
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Eurotech
*******************************************************************************/

package org.eclipse.kura.container.orchestration;

import static java.util.Objects.requireNonNull;

import java.util.Objects;
import java.util.Optional;

import org.osgi.annotation.versioning.ProviderType;

/**
* Object which represents a container network configuration used to when
* requesting the generation of a new container instance.
*
* @noimplement This interface is not intended to be implemented by clients.
* @since 2.4
*
*/
@ProviderType
public class ContainerNetworkConfiguration {

private Optional<String> networkMode;

private ContainerNetworkConfiguration() {
}

/**
*
* Returns the network mode a container will be created with (e.g. 'bridge',
* 'none', 'container:', 'host').
*
* @return
*/
public Optional<String> getNetworkMode() {
return this.networkMode;
}

/**
* Creates a builder for creating a new {@link ContainerNetworkConfiguration}
* instance.
*
* @return the builder.
*/
public static ContainerNetworkConfigurationBuilder builder() {
return new ContainerNetworkConfigurationBuilder();
}

@Override
public int hashCode() {
return Objects.hash(this.networkMode);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof ContainerNetworkConfiguration)) {
return false;
}
ContainerNetworkConfiguration other = (ContainerNetworkConfiguration) obj;
return Objects.equals(this.networkMode, other.networkMode);
}

public static final class ContainerNetworkConfigurationBuilder {

private Optional<String> networkMode = Optional.empty();

public ContainerNetworkConfigurationBuilder setNetworkMode(Optional<String> networkMode) {
this.networkMode = networkMode;
return this;
}

public ContainerNetworkConfiguration build() {
ContainerNetworkConfiguration result = new ContainerNetworkConfiguration();

result.networkMode = requireNonNull(this.networkMode,
"Requested Container Network Mode Name cannot be null");

return result;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ private String createContainer(ContainerConfiguration containerDescription) thro

configuration = containerLogConfigurationHandler(containerDescription, configuration);

configuration = containerNetworkConfigurationHandler(containerDescription, configuration);

if (containerDescription.isContainerPrivileged()) {
configuration = configuration.withPrivileged(containerDescription.isContainerPrivileged());
}
Expand Down Expand Up @@ -529,6 +531,18 @@ private HostConfig containerLogConfigurationHandler(ContainerConfiguration conta
return configuration;
}

private HostConfig containerNetworkConfigurationHandler(ContainerConfiguration containerDescription,
HostConfig configuration) {

if (containerDescription.getContainerNetworkConfiguration().getNetworkMode().isPresent()
&& !containerDescription.getContainerNetworkConfiguration().getNetworkMode().get().trim().isEmpty()) {
configuration.withNetworkMode(containerDescription.getContainerNetworkConfiguration().getNetworkMode().get()
.toLowerCase().trim());
}

return configuration;
}

private HostConfig containerPortManagementHandler(ContainerConfiguration containerDescription,
HostConfig commandBuilder) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@

<AD id="container.ports.internal" name="Internal ports"
description="A comma separated list of ports. Note, the number of internal ports must be equal to the number of external ports. Example: 80, 443."
type="String" cardinality="1" required="true"
type="String" cardinality="1" required="false"
default="80" />

<AD id="container.ports.external" name="External ports"
description="A comma separated list of ports. Note, the number of external ports must be equal to the number of internal ports. Example: 8080, 443."
type="String" cardinality="1" required="true"
type="String" cardinality="1" required="false"
default="8080" />

<AD id="container.privileged" name="Privileged Mode" type="Boolean" cardinality="1" required="true" default="false"
Expand All @@ -107,6 +107,13 @@
type="String" cardinality="1"
required="false" default="" />

<AD id="container.networkMode"
name="Networking Mode"
description="Used to specify what networking mode the container will use. Possible Drivers: bridge, none, container:{container id}, host" type="String" cardinality="0"
required="false"
default="">
</AD>

<AD id="container.loggingType"
name="Logger Type"
description="Used to specify what logging driver the container will use. By default, containers will log to a JSON-FILE on the gateway." type="String" cardinality="0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import org.eclipse.kura.configuration.Password;
import org.eclipse.kura.container.orchestration.ContainerConfiguration;
import org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration;
import org.eclipse.kura.container.orchestration.ImageConfiguration;
import org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;
import org.eclipse.kura.container.orchestration.RegistryCredentials;
Expand Down Expand Up @@ -54,6 +55,7 @@ public class ContainerInstanceOptions {
private static final Property<String> REGISTRY_PASSWORD = new Property<>("registry.password", "");
private static final Property<Integer> IMAGES_DOWNLOAD_TIMEOUT = new Property<>("container.image.download.timeout",
500);
private static final Property<String> CONTAINER_NETWORKING_MODE = new Property<>("container.networkMode", "");
private static final Property<String> CONTAINER_ENTRY_POINT = new Property<>("container.entrypoint", "");

private final boolean enabled;
Expand All @@ -75,6 +77,7 @@ public class ContainerInstanceOptions {
private final Optional<String> registryUsername;
private final Optional<String> registryPassword;
private final int imageDownloadTimeout;
private final Optional<String> containerNetworkingMode;
private final List<String> containerEntryPoint;

public ContainerInstanceOptions(final Map<String, Object> properties) {
Expand All @@ -101,6 +104,7 @@ public ContainerInstanceOptions(final Map<String, Object> properties) {
this.registryUsername = REGISTRY_USERNAME.getOptional(properties);
this.registryPassword = REGISTRY_PASSWORD.getOptional(properties);
this.imageDownloadTimeout = IMAGES_DOWNLOAD_TIMEOUT.get(properties);
this.containerNetworkingMode = CONTAINER_NETWORKING_MODE.getOptional(properties);
this.containerEntryPoint = parseStringListSplitByComma(CONTAINER_ENTRY_POINT.get(properties));
}

Expand Down Expand Up @@ -162,7 +166,7 @@ private List<String> parseStringListSplitByComma(String stringToSplit) {

for (String entry : stringToSplit.trim().split(",")) {
if (entry.trim().length() > 0) {
stringList.add(entry.trim());
stringList.add(entry.trim());
}
}

Expand Down Expand Up @@ -229,6 +233,10 @@ public Map<String, String> getLoggerParameters() {
return this.containerLoggingParameters;
}

public Optional<String> getContainerNetworkingMode() {
return this.containerNetworkingMode;
}

public Optional<RegistryCredentials> getRegistryCredentials() {
if (this.registryUsername.isPresent() && this.registryPassword.isPresent()) {
return Optional.of(new PasswordRegistryCredentials(this.registryURL, this.registryUsername.get(),
Expand All @@ -242,6 +250,11 @@ public int getImageDownloadTimeout() {
return this.imageDownloadTimeout;
}

private ContainerNetworkConfiguration buildContainerNetworkConfig() {
return new ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder()
.setNetworkMode(getContainerNetworkingMode()).build();
}

public List<String> getEntryPoint() {
return this.containerEntryPoint;
}
Expand All @@ -258,6 +271,7 @@ public ContainerConfiguration getContainerConfiguration() {
.setInternalPorts(getContainerPortsInternal()).setEnvVars(getContainerEnvList())
.setVolumes(getContainerVolumeList()).setPrivilegedMode(this.privilegedMode)
.setDeviceList(getContainerDeviceList()).setFrameworkManaged(true).setLoggingType(getLoggingType())
.setContainerNetowrkConfiguration(buildContainerNetworkConfig())
.setLoggerParameters(getLoggerParameters()).setEntryPoint(getEntryPoint()).build();
}

Expand All @@ -280,7 +294,8 @@ public int hashCode() {
this.containerLoggingParameters, this.containerName, this.containerVolumeString, this.containerVolumes,
this.enabled, this.externalPorts, this.image, this.imageDownloadTimeout, this.imageTag,
this.internalPorts, this.maxDownloadRetries, this.privilegedMode, this.registryPassword,
this.registryURL, this.registryUsername, this.retryInterval, this.containerEntryPoint);
this.registryURL, this.registryUsername, this.retryInterval, this.containerEntryPoint,
this.containerNetworkingMode);
}

@Override
Expand All @@ -307,6 +322,7 @@ public boolean equals(Object obj) {
&& Objects.equals(this.registryPassword, other.registryPassword)
&& Objects.equals(this.registryURL, other.registryURL)
&& Objects.equals(this.registryUsername, other.registryUsername)
&& Objects.equals(this.containerNetworkingMode, other.containerNetworkingMode)
&& Objects.equals(this.containerEntryPoint, other.containerEntryPoint)
&& this.retryInterval == other.retryInterval;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.eclipse.kura.configuration.Password;
import org.eclipse.kura.container.orchestration.ContainerConfiguration;
import org.eclipse.kura.container.orchestration.ContainerConfiguration.ContainerConfigurationBuilder;
import org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration;
import org.eclipse.kura.container.orchestration.ImageConfiguration;
import org.eclipse.kura.container.orchestration.PasswordRegistryCredentials;
import org.junit.Test;
Expand Down Expand Up @@ -132,7 +133,9 @@ REGISTRY_USERNAME, new Password(REGISTRY_PASSWORD))))
.setInternalPorts(CONTAINER_PORTS_INTERNAL).setEnvVars(CONTAINER_ENV_VARS)
.setDeviceList(CONTAINER_DEVICE_LIST).setVolumes(CONTAINER_VOLUMES).setPrivilegedMode(false)
.setFrameworkManaged(false).setLoggerParameters(CONTAINER_LOGGER_PARAMETERS)
.setLoggingType(CONTAINER_LOGGER_TYPE);
.setLoggingType(CONTAINER_LOGGER_TYPE).setContainerNetowrkConfiguration(
new ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder()
.setNetworkMode(Optional.of("bridge")).build());
}

private void givenContainerOne() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public class ContainerInstanceOptionsTest {
private static final String DEFAULT_REGISTRY_USERNAME = "";
private static final String DEFAULT_REGISTRY_PASSWORD = "";
private static final int DEFAULT_IMAGES_DOWNLOAD_TIMEOUT = 500;
private static final String DEFAULT_CONTAINER_NETWORKING_MODE = "";
private static final String DEFAULT_CONTAINER_ENTRY_POINT = "";

private static final String CONTAINER_ENV = "container.env";
Expand All @@ -71,6 +72,7 @@ public class ContainerInstanceOptionsTest {
private static final String REGISTRY_USERNAME = "registry.username";
private static final String REGISTRY_PASSWORD = "registry.password";
private static final String IMAGES_DOWNLOAD_TIMEOUT = "container.image.download.timeout";
private static final String CONTAINER_NETWORKING_MODE = "container.networkMode";
private static final String CONTAINER_ENTRY_POINT = "container.entrypoint";

private Map<String, Object> properties;
Expand Down Expand Up @@ -650,6 +652,7 @@ private void givenDefaultProperties() {
this.properties.put(REGISTRY_USERNAME, DEFAULT_REGISTRY_USERNAME);
this.properties.put(REGISTRY_PASSWORD, DEFAULT_REGISTRY_PASSWORD);
this.properties.put(IMAGES_DOWNLOAD_TIMEOUT, DEFAULT_IMAGES_DOWNLOAD_TIMEOUT);
this.properties.put(CONTAINER_NETWORKING_MODE, DEFAULT_CONTAINER_NETWORKING_MODE);
this.properties.put(CONTAINER_ENTRY_POINT, DEFAULT_CONTAINER_ENTRY_POINT);
}

Expand All @@ -671,6 +674,7 @@ private void givenDifferentProperties() {
this.newProperties.put(REGISTRY_USERNAME, "test");
this.newProperties.put(REGISTRY_PASSWORD, "test");
this.newProperties.put(IMAGES_DOWNLOAD_TIMEOUT, 100);
this.newProperties.put(CONTAINER_NETWORKING_MODE, "none");
this.newProperties.put(CONTAINER_ENTRY_POINT, "./test.py,-v,-m,--human-readable,,,");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class ContainerInstanceTest {
private static final String CONTAINER_DEVICE = "container.Device";
private static final String CONTAINER_LOGGER_PARAMETERS = "container.loggerParameters";
private static final String CONTAINER_LOGGING_TYPE = "container.loggingType";
private static final String CONTAINER_NETWORKING_MODE = "container.networkMode";

private ContainerOrchestrationService dockerService;
private Map<String, Object> properties;
Expand Down Expand Up @@ -199,6 +200,7 @@ private void givenFullProperties(boolean enabled) {
this.properties.put(CONTAINER_DEVICE, "");
this.properties.put(CONTAINER_LOGGER_PARAMETERS, "");
this.properties.put(CONTAINER_LOGGING_TYPE, "default");
this.properties.put(CONTAINER_NETWORKING_MODE, "");
}

private void givenConfigurableGenericDockerService() {
Expand Down

0 comments on commit 972cfd8

Please sign in to comment.