Skip to content

Commit

Permalink
Updating to latest Deployer SPI
Browse files Browse the repository at this point in the history
- updating Marathon client library

- adding new option to deploy all apps under one parent group

- adding new option to configure forcing group deletion due to marathon
 client upgrade

- fixed various code analysis warnings
  • Loading branch information
aweigold committed Oct 3, 2018
1 parent 2adb2a3 commit 70bb83c
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 72 deletions.
62 changes: 23 additions & 39 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>

<artifactId>spring-cloud-deployer-mesos</artifactId>
<version>1.1.0.BUILD-SNAPSHOT</version>
<version>1.3.0.BUILD-SNAPSHOT</version>
<groupId>org.springframework.cloud</groupId>
<packaging>jar</packaging>

Expand All @@ -13,19 +13,22 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-parent</artifactId>
<version>1.1.1.RELEASE</version>
<version>1.3.3.RELEASE</version>
</parent>

<properties>
<java.version>1.8</java.version>
<marathon-client.version>0.4.14</marathon-client.version>
<spring-cloud-deployer-spi.version>1.2.0.BUILD-SNAPSHOT</spring-cloud-deployer-spi.version>
<marathon-client.version>0.6.0</marathon-client.version>
<spring-cloud-deployer-spi.version>1.3.3.RELEASE</spring-cloud-deployer-spi.version>
<spring-cloud.version>1.3.3.RELEASE</spring-cloud.version>
<feign.version>9.5.1</feign.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>${spring-cloud.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
Expand All @@ -37,41 +40,31 @@
<artifactId>spring-cloud-deployer-resource-docker</artifactId>
<version>${spring-cloud-deployer-spi.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.cloudbees.marathon</groupId>
<groupId>com.mesosphere</groupId>
<artifactId>marathon-client</artifactId>
<version>${marathon-client.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hashids</groupId>
<artifactId>hashids</artifactId>
<version>1.0.1</version>
<version>1.0.3</version>
</dependency>
<!--Start force Feign versions -->
<dependency>
<groupId>com.netflix.feign</groupId>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>8.14.1</version>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-gson</artifactId>
<version>8.14.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.5</version>
<version>${feign.version}</version>
</dependency>
<!--End force Feign versions -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-spi-test</artifactId>
Expand All @@ -86,22 +79,13 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.0.1.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.1.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-wiremock</artifactId>
<version>2.0.1.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
package org.springframework.cloud.deployer.spi.mesos.marathon;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
Expand All @@ -34,7 +34,7 @@
import mesosphere.marathon.client.model.v2.HealthCheck;
import mesosphere.marathon.client.model.v2.Port;
import mesosphere.marathon.client.model.v2.Task;
import mesosphere.marathon.client.utils.MarathonException;
import mesosphere.marathon.client.MarathonException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

Expand Down Expand Up @@ -62,9 +62,9 @@ public class MarathonAppDeployer implements AppDeployer {

private static final Log logger = LogFactory.getLog(MarathonAppDeployer.class);

private MarathonAppDeployerProperties properties = new MarathonAppDeployerProperties();
private MarathonAppDeployerProperties properties;

Marathon marathon;
private Marathon marathon;

@Autowired
public MarathonAppDeployer(MarathonAppDeployerProperties properties,
Expand Down Expand Up @@ -93,7 +93,7 @@ public String deploy(AppDeploymentRequest request) {
int count = (countProperty != null) ? Integer.parseInt(countProperty) : 1;
for (int i = 0; i < count; i++) {
String instanceId = appId + "/" + request.getDefinition().getName() + "-" + i;
createAppDeployment(request, instanceId, container, Integer.valueOf(i));
createAppDeployment(request, instanceId, container, i);
}
}
else {
Expand All @@ -114,8 +114,7 @@ private void createAppDeployment(AppDeploymentRequest request, String deployment
app.setContainer(container);
app.setId(deploymentId);

Map<String, String> env = new HashMap<>();
env.putAll(request.getDefinition().getProperties());
Map<String, Object> env = new HashMap<>(request.getDefinition().getProperties());
for (String envVar : properties.getEnvironmentVariables()) {
String[] strings = envVar.split("=", 2);
Assert.isTrue(strings.length == 2, "Invalid environment variable declared: " + envVar);
Expand All @@ -141,9 +140,9 @@ private void createAppDeployment(AppDeploymentRequest request, String deployment
app.setInstances(instances);

HealthCheck healthCheck = new HealthCheck();
healthCheck.setPath("/health");
healthCheck.setPath("/actuator/health");
healthCheck.setGracePeriodSeconds(300);
app.setHealthChecks(Arrays.asList(healthCheck));
app.setHealthChecks(Collections.singletonList(healthCheck));

logger.debug("Creating app with definition:\n" + app.toString());
try {
Expand All @@ -157,17 +156,18 @@ private void createAppDeployment(AppDeploymentRequest request, String deployment
private Container createContainer(AppDeploymentRequest request) {
Container container = new Container();
Docker docker = new Docker();
String image = null;
String image;
try {
image = request.getResource().getURI().getSchemeSpecificPart();
} catch (IOException e) {
throw new IllegalArgumentException("Unable to get URI for " + request.getResource(), e);
}
logger.info("Using Docker image: " + image);
docker.setImage(image);
Port port = new Port(8080);
Port port = new Port();
port.setContainerPort(8080);
port.setHostPort(0);
docker.setPortMappings(Arrays.asList(port));
docker.setPortMappings(Collections.singletonList(port));
docker.setNetwork("BRIDGE");
container.setDocker(docker);
return container;
Expand Down Expand Up @@ -235,7 +235,7 @@ private void deleteAppsForGroupDeployment(String groupId) throws MarathonExcepti
}
if (group.getApps().size() == 0 && group.getGroups().size() == 0) {
logger.info(String.format("Deleting group: %s", groupId));
marathon.deleteGroup(groupId);
marathon.deleteGroup(groupId, properties.isForceGroupDeletion());
}
deleteTopLevelGroupForDeployment(groupId);
}
Expand All @@ -250,7 +250,7 @@ private void deleteTopLevelGroupForDeployment(String id) throws MarathonExceptio
}
if (topGroup.getApps().size() == 0 && topGroup.getGroups().size() == 0) {
logger.info(String.format("Deleting group: %s", topLevelGroupId));
marathon.deleteGroup(topLevelGroupId);
marathon.deleteGroup(topLevelGroupId, properties.isForceGroupDeletion());
}
}
}
Expand Down Expand Up @@ -312,11 +312,16 @@ public RuntimeEnvironmentInfo environmentInfo() {
private String deduceAppId(AppDeploymentRequest request) {
String groupId = request.getDeploymentProperties().get(GROUP_PROPERTY_KEY);
String name = request.getDefinition().getName();
String globalMarathonGroup = properties.getGlobalMarathonGroup();
String prefix = "/";
if (StringUtils.hasText(globalMarathonGroup)) {
prefix = "/" + globalMarathonGroup + "/";
}
if (groupId != null) {
return "/" + groupId + "/" + name;
return prefix + groupId + "/" + name;
}
else {
return "/" + name;
return prefix + name;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
*
* @author Eric Bottard
* @author Thomas Risberg
* @author Adam J. Weigold
*/
@ConfigurationProperties(MarathonAppDeployerProperties.PREFIX)
public class MarathonAppDeployerProperties {
Expand Down Expand Up @@ -71,6 +72,17 @@ public class MarathonAppDeployerProperties {
*/
private List<String> uris = new ArrayList<>(0);

/**
* Whether group deletions should be forced (marathon will not delete the group if there is an ongoing deployment
* within the group if this is set to false).
*/
private boolean forceGroupDeletion = true;

/**
* Forces all deployed apps to reside underneath a single global group.
*/
private String globalMarathonGroup;

public double getMemory() {
return memory;
}
Expand Down Expand Up @@ -126,4 +138,20 @@ public Set<Constraint> getConstraints() {
public void setConstraints(Set<Constraint> constraints) {
this.constraints = constraints;
}

public boolean isForceGroupDeletion() {
return forceGroupDeletion;
}

public void setForceGroupDeletion(boolean forceGroupDeletion) {
this.forceGroupDeletion = forceGroupDeletion;
}

public String getGlobalMarathonGroup() {
return globalMarathonGroup;
}

public void setGlobalMarathonGroup(String globalMarathonGroup) {
this.globalMarathonGroup = globalMarathonGroup;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@

import org.springframework.cloud.deployer.spi.app.AppInstanceStatus;
import org.springframework.cloud.deployer.spi.app.DeploymentState;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import mesosphere.marathon.client.model.v2.App;
import mesosphere.marathon.client.model.v2.HealthCheckResult;
import mesosphere.marathon.client.model.v2.HealthCheckResults;
import mesosphere.marathon.client.model.v2.Task;

/**
Expand Down Expand Up @@ -78,12 +79,13 @@ public DeploymentState getState() {
}
}
else {
if (app.getInstances().intValue() > app.getTasksRunning().intValue()) {
if (app.getInstances() > app.getTasksRunning()) {
return DeploymentState.deploying;
}
else {
Collection<HealthCheckResult> healthCheckResults = task.getHealthCheckResults();
boolean alive = healthCheckResults != null && healthCheckResults.iterator().next().isAlive();
Collection<HealthCheckResults> healthCheckResults = task.getHealthCheckResults();
boolean alive = !CollectionUtils.isEmpty(healthCheckResults) &&
healthCheckResults.iterator().next().getAlive();
if (!alive && app.getLastTaskFailure() != null) {
return DeploymentState.failed;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,23 @@
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.deployer.resource.docker.DockerResource;
import org.springframework.cloud.deployer.spi.mesos.MesosAutoConfiguration;
import org.springframework.cloud.deployer.spi.mesos.TestConfig;
import org.springframework.cloud.deployer.spi.task.TaskLauncher;
import org.springframework.cloud.deployer.spi.test.AbstractTaskLauncherIntegrationTests;
import org.springframework.cloud.deployer.spi.test.Timeout;
import org.springframework.core.io.Resource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
* Integration tests for {@link ChronosTaskLauncher}.
*
* @author Thomas Risberg
*/
@SpringApplicationConfiguration(classes = {TestConfig.class, MesosAutoConfiguration.class})
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {TestConfig.class, MesosAutoConfiguration.class})
public class ChronosTaskLauncherIntegrationTests extends AbstractTaskLauncherIntegrationTests{

@Autowired
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

package org.springframework.cloud.deployer.spi.mesos.chronos;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.deployer.spi.mesos.dcos.DcosClusterProperties;
import org.springframework.cloud.deployer.spi.test.junit.AbstractExternalResourceTestSupport;
Expand All @@ -38,19 +38,19 @@ public class ChronosTestSupport extends AbstractExternalResourceTestSupport<Chro

private ConfigurableApplicationContext context;

protected ChronosTestSupport() {
ChronosTestSupport() {
super("CHRONOS");
}


@Override
protected void cleanupResource() throws Exception {
protected void cleanupResource() {
context.close();
}

@Override
protected void obtainResource() throws Exception {
context = SpringApplication.run(Config.class);
context = new SpringApplicationBuilder(Config.class).web(false).run();
resource = context.getBean(Chronos.class);
resource.getGraphCsv();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import org.junit.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.deployer.resource.docker.DockerResource;
import org.springframework.cloud.deployer.spi.app.AppDeployer;
import org.springframework.cloud.deployer.spi.mesos.MesosAutoConfiguration;
Expand All @@ -35,7 +35,7 @@
*
* @author Thomas Risberg
*/
@SpringApplicationConfiguration(classes = {TestConfig.class, MesosAutoConfiguration.class})
@SpringBootTest(classes = {TestConfig.class, MesosAutoConfiguration.class})
public class MesosAppDeployerIntegrationTests extends AbstractAppDeployerIntegrationTests {

@Autowired
Expand Down
Loading

0 comments on commit 70bb83c

Please sign in to comment.