Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a "defaultPortMapping" option which exposes all Mesos provided ports #1036

Merged
merged 5 commits into from May 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion Docs/reference/configuration.md
Expand Up @@ -21,6 +21,7 @@ Singularity (Service) is configured by DropWizard via a YAML file referenced on
- [Resource Limits](#resource-limits)
- [Racks](#racks)
- [Slaves](#slaves)
- [Network Configuration](#network-configuration)
- [Database](#database)
- [History Purging](#history-purging)
- [S3](#s3)
Expand Down Expand Up @@ -192,6 +193,14 @@ These settings should live under the "mesos" field inside the root configuration
|-----------|---------|-------------|------|
| database | | The database connection for SingularityService follows the [dropwizard DataSourceFactory format](http://www.dropwizard.io/0.7.0/dropwizard-db/apidocs/io/dropwizard/db/DataSourceFactory.html) | [DataSourceFactory](http://www.dropwizard.io/0.7.0/dropwizard-db/apidocs/io/dropwizard/db/DataSourceFactory.html) |

## Network Configuration

These settings should live under the "network" field of the root configuration.

| Parameter | Default | Description | Type |
|-----------|---------|-------------|------|
| defaultPortMapping | false | If no port mapping is provided, map all Mesos-provided ports to the host | boolean |

#### History Purging ####

These settings live under the "historyPuring" field in the root configuration
Expand Down Expand Up @@ -232,7 +241,7 @@ These settings live under the "sentry" field in the root config and enable Singu

## SMTP ##

These settings live under the "smtp" field in teh root config.
These settings live under the "smtp" field in the root config.

| Parameter | Default | Description | Type |
|-----------|---------|-------------|------|
Expand Down
@@ -0,0 +1,18 @@
package com.hubspot.singularity.config;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties( ignoreUnknown = true )
public class NetworkConfiguration {
private boolean defaultPortMapping;

public void setDefaultPortMapping(boolean defaultPortMapping)
{
this.defaultPortMapping = defaultPortMapping;
}

public boolean isDefaultPortMapping()
{
return defaultPortMapping;
}
}
Expand Up @@ -169,6 +169,10 @@ public class SingularityConfiguration extends Configuration {
@Valid
private MesosConfiguration mesosConfiguration;

@JsonProperty("network")
@Valid
private NetworkConfiguration networkConfiguration = new NetworkConfiguration();

private int newTaskCheckerBaseDelaySeconds = 1;

private long pendingDeployHoldTaskDuringDecommissionMillis = TimeUnit.MINUTES.toMillis(10);
Expand Down Expand Up @@ -523,6 +527,10 @@ public MesosConfiguration getMesosConfiguration() {
return mesosConfiguration;
}

public NetworkConfiguration getNetworkConfiguration() {
return networkConfiguration;
}

public int getNewTaskCheckerBaseDelaySeconds() {
return newTaskCheckerBaseDelaySeconds;
}
Expand Down Expand Up @@ -843,6 +851,10 @@ public void setMesosConfiguration(MesosConfiguration mesosConfiguration) {
this.mesosConfiguration = mesosConfiguration;
}

public void setNetworkConfiguration(NetworkConfiguration networkConfiguration) {
this.networkConfiguration = networkConfiguration;
}

public void setNewTaskCheckerBaseDelaySeconds(int newTaskCheckerBaseDelaySeconds) {
this.newTaskCheckerBaseDelaySeconds = newTaskCheckerBaseDelaySeconds;
}
Expand Down
Expand Up @@ -44,6 +44,7 @@
import com.hubspot.mesos.Resources;
import com.hubspot.mesos.SingularityContainerInfo;
import com.hubspot.mesos.SingularityDockerInfo;
import com.hubspot.mesos.SingularityDockerNetworkType;
import com.hubspot.mesos.SingularityDockerPortMapping;
import com.hubspot.mesos.SingularityVolume;
import com.hubspot.singularity.SingularityTask;
Expand Down Expand Up @@ -231,14 +232,25 @@ private void prepareContainerInfo(final Offer offer, final SingularityTaskId tas
dockerInfoBuilder.setNetwork(DockerInfo.Network.valueOf(dockerInfo.get().getNetwork().get().toString()));
}

if ((dockerInfo.get().hasAllLiteralHostPortMappings() || ports.isPresent()) && !dockerInfo.get().getPortMappings().isEmpty()) {
for (SingularityDockerPortMapping singularityDockerPortMapping : dockerInfo.get().getPortMappings()) {
final List<SingularityDockerPortMapping> portMappings = dockerInfo.get().getPortMappings();
final boolean isBridged = SingularityDockerNetworkType.BRIDGE.equals(dockerInfo.get().getNetwork().orNull());

if ((dockerInfo.get().hasAllLiteralHostPortMappings() || ports.isPresent()) && !portMappings.isEmpty()) {
for (SingularityDockerPortMapping singularityDockerPortMapping : portMappings) {
final Optional<DockerInfo.PortMapping> maybePortMapping = buildPortMapping(singularityDockerPortMapping, ports);

if (maybePortMapping.isPresent()) {
dockerInfoBuilder.addPortMappings(maybePortMapping.get());
}
}
} else if (configuration.getNetworkConfiguration().isDefaultPortMapping() && isBridged && portMappings.isEmpty() && ports.isPresent()) {
for (long longPort : ports.get()) {
int port = Ints.checkedCast(longPort);
dockerInfoBuilder.addPortMappings(DockerInfo.PortMapping.newBuilder()
.setHostPort(port)
.setContainerPort(port)
.build());
}
}

if (!dockerInfo.get().getParameters().isEmpty()) {
Expand Down
Expand Up @@ -13,6 +13,7 @@
import java.util.concurrent.atomic.AtomicLong;

import org.apache.mesos.Protos;
import org.apache.mesos.Protos.ContainerInfo.DockerInfo.PortMapping;
import org.apache.mesos.Protos.ContainerInfo.Type;
import org.apache.mesos.Protos.FrameworkID;
import org.apache.mesos.Protos.Offer;
Expand Down Expand Up @@ -48,10 +49,12 @@
import com.hubspot.singularity.SingularityRequestBuilder;
import com.hubspot.singularity.SingularityTask;
import com.hubspot.singularity.SingularityTaskRequest;
import com.hubspot.singularity.config.NetworkConfiguration;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.ExecutorIdGenerator;

public class SingularityMesosTaskBuilderTest {
private final SingularityConfiguration configuration = new SingularityConfiguration();
private SingularityMesosTaskBuilder builder;
private Resources taskResources;
private Resources executorResources;
Expand All @@ -68,7 +71,7 @@ public void createMocks() {

when(idGenerator.getNextExecutorId()).then(new CreateFakeId());

builder = new SingularityMesosTaskBuilder(new ObjectMapper(), slaveAndRackHelper, idGenerator, new SingularityConfiguration());
builder = new SingularityMesosTaskBuilder(new ObjectMapper(), slaveAndRackHelper, idGenerator, configuration);

taskResources = new Resources(1, 1, 0);
executorResources = new Resources(0.1, 1, 0);
Expand Down Expand Up @@ -186,7 +189,9 @@ public void testDockerMinimalNetworking() {
SingularityContainerType.DOCKER,
Optional.<List<SingularityVolume>>absent(),
Optional.of(new SingularityDockerInfo("docker-image", true, SingularityDockerNetworkType.NONE,
Optional.<List<SingularityDockerPortMapping>>absent())));
Optional.<List<SingularityDockerPortMapping>>absent(),
Optional.<Boolean>absent(),
Optional.<Map<String, String>>absent())));
final SingularityDeploy deploy = new SingularityDeployBuilder("test", "1")
.setContainerInfo(Optional.of(containerInfo))
.build();
Expand All @@ -197,6 +202,41 @@ public void testDockerMinimalNetworking() {
assertEquals(Protos.ContainerInfo.DockerInfo.Network.NONE, task.getMesosTask().getContainer().getDocker().getNetwork());
}

@Test
public void testAutomaticPortMapping() {
NetworkConfiguration netConf = new NetworkConfiguration();
netConf.setDefaultPortMapping(true);
configuration.setNetworkConfiguration(netConf);

taskResources = new Resources(1, 1, 2);

final SingularityRequest request = new SingularityRequestBuilder("test", RequestType.WORKER).build();
final SingularityContainerInfo containerInfo = new SingularityContainerInfo(
SingularityContainerType.DOCKER,
Optional.<List<SingularityVolume>>absent(),
Optional.of(new SingularityDockerInfo("docker-image", false, SingularityDockerNetworkType.BRIDGE,
Optional.<List<SingularityDockerPortMapping>>absent(),
Optional.<Boolean>absent(),
Optional.<Map<String, String>>absent())));
final SingularityDeploy deploy = new SingularityDeployBuilder("test", "1")
.setContainerInfo(Optional.of(containerInfo))
.build();
final SingularityTaskRequest taskRequest = new SingularityTaskRequest(request, deploy, pendingTask);
final SingularityTask task = builder.buildTask(offer, Collections.singletonList(MesosUtils.getPortRangeResource(31010, 31011)), taskRequest, taskResources, executorResources);

assertEquals(Type.DOCKER, task.getMesosTask().getContainer().getType());
assertEquals(Protos.ContainerInfo.DockerInfo.Network.BRIDGE, task.getMesosTask().getContainer().getDocker().getNetwork());

List<PortMapping> portMappings = task.getMesosTask().getContainer().getDocker().getPortMappingsList();
assertEquals(2, portMappings.size());

assertEquals(31010, portMappings.get(0).getHostPort());
assertEquals(31010, portMappings.get(0).getContainerPort());

assertEquals(31011, portMappings.get(1).getHostPort());
assertEquals(31011, portMappings.get(1).getContainerPort());
}

private static class CreateFakeId implements Answer<String> {

private final AtomicLong string = new AtomicLong();
Expand Down