bug4811: interims commit, started with StartMongoDBServer procedure and refined UpgradeAmi procedure

This commit is contained in:
Axel Uhl committed 2020-11-06 15:18:41 +01:00
1 parent 920020b6a3
commit 1be2ee9215
16 files changed
+327 -35

No files matched your search

@@ -7,4 +7,5 @@ Bundle-Vendor: SAP
Fragment-Host: com.sap.sailing.landscape
Automatic-Module-Name: com.sap.sailing.landscape.test
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.junit
Require-Bundle: org.junit,
org.mongodb.mongo-java-driver
@@ -5,15 +5,19 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bson.Document;
import org.junit.Before;
import org.junit.Test;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.sap.sailing.landscape.SailingAnalyticsHost;
import com.sap.sailing.landscape.SailingAnalyticsMaster;
import com.sap.sailing.landscape.SailingAnalyticsMetrics;
@@ -23,11 +27,15 @@ import com.sap.sailing.landscape.procedures.StartSailingAnalyticsMaster;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.landscape.InboundReplicationConfiguration;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.aws.AwsInstance;
import com.sap.sse.landscape.aws.AwsLandscape;
import com.sap.sse.landscape.aws.Tags;
import com.sap.sse.landscape.aws.impl.AwsRegion;
import com.sap.sse.landscape.aws.orchestration.CreateDynamicLoadBalancerMapping;
import com.sap.sse.landscape.aws.orchestration.StartMongoDBServer;
import com.sap.sse.landscape.aws.orchestration.StartMongoDBServer.Builder;
import com.sap.sse.landscape.mongodb.MongoEndpoint;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.ec2.model.Instance;
@@ -59,6 +67,28 @@ public class TestProcedures {
securityServiceReplicationBearerToken = System.getProperty(SECURITY_SERVICE_REPLICATION_BEARER_TOKEN);
}
@Test
public void testMongoReplica() throws Exception {
final Builder<String, ApplicationProcessMetrics, ?, ?> startMongoDBServerProcedureBuilder = StartMongoDBServer.builder();
final StartMongoDBServer<String, ApplicationProcessMetrics, ?, ?> startMongoDBServerProcedure = startMongoDBServerProcedureBuilder.build();
// by default this should add a replica to the only "live" server in the test landscape
try {
startMongoDBServerProcedure.run();
final AwsInstance<String, ApplicationProcessMetrics> host = startMongoDBServerProcedure.getHost();
final String internalDNSName = landscape.getInstance(host.getInstanceId(), region).privateDnsName();
// now configure a MongoEndpoint against the replica just launched and try to connect (with a timeout)
final MongoEndpoint mongoEndpoint = landscape.getDatabaseConfigurationForDefaultReplicaSet(region);
final MongoClient mongoClient = mongoEndpoint.getClient();
final MongoDatabase database = mongoClient.getDatabase("admin");
final Document replicaSetStatus = database.runCommand(new Document("replSetGetStatus", 1));
@SuppressWarnings("unchecked")
final List<Document> members = (List<Document>) replicaSetStatus.get("members");
assertTrue(members.stream().filter(member->member.get("name").equals(internalDNSName+":27017")).findAny().isPresent());
} finally {
startMongoDBServerProcedure.getHost().terminate();
}
}
@Test
public void testConnectivity() throws Exception {
final String serverName = "test"+new Random().nextInt();
@@ -36,6 +36,8 @@ implements Procedure<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
* <ul>
* <li>If no {@link #getInstanceName() instance name} is set, the default instance name will be constructed as
* {@code IMAGE_UPGRADE+" for "+machineImage.getId()}</li>
* <li>The {@link #isNoShutdown()} defaults to {@code true} because "starting" a server is what the {@link StartEmptyServer}
* procedure is meant to do. Specialized builders may change this default.</li>
* <li>The user data are set to the string defined by {@link StartEmptyServer#IMAGE_UPGRADE_USER_DATA}, forcing the image to
* boot without trying to launch a process instance.</li>
* </ul>
@@ -57,7 +59,7 @@ implements Procedure<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
HostT extends AwsInstance<ShardingKey, MetricsT>>
extends StartAwsHost.BuilderImpl<StartEmptyServer<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>, ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
implements Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT> {
private boolean noShutdown;
private boolean noShutdown = true;
@Override
public boolean isNoShutdown() {
@@ -12,8 +12,8 @@ import com.sap.sailing.landscape.SailingReleaseRepository;
import com.sap.sailing.landscape.impl.SailingAnalyticsHostImpl;
import com.sap.sse.landscape.ProcessConfigurationVariable;
import com.sap.sse.landscape.Release;
import com.sap.sse.landscape.aws.AmazonMachineImage;
import com.sap.sse.landscape.aws.HostSupplier;
import com.sap.sse.landscape.aws.impl.AmazonMachineImage;
import com.sap.sse.landscape.aws.orchestration.StartAwsHost;
import com.sap.sse.landscape.orchestration.Procedure;
@@ -35,7 +35,7 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
private final static String EXPEDITION_PORT_USER_DATA_NAME = "EXPEDITION_PORT";
private final int DEFAULT_PORT = 8888;
private final Integer port;
private final String serverDirectory;
private final String defaultServerDirectory;
/**
* The following defaults, in addition to the defaults implemented by the more general {@link StartAwsHost.Builder},
@@ -49,7 +49,7 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
* <li>If no {@link Release} is explicitly {@link #setRelease set}, or that {@link Optional} is empty,
* {@link SailingReleaseRepository#INSTANCE}{@link SailingReleaseRepository#getLatestMasterRelease()
* getLatestMasterRelease()} will be used instead.</li>
* <li>The {@link #getServerDirectory() server directory} defaults to {@link /home/sailing/servers/server}</li>
* <li>The {@link #getDefaultServerDirectory() server directory} defaults to {@link /home/sailing/servers/server}</li>
* </ul>
*
* @author Axel Uhl (D043530)
@@ -68,9 +68,9 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
Builder<T, ShardingKey, ProcessT> setExpeditionPort(int expeditionPort);
String getServerDirectory();
String getDefaultServerDirectory();
Builder<T, ShardingKey, ProcessT> setServerDirectory(String serverDirectory);
Builder<T, ShardingKey, ProcessT> setDefaultServerDirectory(String serverDirectory);
}
protected abstract static class BuilderImpl<T extends StartSailingAnalyticsHost<ShardingKey, ProcessT>, ShardingKey, ProcessT extends SailingAnalyticsProcess<ShardingKey>>
@@ -79,7 +79,7 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
private Integer port;
private Integer telnetPort;
private Integer expeditionPort;
private String serverDirectory;
private String defaultServerDirectory;
@Override
public String getImageType() {
@@ -134,14 +134,15 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
return this;
}
// TODO the host start-up should ideally be separated from the process installation/startup
@Override
public String getServerDirectory() {
return serverDirectory == null ? "/home/sailing/servers/server" : serverDirectory;
public String getDefaultServerDirectory() {
return defaultServerDirectory == null ? "/home/sailing/servers/server" : defaultServerDirectory;
}
@Override
public Builder<T, ShardingKey, ProcessT> setServerDirectory(String serverDirectory) {
this.serverDirectory = serverDirectory;
public Builder<T, ShardingKey, ProcessT> setDefaultServerDirectory(String defaultServerDirectory) {
this.defaultServerDirectory = defaultServerDirectory;
return this;
}
}
@@ -150,7 +151,7 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
super(builder);
// remember the port we need in order to hand out the process
this.port = builder.getPort();
this.serverDirectory = builder.getServerDirectory();
this.defaultServerDirectory = builder.getDefaultServerDirectory();
if (builder.getPort() != null) {
addUserData(ProcessConfigurationVariable.SERVER_PORT, builder.getPort().toString());
}
@@ -166,8 +167,8 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, SailingAnalyticsMaste
return port == null ? DEFAULT_PORT : port;
}
protected String getServerDirectory() {
return serverDirectory;
protected String getDefaultServerDirectory() {
return defaultServerDirectory;
}
public abstract ProcessT getSailingAnalyticsProcess();
@@ -53,6 +53,6 @@ public class StartSailingAnalyticsMaster<ShardingKey>
@Override
public SailingAnalyticsMaster<ShardingKey> getSailingAnalyticsProcess() {
return new SailingAnalyticsMasterImpl<>(getPort(), getHost(), getServerDirectory());
return new SailingAnalyticsMasterImpl<>(getPort(), getHost(), getDefaultServerDirectory());
}
}
@@ -54,6 +54,6 @@ public class StartSailingAnalyticsReplica<ShardingKey>
@Override
public SailingAnalyticsReplica<ShardingKey> getSailingAnalyticsProcess() {
return new SailingAnalyticsReplicaImpl<>(getPort(), getHost(), getServerDirectory());
return new SailingAnalyticsReplicaImpl<>(getPort(), getHost(), getDefaultServerDirectory());
}
}
@@ -1,10 +1,14 @@
package com.sap.sailing.landscape.procedures;
import java.util.Collections;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.sap.sailing.landscape.SailingAnalyticsHost;
import com.sap.sailing.landscape.SailingAnalyticsMetrics;
import com.sap.sailing.landscape.impl.SailingAnalyticsHostImpl;
import com.sap.sailing.landscape.procedures.UpgradeAmi.Builder;
import com.sap.sailing.landscape.procedures.UpgradeAmi.Builder.VersionPart;
import com.sap.sse.landscape.MachineImage;
import com.sap.sse.landscape.application.ApplicationMasterProcess;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
@@ -16,7 +20,18 @@ import com.sap.sse.landscape.orchestration.Procedure;
/**
* Upgrades an existing Amazon Machine Image that is expected to be prepared for such an upgrade, by
* invoking it with very specific user data that trigger the automatic upgrade. The resulting AMI can
* be obtained after this procedure has completed by calling {@link #getUpgradedAmi()}.
* be obtained after this procedure has completed by calling {@link #getUpgradedAmi()}.<p>
*
* The procedure uses a new name for the image and its snapshots. This name can either be explicitly
* configured using the {@link Builder}, or it is inferred from the name of the image to upgrade by looking
* for a version number in the form {@code [0-9]+\.[0-9]+(\.[0-9]+)}, so that major.minor and major.minor.micro
* will all be considered matches. The {@link Builder} can be provided only with a new version string. By default,
* it will increment the last version part matched (minor in case of major.minor and micro in case of
* major.minor.micro) by one.<p>
*
* TODO generalize such that kernel upgrades / security patches can be applied to any CentOS/Amazon Linux-based
* image; then one level more specialized clean httpd logs for anything that has a reverse proxy on it;
* then for those that have a default server process / git on it cleaning that up and refreshing...
*
* @author Axel Uhl (D043530)
*
@@ -30,7 +45,9 @@ extends StartEmptyServer<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, R
implements Procedure<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT> {
private static final String IMAGE_UPGRADE_USER_DATA = "image-upgrade";
private static final String NO_SHUTDOWN_USER_DATA = "no-shutdown";
private static final Pattern imageNamePattern = Pattern.compile("^(.*) ([0-9]+)\\.([0-9]+)(\\.([0-9]+))?$");
private final String upgradedImageName;
private MachineImage upgradedAmi;
/**
@@ -41,13 +58,28 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, Repli
* {@code IMAGE_UPGRADE+" for "+machineImage.getId()}</li>
* <li>The user data are set to the string defined by {@link UpgradeAmi#IMAGE_UPGRADE_USER_DATA}, forcing the image to
* boot without trying to launch a process instance.</li>
* <li>The {@link #isNoShutdown()} property default is changed to {@code false} because when upgrading an image the
* default is that after the upgrading activity the instance is shut down for image creation.</li>
* <li>By default the last part of the version number found will be incremented.</li>
* <li>If the {@link #setVersionPartToIncrement(VersionPart)} method is used to explicitly specify a part to increment
* then if its {@link VersionPart#MICRO} and the {@link VersionPart#MICRO} part doesn't exist yet, it is added and set to 0.
* If the part exists it is incremented and in case it's not the last part, tailing parts are all set to 0. With this,
* the new image name defaults to the old image's base name plus a space plus the new version number.</li>
* </ul>
* @author Axel Uhl (D043530)
*/
public static interface Builder<ShardingKey,
MasterProcessT extends ApplicationMasterProcess<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT>,
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT>>
extends StartEmptyServer.Builder<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT, SailingAnalyticsHost<ShardingKey>> {
extends
StartEmptyServer.Builder<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT, SailingAnalyticsHost<ShardingKey>> {
enum VersionPart {
MAJOR, MINOR, MICRO
}
Builder<ShardingKey, MasterProcessT, ReplicaProcessT> setUpgradedImageName(String upgradedImageName);
Builder<ShardingKey, MasterProcessT, ReplicaProcessT> setVersionPartToIncrement(VersionPart versionPartToIncrement);
}
protected static class BuilderImpl<ShardingKey,
@@ -55,13 +87,64 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, Repli
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT>>
extends StartEmptyServer.BuilderImpl<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT, SailingAnalyticsHost<ShardingKey>>
implements Builder<ShardingKey, MasterProcessT, ReplicaProcessT> {
private String upgradedImageName;
private VersionPart versionPartToIncrement;
private BuilderImpl() {
super();
setNoShutdown(false);
}
@Override
public Builder<ShardingKey, MasterProcessT, ReplicaProcessT> setVersionPartToIncrement(VersionPart versionPartToIncrement) {
this.versionPartToIncrement = versionPartToIncrement;
return this;
}
private String increaseVersionNumber(String imageName) {
final String result;
final Matcher versionNumberMatcher = imageNamePattern.matcher(imageName);
if (versionNumberMatcher.matches()) {
final String imageBaseName = versionNumberMatcher.group(1);
final String majorVersion = versionNumberMatcher.group(2);
final String minorVersion = versionNumberMatcher.group(3);
final String microVersion = versionNumberMatcher.group(5);
final StringBuilder sb = new StringBuilder(imageBaseName);
sb.append(' ');
sb.append(majorVersion);
sb.append('.');
sb.append(minorVersion);
if (microVersion != null || versionPartToIncrement == VersionPart.MICRO) {
sb.append('.');
sb.append(microVersion);
}
result = sb.toString();
} else {
result = imageName+" (1)";
}
return result;
}
@Override
public Builder<ShardingKey, MasterProcessT, ReplicaProcessT> setUpgradedImageName(String upgradedImageName) {
this.upgradedImageName = upgradedImageName;
return this;
}
@Override
public HostSupplier<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT, SailingAnalyticsHost<ShardingKey>> getHostSupplier() {
return SailingAnalyticsHostImpl::new;
}
protected String getUpgradedImageName() {
return upgradedImageName;
}
@Override
public StartEmptyServer<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, ReplicaProcessT, SailingAnalyticsHost<ShardingKey>> build() {
public UpgradeAmi<ShardingKey, MasterProcessT, ReplicaProcessT> build() {
if (upgradedImageName == null) {
upgradedImageName = increaseVersionNumber(getMachineImage().getName());
}
return new UpgradeAmi<>(this);
}
}
@@ -73,8 +156,9 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, Repli
return new BuilderImpl<>();
}
public UpgradeAmi(Builder<ShardingKey, MasterProcessT, ReplicaProcessT> builder) {
protected UpgradeAmi(BuilderImpl<ShardingKey, MasterProcessT, ReplicaProcessT> builder) {
super(builder);
upgradedImageName = builder.getUpgradedImageName();
addUserData(Collections.singleton(IMAGE_UPGRADE_USER_DATA));
if (builder.isNoShutdown()) {
addUserData(Collections.singleton(NO_SHUTDOWN_USER_DATA));
@@ -84,6 +168,7 @@ implements Procedure<ShardingKey, SailingAnalyticsMetrics, MasterProcessT, Repli
@Override
public void run() throws Exception {
super.run(); // launches the machine in upgrade mode and shuts it down again, preparing for AMI creation
upgradedAmi = getLandscape().createImage(getHost(), upgradedImageName);
// TODO now comes the waiting for the shutdown and initiating the creation of an AMI for the instance
// TODO then comes the tagging of the volume snapshots created
// TODO then tag the resulting AMI according to the original image's tags, except for the name where automatic version number increment should be implemented
@@ -37,7 +37,6 @@ import com.sap.sse.landscape.application.ApplicationProcess;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
import com.sap.sse.landscape.application.impl.ApplicationProcessImpl;
import com.sap.sse.landscape.aws.impl.AmazonMachineImage;
import com.sap.sse.landscape.aws.impl.AwsRegion;
import com.sap.sse.landscape.aws.orchestration.CreateDNSBasedLoadBalancerMapping;
import com.sap.sse.landscape.impl.ReleaseRepositoryImpl;
@@ -0,0 +1,10 @@
package com.sap.sse.landscape.aws;
import com.sap.sse.landscape.MachineImage;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import software.amazon.awssdk.services.ec2.model.BlockDeviceMapping;
public interface AmazonMachineImage<ShardingKey, MetricsT extends ApplicationProcessMetrics> extends MachineImage {
Iterable<BlockDeviceMapping> getBlockDeviceMappings();
}
@@ -15,7 +15,6 @@ import com.sap.sse.landscape.SecurityGroup;
import com.sap.sse.landscape.application.ApplicationMasterProcess;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
import com.sap.sse.landscape.aws.impl.AmazonMachineImage;
import com.sap.sse.landscape.aws.impl.AwsInstanceImpl;
import com.sap.sse.landscape.aws.impl.AwsLandscapeImpl;
import com.sap.sse.landscape.aws.impl.AwsRegion;
@@ -119,6 +118,8 @@ extends Landscape<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
AmazonMachineImage<ShardingKey, MetricsT> getImage(Region region, String imageId);
AmazonMachineImage<ShardingKey, MetricsT> createImage(AwsInstance<ShardingKey, MetricsT> instance, String imageName);
AmazonMachineImage<ShardingKey, MetricsT> getLatestImageWithTag(Region region, String tagName, String tagValue);
/**
@@ -7,17 +7,19 @@ import java.util.Date;
import java.util.TimeZone;
import com.sap.sse.common.TimePoint;
import com.sap.sse.landscape.MachineImage;
import com.sap.sse.landscape.Region;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.aws.AmazonMachineImage;
import software.amazon.awssdk.services.ec2.model.BlockDeviceMapping;
import software.amazon.awssdk.services.ec2.model.Image;
public class AmazonMachineImage<ShardingKey, MetricsT extends ApplicationProcessMetrics> implements MachineImage {
public class AmazonMachineImageImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics> implements AmazonMachineImage<ShardingKey, MetricsT> {
private static final long serialVersionUID = 1615200981492476022L;
private final Image image;
private final Region region;
public AmazonMachineImage(Image image, Region region) {
public AmazonMachineImageImpl(Image image, Region region) {
this.image = image;
this.region = region;
}
@@ -27,6 +29,11 @@ public class AmazonMachineImage<ShardingKey, MetricsT extends ApplicationProcess
return image.imageId();
}
@Override
public String getName() {
return image.name();
}
@Override
public Region getRegion() {
return region;
@@ -54,7 +61,11 @@ public class AmazonMachineImage<ShardingKey, MetricsT extends ApplicationProcess
@Override
public void delete() {
// TODO Implement MachineImage<AwsInstance>.delete(...)
// TODO implement AmazonMachineImageImpl.delete(); we probably want landscape here...
}
@Override
public Iterable<BlockDeviceMapping> getBlockDeviceMappings() {
return image.blockDeviceMappings();
}
}
@@ -11,6 +11,7 @@ import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
import com.sap.sse.landscape.application.ApplicationReplicaSet;
import com.sap.sse.landscape.application.Scope;
import com.sap.sse.landscape.aws.AmazonMachineImage;
import com.sap.sse.landscape.aws.AwsAvailabilityZone;
import com.sap.sse.landscape.aws.AwsInstance;
import com.sap.sse.landscape.aws.AwsLandscape;
@@ -31,6 +31,7 @@ import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
import com.sap.sse.landscape.application.ApplicationReplicaSet;
import com.sap.sse.landscape.application.Scope;
import com.sap.sse.landscape.aws.AmazonMachineImage;
import com.sap.sse.landscape.aws.ApplicationLoadBalancer;
import com.sap.sse.landscape.aws.AwsAvailabilityZone;
import com.sap.sse.landscape.aws.AwsInstance;
@@ -449,14 +450,23 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
public AmazonMachineImage<ShardingKey, MetricsT> getImage(com.sap.sse.landscape.Region region, String imageId) {
final DescribeImagesResponse response = getEc2Client(getRegion(region))
.describeImages(DescribeImagesRequest.builder().imageIds(imageId).build());
return new AmazonMachineImage<>(response.images().iterator().next(), region);
return new AmazonMachineImageImpl<>(response.images().iterator().next(), region);
}
@Override
public AmazonMachineImage<ShardingKey, MetricsT> createImage(AwsInstance<ShardingKey, MetricsT> instance, String imageName) {
final Ec2Client client = getEc2Client(getRegion(instance.getRegion()));
final String imageId = client.createImage(b->b
.instanceId(instance.getInstanceId())
.name(imageName)).imageId();
return getImage(instance.getRegion(), imageId);
}
@Override
public AmazonMachineImage<ShardingKey, MetricsT> getLatestImageWithTag(com.sap.sse.landscape.Region region, String tagName, String tagValue) {
final DescribeImagesResponse response = getEc2Client(getRegion(region))
.describeImages(DescribeImagesRequest.builder().filters(Filter.builder().name("tag:"+tagName).values(tagValue).build()).build());
return new AmazonMachineImage<>(response.images().stream().max(getMachineImageCreationDateComparator()).get(), region);
return new AmazonMachineImageImpl<>(response.images().stream().max(getMachineImageCreationDateComparator()).get(), region);
}
@Override
@@ -781,7 +791,7 @@ ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterP
}
return null;
}
@Override
public MongoEndpoint getDatabaseConfigurationForDefaultReplicaSet(com.sap.sse.landscape.Region region) {
return getDatabaseConfigurationForReplicaSet(region, MONGO_DEFAULT_REPLICA_SET_NAME);
@@ -23,12 +23,12 @@ import com.sap.sse.landscape.UserDataProvider;
import com.sap.sse.landscape.application.ApplicationMasterProcess;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
import com.sap.sse.landscape.aws.AmazonMachineImage;
import com.sap.sse.landscape.aws.AwsAvailabilityZone;
import com.sap.sse.landscape.aws.AwsInstance;
import com.sap.sse.landscape.aws.AwsLandscape;
import com.sap.sse.landscape.aws.HostSupplier;
import com.sap.sse.landscape.aws.Tags;
import com.sap.sse.landscape.aws.impl.AmazonMachineImage;
import com.sap.sse.landscape.aws.impl.AwsRegion;
import com.sap.sse.landscape.mongodb.Database;
import com.sap.sse.landscape.orchestration.StartHost;
@@ -613,7 +613,11 @@ extends StartHost<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, HostT>
* will be escaped by preceding them with a {@code \} (backslash) character.
*/
protected void addUserData(ProcessConfigurationVariable userDataVariable, String value) {
userData.add(userDataVariable.name()+"=\""+value.replaceAll("\"", "\\\"")+"\"");
addUserData(userDataVariable.name(), value);
}
protected void addUserData(String name, String value) {
userData.add(name+"=\""+value.replaceAll("\"", "\\\"")+"\"");
}
/**
@@ -0,0 +1,137 @@
package com.sap.sse.landscape.aws.orchestration;
import com.sap.sse.landscape.application.ApplicationMasterProcess;
import com.sap.sse.landscape.application.ApplicationProcessMetrics;
import com.sap.sse.landscape.application.ApplicationReplicaProcess;
import com.sap.sse.landscape.aws.AwsInstance;
import com.sap.sse.landscape.aws.HostSupplier;
import com.sap.sse.landscape.aws.impl.AwsInstanceImpl;
/**
* Launches a MongoDB host with user data as follows:<pre>
* REPLICA_SET_NAME={@link Builder#setReplicaSetName(String) replicaSetName}
* REPLICA_SET_PRIMARY={@link Builder#setReplicaSetName(String) replicaSetPrimary}
* REPLICA_SET_PRIORITY={@link Builder#setReplicaSetName(String) replicaSetVotes}
* REPLICA_SET_VOTES={@link Builder#setReplicaSetName(String) replicaSetVotes}</pre>
*
* @author Axel Uhl (D043530)
*/
public class StartMongoDBServer<ShardingKey, MetricsT extends ApplicationProcessMetrics,
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>>
extends StartAwsHost<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, AwsInstance<ShardingKey, MetricsT>> {
private static enum MongoDBReplicaSetUserData {
REPLICA_SET_NAME, REPLICA_SET_PRIMARY, REPLICA_SET_PRIORITY, REPLICA_SET_VOTES;
}
/**
* Defaults:
* <ul>
* <li>The image type defaults to the value of the constant {@link #MONGODB_SERVER_IMAGE_TYPE} ("mongodb-server").</li>
* <li>The replica set name defaults to "live"</li>
* <li>The replica set priority defaults to 1</li>
* <li>The replica set votes defaults to 1</li>
* </ul>
* @author Axel Uhl (D043530)
*/
public static interface Builder<ShardingKey, MetricsT extends ApplicationProcessMetrics,
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>>
extends StartAwsHost.Builder<StartMongoDBServer<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, AwsInstance<ShardingKey, MetricsT>> {
/**
* The default {@link #setImageType(String) image type} used for launching a MongoDB server.
*/
String MONGODB_SERVER_IMAGE_TYPE = "mongodb-server";
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetName(String replicaSetName);
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetPrimary(String replicaSetPrimary);
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetPriority(int replicaSetPriority);
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetVotes(int replicaSetVotes);
StartMongoDBServer<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> build();
}
protected static class BuilderImpl<ShardingKey, MetricsT extends ApplicationProcessMetrics,
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>>
extends StartAwsHost.BuilderImpl<StartMongoDBServer<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>, ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, AwsInstance<ShardingKey, MetricsT>>
implements Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> {
private String replicaSetName = "live";
private String replicaSetPrimary;
private int replicaSetPriority = 1;
private int replicaSetVotes = 1;
private BuilderImpl() {
setImageType(MONGODB_SERVER_IMAGE_TYPE);
}
@Override
public HostSupplier<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT, AwsInstance<ShardingKey, MetricsT>> getHostSupplier() {
return AwsInstanceImpl::new;
}
@Override
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetName(String replicaSetName) {
this.replicaSetName = replicaSetName;
return this;
}
@Override
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetPrimary(String replicaSetPrimary) {
this.replicaSetPrimary = replicaSetPrimary;
return this;
}
@Override
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetPriority(int replicaSetPriority) {
this.replicaSetPriority = replicaSetPriority;
return this;
}
@Override
public Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> setReplicaSetVotes(int replicaSetVotes) {
this.replicaSetVotes = replicaSetVotes;
return this;
}
protected String getReplicaSetName() {
return replicaSetName;
}
protected String getReplicaSetPrimary() {
return replicaSetPrimary;
}
protected int getReplicaSetPriority() {
return replicaSetPriority;
}
protected int getReplicaSetVotes() {
return replicaSetVotes;
}
@Override
public StartMongoDBServer<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> build() {
return new StartMongoDBServer<>(this);
}
}
public static <ShardingKey, MetricsT extends ApplicationProcessMetrics,
MasterProcessT extends ApplicationMasterProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>,
ReplicaProcessT extends ApplicationReplicaProcess<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT>>
Builder<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> builder() {
return new BuilderImpl<>();
}
protected StartMongoDBServer(BuilderImpl<ShardingKey, MetricsT, MasterProcessT, ReplicaProcessT> builder) {
super(builder);
addUserData(MongoDBReplicaSetUserData.REPLICA_SET_NAME.name(), builder.getReplicaSetName());
addUserData(MongoDBReplicaSetUserData.REPLICA_SET_PRIMARY.name(), builder.getReplicaSetPrimary());
addUserData(MongoDBReplicaSetUserData.REPLICA_SET_PRIORITY.name(), Integer.toString(builder.getReplicaSetPriority()));
addUserData(MongoDBReplicaSetUserData.REPLICA_SET_VOTES.name(), Integer.toString(builder.getReplicaSetVotes()));
}
}
@@ -1,7 +1,7 @@
package com.sap.sse.landscape;
import com.sap.sse.common.NamedWithID;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.WithID;
/**
* An image (e.g., an AMI for AWS) that can be used to
@@ -13,7 +13,7 @@ import com.sap.sse.common.WithID;
* @author Axel Uhl (D043530)
*
*/
public interface MachineImage extends WithID {
public interface MachineImage extends NamedWithID {
/**
* The image lives in a region; it can only be used for {@link Host} creation in that region.
*/