mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-03 01:29:33 +00:00
bug6288: protect live races during landscape operations
Add shared live-content conflict reporting, REST and GWT preflight support, operation-time guards, selective force handling, and landscape tests. Assisted-By: GPT-5.6-sol
This commit is contained in:
1 parent
35068d7799
commit
418c8e5634
34 files changed
+1441
-201
No files matched your search
+47
@@ -0,0 +1,47 @@
|
||||
package com.sap.sailing.landscape.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Live tracked races belonging to one event. */
|
||||
public final class EventLiveContent implements Serializable {
|
||||
private static final long serialVersionUID = 852529878882048466L;
|
||||
private final String eventId;
|
||||
private final String eventName;
|
||||
private final Long eventStartMillis;
|
||||
private final Long eventEndMillis;
|
||||
private final List<RaceLiveContent> racesWithLiveContent;
|
||||
|
||||
public EventLiveContent(final String eventId, final String eventName, final Long eventStartMillis,
|
||||
final Long eventEndMillis, final Iterable<RaceLiveContent> racesWithLiveContent) {
|
||||
this.eventId = eventId;
|
||||
this.eventName = eventName;
|
||||
this.eventStartMillis = eventStartMillis;
|
||||
this.eventEndMillis = eventEndMillis;
|
||||
final List<RaceLiveContent> racesWithLiveContentCopy = new ArrayList<>();
|
||||
racesWithLiveContent.forEach(racesWithLiveContentCopy::add);
|
||||
this.racesWithLiveContent = Collections.unmodifiableList(racesWithLiveContentCopy);
|
||||
}
|
||||
|
||||
public String getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public String getEventName() {
|
||||
return eventName;
|
||||
}
|
||||
|
||||
public Long getEventStartMillis() {
|
||||
return eventStartMillis;
|
||||
}
|
||||
|
||||
public Long getEventEndMillis() {
|
||||
return eventEndMillis;
|
||||
}
|
||||
|
||||
public List<RaceLiveContent> getRacesWithLiveContent() {
|
||||
return racesWithLiveContent;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.sap.sailing.landscape.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* The result of a landscape operation which either completed successfully or was prevented because live content was
|
||||
* found. Technical failures continue to be reported as exceptions by the operation.
|
||||
*/
|
||||
public final class LiveContentAwareOperationResult<T> implements Serializable {
|
||||
private static final long serialVersionUID = -4892697307147697172L;
|
||||
private final boolean successful;
|
||||
private final T successfulResult;
|
||||
private final LiveContentCheckResult liveContentCheckResult;
|
||||
|
||||
private LiveContentAwareOperationResult(final boolean successful, final T successfulResult,
|
||||
final LiveContentCheckResult liveContentCheckResult) {
|
||||
if (successful == (liveContentCheckResult != null)) {
|
||||
throw new IllegalArgumentException("A successful result must not have a live-content conflict and a failed result must have one");
|
||||
}
|
||||
this.successful = successful;
|
||||
this.successfulResult = successfulResult;
|
||||
this.liveContentCheckResult = liveContentCheckResult;
|
||||
}
|
||||
|
||||
public static <T> LiveContentAwareOperationResult<T> success(final T successfulResult) {
|
||||
return new LiveContentAwareOperationResult<>(true, successfulResult, null);
|
||||
}
|
||||
|
||||
public static <T> LiveContentAwareOperationResult<T> liveContentConflict(
|
||||
final LiveContentCheckResult liveContentCheckResult) {
|
||||
return new LiveContentAwareOperationResult<>(false, null, liveContentCheckResult);
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return successful;
|
||||
}
|
||||
|
||||
public T getSuccessfulResult() {
|
||||
return successfulResult;
|
||||
}
|
||||
|
||||
public LiveContentCheckResult getLiveContentCheckResult() {
|
||||
return liveContentCheckResult;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sailing.landscape.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Describes live tracked races found in one or more application replica sets at one instant in time. An empty
|
||||
* {@link #getReplicaSetsWithLiveContent() list} means that no live content was found.
|
||||
*/
|
||||
public final class LiveContentCheckResult implements Serializable {
|
||||
private static final long serialVersionUID = 4259503344851123760L;
|
||||
private final long checkedAtMillis;
|
||||
private final List<ReplicaSetLiveContent> replicaSetsWithLiveContent;
|
||||
|
||||
public LiveContentCheckResult(final long checkedAtMillis,
|
||||
final Iterable<ReplicaSetLiveContent> replicaSetsWithLiveContent) {
|
||||
this.checkedAtMillis = checkedAtMillis;
|
||||
final List<ReplicaSetLiveContent> replicaSetsWithLiveContentCopy = new ArrayList<>();
|
||||
replicaSetsWithLiveContent.forEach(replicaSetsWithLiveContentCopy::add);
|
||||
this.replicaSetsWithLiveContent = Collections.unmodifiableList(replicaSetsWithLiveContentCopy);
|
||||
}
|
||||
|
||||
public long getCheckedAtMillis() {
|
||||
return checkedAtMillis;
|
||||
}
|
||||
|
||||
public List<ReplicaSetLiveContent> getReplicaSetsWithLiveContent() {
|
||||
return replicaSetsWithLiveContent;
|
||||
}
|
||||
|
||||
public boolean hasLiveContent() {
|
||||
return !replicaSetsWithLiveContent.isEmpty();
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.sap.sailing.landscape.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** The identifying and tracking-time information for a live tracked race. */
|
||||
public final class RaceLiveContent implements Serializable {
|
||||
private static final long serialVersionUID = 4664388720482818951L;
|
||||
private final String regattaName;
|
||||
private final String raceName;
|
||||
private final long trackingStartMillis;
|
||||
private final Long trackingEndMillis;
|
||||
|
||||
public RaceLiveContent(final String regattaName, final String raceName, final long trackingStartMillis,
|
||||
final Long trackingEndMillis) {
|
||||
this.regattaName = regattaName;
|
||||
this.raceName = raceName;
|
||||
this.trackingStartMillis = trackingStartMillis;
|
||||
this.trackingEndMillis = trackingEndMillis;
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
public String getRaceName() {
|
||||
return raceName;
|
||||
}
|
||||
|
||||
public long getTrackingStartMillis() {
|
||||
return trackingStartMillis;
|
||||
}
|
||||
|
||||
public Long getTrackingEndMillis() {
|
||||
return trackingEndMillis;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sailing.landscape.common;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/** Live content found in one application replica set. */
|
||||
public final class ReplicaSetLiveContent implements Serializable {
|
||||
private static final long serialVersionUID = -8106650879852011910L;
|
||||
private final String replicaSetName;
|
||||
private final List<EventLiveContent> eventsWithLiveContent;
|
||||
|
||||
public ReplicaSetLiveContent(final String replicaSetName,
|
||||
final Iterable<EventLiveContent> eventsWithLiveContent) {
|
||||
this.replicaSetName = replicaSetName;
|
||||
final List<EventLiveContent> eventsWithLiveContentCopy = new ArrayList<>();
|
||||
eventsWithLiveContent.forEach(eventsWithLiveContentCopy::add);
|
||||
this.eventsWithLiveContent = Collections.unmodifiableList(eventsWithLiveContentCopy);
|
||||
}
|
||||
|
||||
public String getReplicaSetName() {
|
||||
return replicaSetName;
|
||||
}
|
||||
|
||||
public List<EventLiveContent> getEventsWithLiveContent() {
|
||||
return eventsWithLiveContent;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ Require-Bundle: com.sap.sailing.landscape,
|
||||
com.sap.sse.landscape,
|
||||
com.sap.sse.landscape.aws,
|
||||
com.sap.sailing.landscape,
|
||||
com.sap.sailing.landscape.common,
|
||||
org.apache.shiro.core;bundle-version="1.7.1",
|
||||
org.apache.shiro.ehcache;bundle-version="1.7.1",
|
||||
org.apache.shiro.web;bundle-version="1.7.1",
|
||||
|
||||
+120
-18
@@ -1,9 +1,12 @@
|
||||
package com.sap.sailing.landscape.gateway.jaxrs.api;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -27,6 +30,7 @@ import org.json.simple.JSONObject;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.AwsSessionCredentialsWithExpiry;
|
||||
import com.sap.sailing.landscape.LandscapeService;
|
||||
import com.sap.sailing.landscape.LiveContentConflictException;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsHost;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsMetrics;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsProcess;
|
||||
@@ -34,10 +38,12 @@ import com.sap.sailing.landscape.gateway.impl.AwsApplicationProcessJsonSerialize
|
||||
import com.sap.sailing.landscape.gateway.impl.AwsApplicationReplicaSetJsonSerializer;
|
||||
import com.sap.sailing.landscape.gateway.impl.HostJsonSerializer;
|
||||
import com.sap.sailing.landscape.gateway.jaxrs.AbstractLandscapeResource;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.procedures.SailingAnalyticsHostSupplier;
|
||||
import com.sap.sailing.server.gateway.interfaces.CompareServersResult;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.CompareServersResultJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.DataImportProgressJsonSerializer;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.LiveContentCheckResultJsonSerializer;
|
||||
import com.sap.sse.common.Duration;
|
||||
import com.sap.sse.common.Util.Triple;
|
||||
import com.sap.sse.landscape.Landscape;
|
||||
@@ -100,6 +106,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
private static final String REPLICA_SET_NAME = "replicaSetName";
|
||||
private static final String PORT = "port";
|
||||
private static final String IGTIMI_RIOT_PORT = "igtimiRiotPort";
|
||||
private static final String FORCE_FORM_PARAM = "force";
|
||||
private static final String FORCE_REPLICA_SET_FORM_PARAM = "forceReplicaSet";
|
||||
|
||||
@Context
|
||||
UriInfo uriInfo;
|
||||
@@ -212,8 +220,7 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
dedicatedInstanceType, dynamicLoadBalancerMapping, release.getName(),
|
||||
optionalKeyName, privateKeyEncryptionPassphrase == null ? null : privateKeyEncryptionPassphrase.getBytes(), masterReplicationBearerToken,
|
||||
replicaReplicationBearerToken, domainName, optionalMemoryInMegabytesOrNull,
|
||||
optionalMemoryTotalSizeFactorOrNull, optionalIgtimiRiotPort, Optional.ofNullable(optionalMinimumAutoScalingGroupSize),
|
||||
Optional.ofNullable(optionalMaximumAutoScalingGroupSize));
|
||||
optionalMemoryTotalSizeFactorOrNull, optionalIgtimiRiotPort, Optional.ofNullable(optionalMinimumAutoScalingGroupSize), Optional.ofNullable(optionalMaximumAutoScalingGroupSize));
|
||||
final JSONObject result = new AwsApplicationReplicaSetJsonSerializer(release.getName()).serialize(replicaSet);
|
||||
response = Response.ok(streamingOutput(result)).build();
|
||||
} catch (Exception e) {
|
||||
@@ -234,7 +241,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
@FormParam(KEY_NAME_FORM_PARAM) String optionalKeyName,
|
||||
@FormParam(PRIVATE_KEY_ENCRYPTION_PASSPHRASE_FORM_PARAM) String privateKeyEncryptionPassphrase,
|
||||
@FormParam(REPLICA_REPLICATION_BEARER_TOKEN_FORM_PARAM) String replicaReplicationBearerToken,
|
||||
@FormParam(TIMEOUT_IN_MILLISECONDS_FORM_PARAM) Long optionalTimeoutInMilliseconds) {
|
||||
@FormParam(TIMEOUT_IN_MILLISECONDS_FORM_PARAM) Long optionalTimeoutInMilliseconds,
|
||||
@FormParam(FORCE_FORM_PARAM) @DefaultValue("false") boolean force) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
ResponseBuilder responseBuilder;
|
||||
final JSONObject result = new JSONObject();
|
||||
@@ -245,19 +253,62 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
replicaSet = getLandscapeService().getApplicationReplicaSet(region, replicaSetName, optionalTimeoutInMilliseconds, optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> upgradedReplicaSet = getLandscapeService().upgradeApplicationReplicaSet(region, replicaSet,
|
||||
releaseNameOrNullForLatestMaster, optionalKeyName, passphraseForPrivateKeyDecryption,
|
||||
replicaReplicationBearerToken);
|
||||
replicaReplicationBearerToken, force);
|
||||
responseBuilder = Response.ok();
|
||||
result.put(RESPONSE_STATUS, "OK");
|
||||
result.put(RESPONSE_RELEASE, upgradedReplicaSet.getVersion(Optional.ofNullable(optionalTimeoutInMilliseconds).map(Duration::ofMillis),
|
||||
Optional.ofNullable(optionalKeyName), passphraseForPrivateKeyDecryption).getName());
|
||||
} catch (LiveContentConflictException e) {
|
||||
return liveContentConflict(e.getLiveContentCheckResult());
|
||||
} catch (Exception e) {
|
||||
result.put(RESPONSE_STATUS, "ERROR");
|
||||
result.put(RESPONSE_ERROR_MESSAGE, e.getMessage());
|
||||
responseBuilder = Response.serverError();
|
||||
}
|
||||
return responseBuilder.entity(streamingOutput(result)).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Path("/stopreplicatingandremovemasterfromtargetgroups")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(
|
||||
@FormParam(REGION_FORM_PARAM) final String regionId,
|
||||
@FormParam(REPLICA_SET_NAME_FORM_PARAM) final String replicaSetName,
|
||||
@FormParam(TIMEOUT_IN_MILLISECONDS_FORM_PARAM) final Long optionalTimeoutInMilliseconds,
|
||||
@FormParam(KEY_NAME_FORM_PARAM) final String optionalKeyName,
|
||||
@FormParam(PRIVATE_KEY_ENCRYPTION_PASSPHRASE_FORM_PARAM) final String privateKeyEncryptionPassphrase,
|
||||
@FormParam(REPLICA_REPLICATION_BEARER_TOKEN_FORM_PARAM) final String replicaReplicationBearerToken,
|
||||
@FormParam(FORCE_FORM_PARAM) @DefaultValue("false") final boolean force) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
Response response;
|
||||
try {
|
||||
final AwsRegion region = new AwsRegion(regionId, getLandscapeService().getLandscape());
|
||||
final byte[] passphrase = privateKeyEncryptionPassphrase == null ? null
|
||||
: privateKeyEncryptionPassphrase.getBytes();
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet =
|
||||
getLandscapeService().getApplicationReplicaSet(region, replicaSetName,
|
||||
optionalTimeoutInMilliseconds, optionalKeyName, passphrase);
|
||||
if (replicaSet == null) {
|
||||
response = badRequest("Application replica set with name " + replicaSetName + " not found in region "
|
||||
+ regionId);
|
||||
} else {
|
||||
final SailingAnalyticsProcess<String> additionalReplicaStarted = getLandscapeService()
|
||||
.ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(replicaSet,
|
||||
optionalKeyName, passphrase,
|
||||
getLandscapeService().getEffectiveBearerToken(replicaReplicationBearerToken), force);
|
||||
final JSONObject result = new JSONObject();
|
||||
result.put("additionalReplicaStarted", additionalReplicaStarted != null);
|
||||
response = Response.ok(streamingOutput(result)).build();
|
||||
}
|
||||
} catch (LiveContentConflictException e) {
|
||||
response = liveContentConflict(e.getLiveContentCheckResult());
|
||||
} catch (Exception e) {
|
||||
response = badRequest(e.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@Path("/movetoarchiveserver")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@@ -273,7 +324,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
@FormParam(DURATION_TO_WAIT_BEFORE_COMPARE_SERVERS_IN_MILLISECONDS_FORM_PARAM) @DefaultValue("300000") long durationToWaitBeforeCompareServersInMillis,
|
||||
@FormParam(MAX_NUMBER_OF_COMPARE_SERVER_ATTEMPTS_FORM_PARAM) @DefaultValue("5") int maxNumberOfCompareServerAttempts,
|
||||
@FormParam(REMOVE_APPLICATION_REPLICA_SET_FORM_PARAM) @DefaultValue("true") boolean removeApplicationReplicaSet,
|
||||
@FormParam(MONGO_URI_TO_ARCHIVE_DB_TO_FORM_PARAM) String mongoUriToArchiveDbTo) {
|
||||
@FormParam(MONGO_URI_TO_ARCHIVE_DB_TO_FORM_PARAM) String mongoUriToArchiveDbTo,
|
||||
@FormParam(FORCE_FORM_PARAM) @DefaultValue("false") boolean force) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
if (removeApplicationReplicaSet) {
|
||||
getSecurityService().checkCurrentUserDeletePermission(SecuredSecurityTypes.SERVER.getQualifiedObjectIdentifier(
|
||||
@@ -295,13 +347,15 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
final Triple<DataImportProgress, CompareServersResult, String> mdiProgressAndCompareServersResult = getLandscapeService().archiveReplicaSet(regionId, applicationReplicaSetToArchive,
|
||||
bearerTokenOrNullForApplicationReplicaSetToArchive, bearerTokenOrNullForArchive,
|
||||
Duration.ofMillis(durationToWaitBeforeCompareServersInMillis), maxNumberOfCompareServerAttempts, removeApplicationReplicaSet,
|
||||
moveDatabaseHere, optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
moveDatabaseHere, optionalKeyName, passphraseForPrivateKeyDecryption, force);
|
||||
final JSONObject result = new JSONObject();
|
||||
result.put(MDI_PROGRESS, mdiProgressAndCompareServersResult.getA()==null?null:new DataImportProgressJsonSerializer().serialize(mdiProgressAndCompareServersResult.getA()));
|
||||
result.put(COMPARE_SERVERS_RESULT, mdiProgressAndCompareServersResult.getB()==null?null:new CompareServersResultJsonSerializer().serialize(mdiProgressAndCompareServersResult.getB()));
|
||||
result.put(ARCHIVE_MONGODB_RESULT, mdiProgressAndCompareServersResult.getC());
|
||||
response = Response.ok(streamingOutput(result)).build();
|
||||
}
|
||||
} catch (LiveContentConflictException e) {
|
||||
response = liveContentConflict(e.getLiveContentCheckResult());
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error trying to archive replica set "+replicaSetName+" in region "+regionId+": "+e.getMessage(), e);
|
||||
response = badRequest("Error trying to archive replica set "+replicaSetName+" in region "+regionId+": "+e.getMessage());
|
||||
@@ -318,7 +372,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
@FormParam(INSTANCE_ID) String fromInstanceWithId,
|
||||
@FormParam(INSTANCE_TYPE_FORM_PARAM) String optionalInstanceType,
|
||||
@FormParam(KEY_NAME_FORM_PARAM) String optionalKeyName,
|
||||
@FormParam(PRIVATE_KEY_ENCRYPTION_PASSPHRASE_FORM_PARAM) String privateKeyEncryptionPassphrase) {
|
||||
@FormParam(PRIVATE_KEY_ENCRYPTION_PASSPHRASE_FORM_PARAM) String privateKeyEncryptionPassphrase,
|
||||
@FormParam(FORCE_REPLICA_SET_FORM_PARAM) Set<String> forceMasterReplicaSetNames) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
Response response;
|
||||
try {
|
||||
@@ -328,7 +383,9 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
final Triple<SailingAnalyticsHost<String>, Map<String, SailingAnalyticsProcess<String>>, Map<String, SailingAnalyticsProcess<String>>> result = getLandscapeService()
|
||||
.moveAllApplicationProcessesAwayFrom(fromHost,
|
||||
Optional.ofNullable(optionalInstanceType == null ? null : InstanceType.valueOf(optionalInstanceType)),
|
||||
optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
optionalKeyName, passphraseForPrivateKeyDecryption,
|
||||
forceMasterReplicaSetNames == null ? Collections.emptySet()
|
||||
: new HashSet<>(forceMasterReplicaSetNames));
|
||||
final JSONObject jsonResult = new JSONObject();
|
||||
jsonResult.put(NEW_HOST_ID, result.getA().getId());
|
||||
final JSONArray masterProcessesMoved = getProcessesAndTheirReplicaSetNamesAsJSONArray(result.getB());
|
||||
@@ -336,6 +393,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
final JSONArray replicaProcessesMoved = getProcessesAndTheirReplicaSetNamesAsJSONArray(result.getC());
|
||||
jsonResult.put(REPLICA_PROCESSES_MOVED, replicaProcessesMoved);
|
||||
response = Response.ok(streamingOutput(jsonResult)).build();
|
||||
} catch (LiveContentConflictException e) {
|
||||
response = liveContentConflict(e.getLiveContentCheckResult());
|
||||
} catch (Exception e) {
|
||||
final String msg = "Error trying to move processes away from instance with ID "+fromInstanceWithId+" in region "+regionId+": "+e.getMessage();
|
||||
logger.log(Level.SEVERE, msg, e);
|
||||
@@ -344,6 +403,12 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
return response;
|
||||
}
|
||||
|
||||
private Response liveContentConflict(final LiveContentCheckResult liveContentCheckResult) {
|
||||
return Response.status(Status.CONFLICT)
|
||||
.entity(streamingOutput(new LiveContentCheckResultJsonSerializer().serialize(liveContentCheckResult)))
|
||||
.build();
|
||||
}
|
||||
|
||||
private JSONArray getProcessesAndTheirReplicaSetNamesAsJSONArray(Map<String, SailingAnalyticsProcess<String>> processesKeyedByTheirApplicationReplicaSetName) {
|
||||
final JSONArray result = new JSONArray();
|
||||
for (final Entry<String, SailingAnalyticsProcess<String>> e : processesKeyedByTheirApplicationReplicaSetName.entrySet()) {
|
||||
@@ -364,7 +429,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
@FormParam(TIMEOUT_IN_MILLISECONDS_FORM_PARAM) Long optionalTimeoutInMilliseconds,
|
||||
@FormParam(KEY_NAME_FORM_PARAM) String optionalKeyName,
|
||||
@FormParam(PRIVATE_KEY_ENCRYPTION_PASSPHRASE_FORM_PARAM) String privateKeyEncryptionPassphrase,
|
||||
@FormParam(MONGO_URI_TO_ARCHIVE_DB_TO_FORM_PARAM) String mongoUriToArchiveDbTo) {
|
||||
@FormParam(MONGO_URI_TO_ARCHIVE_DB_TO_FORM_PARAM) String mongoUriToArchiveDbTo,
|
||||
@FormParam(FORCE_FORM_PARAM) @DefaultValue("false") boolean force) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
getSecurityService().checkCurrentUserDeletePermission(SecuredSecurityTypes.SERVER.getQualifiedObjectIdentifier(
|
||||
new TypeRelativeObjectIdentifier(replicaSetName)));
|
||||
@@ -382,9 +448,11 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
final MongoUriParser<String> mongoUriParser = new MongoUriParser<>(landscape, region);
|
||||
final MongoEndpoint moveDatabaseHere = mongoUriToArchiveDbTo == null ? null : mongoUriParser.parseMongoUri(mongoUriToArchiveDbTo).getEndpoint();
|
||||
getLandscapeService().removeApplicationReplicaSet(regionId, applicationReplicaSetToRemove, moveDatabaseHere,
|
||||
optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
optionalKeyName, passphraseForPrivateKeyDecryption, force);
|
||||
response = Response.ok().build();
|
||||
}
|
||||
} catch (LiveContentConflictException e) {
|
||||
response = liveContentConflict(e.getLiveContentCheckResult());
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error trying to archive replica set "+replicaSetName+" in region "+regionId+": "+e.getMessage(), e);
|
||||
response = badRequest("Error trying to archive replica set "+replicaSetName+" in region "+regionId+": "+e.getMessage());
|
||||
@@ -420,9 +488,10 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
} else {
|
||||
final LandscapeService landscapeService = getLandscapeService();
|
||||
final SailingAnalyticsHost<String> hostToDeployTo = landscapeService.getLandscape().getHostByInstanceId(region, hostId, new SailingAnalyticsHostSupplier<>());
|
||||
if (landscapeService.isEligibleForDeployment(hostToDeployTo, replicaSet.getServerName(), replicaSet.getPort(),
|
||||
optionalIgtimiRiotPort,
|
||||
optionalTimeoutInMilliseconds == null ? Optional.empty() : Optional.of(Duration.ofMillis(optionalTimeoutInMilliseconds)),
|
||||
if (landscapeService.isEligibleForDeployment(hostToDeployTo, replicaSet.getServerName(),
|
||||
replicaSet.getPort(), optionalIgtimiRiotPort,
|
||||
optionalTimeoutInMilliseconds == null ? Optional.empty()
|
||||
: Optional.of(Duration.ofMillis(optionalTimeoutInMilliseconds)),
|
||||
optionalKeyName, passphraseForPrivateKeyDecryption)) {
|
||||
final SailingAnalyticsProcess<String> process = getLandscapeService().deployReplicaToExistingHost(replicaSet, hostToDeployTo, optionalKeyName,
|
||||
passphraseForPrivateKeyDecryption, replicaReplicationBearerToken,
|
||||
@@ -576,7 +645,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
@FormParam(MASTER_REPLICATION_BEARER_TOKEN_FORM_PARAM) String masterReplicationBearerToken,
|
||||
@FormParam(REPLICA_REPLICATION_BEARER_TOKEN_FORM_PARAM) String replicaReplicationBearerToken,
|
||||
@FormParam(MEMORY_IN_MEGABYTES_FORM_PARAM) Integer optionalMemoryInMegabytesOrNull,
|
||||
@FormParam(MEMORY_TOTAL_SIZE_FACTOR_FORM_PARAM) Integer optionalMemoryTotalSizeFactorOrNull) {
|
||||
@FormParam(MEMORY_TOTAL_SIZE_FACTOR_FORM_PARAM) Integer optionalMemoryTotalSizeFactorOrNull,
|
||||
@FormParam(FORCE_FORM_PARAM) @DefaultValue("false") boolean force) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
Response response;
|
||||
final AwsRegion region = new AwsRegion(regionId, getLandscapeService().getLandscape());
|
||||
@@ -596,7 +666,7 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
Optional.ofNullable(optionalInstanceType).map(instanceTypeName->InstanceType.valueOf(instanceTypeName)),
|
||||
optionalPreferredInstanceToDeployTo, optionalKeyName, passphraseForPrivateKeyDecryption,
|
||||
masterReplicationBearerToken, replicaReplicationBearerToken,
|
||||
optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull);
|
||||
optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull, force);
|
||||
response = Response.ok()
|
||||
.entity(streamingOutput(new AwsApplicationReplicaSetJsonSerializer(result.getVersion(
|
||||
optionalTimeoutInMilliseconds == null ? Landscape.WAIT_FOR_PROCESS_TIMEOUT
|
||||
@@ -604,6 +674,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
Optional.ofNullable(optionalKeyName), passphraseForPrivateKeyDecryption).getName()).serialize(result)))
|
||||
.build();
|
||||
}
|
||||
} catch (LiveContentConflictException e) {
|
||||
response = liveContentConflict(e.getLiveContentCheckResult());
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error trying to archive replica set "+replicaSetName+" in region "+regionId+": "+e.getMessage(), e);
|
||||
response = badRequest("Error trying to archive replica set "+replicaSetName+" in region "+regionId+": "+e.getMessage());
|
||||
@@ -611,6 +683,35 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
return response;
|
||||
}
|
||||
|
||||
@Path("/livecontentcheck")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response checkForLiveContent(@FormParam(REGION_FORM_PARAM) final String regionId,
|
||||
@FormParam(REPLICA_SET_NAME_FORM_PARAM) final Set<String> replicaSetNames,
|
||||
@FormParam(TIMEOUT_IN_MILLISECONDS_FORM_PARAM) final Long optionalTimeoutInMilliseconds,
|
||||
@FormParam(KEY_NAME_FORM_PARAM) final String optionalKeyName,
|
||||
@FormParam(PRIVATE_KEY_ENCRYPTION_PASSPHRASE_FORM_PARAM) final String privateKeyEncryptionPassphrase,
|
||||
@FormParam(MASTER_REPLICATION_BEARER_TOKEN_FORM_PARAM) final String bearerToken) {
|
||||
checkLandscapeManageAwsPermission();
|
||||
Response response;
|
||||
try {
|
||||
final AwsRegion region = new AwsRegion(regionId, getLandscapeService().getLandscape());
|
||||
final byte[] passphrase = privateKeyEncryptionPassphrase == null ? null
|
||||
: privateKeyEncryptionPassphrase.getBytes();
|
||||
final Set<AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>>> replicaSets = new HashSet<>();
|
||||
for (final String replicaSetName : replicaSetNames) {
|
||||
replicaSets.add(getLandscapeService().getApplicationReplicaSet(region, replicaSetName,
|
||||
optionalTimeoutInMilliseconds, optionalKeyName, passphrase));
|
||||
}
|
||||
response = Response.ok(streamingOutput(new LiveContentCheckResultJsonSerializer()
|
||||
.serialize(getLandscapeService().checkForLiveContent(replicaSets, bearerToken)))).build();
|
||||
} catch (Exception e) {
|
||||
response = badRequest(e.getMessage());
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@Path("/changeautoscalingreplicasinstancetype")
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||
@@ -634,7 +735,8 @@ public class SailingLandscapeResource extends AbstractLandscapeResource {
|
||||
} else {
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> result = getLandscapeService()
|
||||
.changeAutoScalingReplicasInstanceType(replicaSet, InstanceType.valueOf(instanceType),
|
||||
Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), passphraseForPrivateKeyDecryption);
|
||||
Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName),
|
||||
passphraseForPrivateKeyDecryption);
|
||||
response = Response.ok()
|
||||
.entity(streamingOutput(new AwsApplicationReplicaSetJsonSerializer(result.getVersion(
|
||||
Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), passphraseForPrivateKeyDecryption).getName()).serialize(result)))
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.sap.sailing.landscape.test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.LiveContentAwareOperationResult;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
|
||||
public class TestLiveContentValueTypes {
|
||||
@Test
|
||||
public void testEmptyCheckResult() {
|
||||
final LiveContentCheckResult result = new LiveContentCheckResult(42L, Collections.emptyList());
|
||||
assertFalse(result.hasLiveContent());
|
||||
assertEquals(42L, result.getCheckedAtMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedLiveContent() {
|
||||
final RaceLiveContent race = new RaceLiveContent("regatta", "race", 10L, null);
|
||||
final EventLiveContent event = new EventLiveContent("event-id", "event", 1L, 100L,
|
||||
Collections.singleton(race));
|
||||
final ReplicaSetLiveContent replicaSet = new ReplicaSetLiveContent("replica-set",
|
||||
Collections.singleton(event));
|
||||
final LiveContentCheckResult result = new LiveContentCheckResult(42L, Collections.singleton(replicaSet));
|
||||
assertTrue(result.hasLiveContent());
|
||||
assertEquals("race", result.getReplicaSetsWithLiveContent().get(0).getEventsWithLiveContent().get(0)
|
||||
.getRacesWithLiveContent().get(0).getRaceName());
|
||||
assertNull(race.getTrackingEndMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperationResultInvariants() {
|
||||
final LiveContentCheckResult conflict = new LiveContentCheckResult(42L, Collections.emptyList());
|
||||
assertTrue(LiveContentAwareOperationResult.success("ok").isSuccessful());
|
||||
assertFalse(LiveContentAwareOperationResult.liveContentConflict(conflict).isSuccessful());
|
||||
assertThrows(IllegalArgumentException.class, () -> LiveContentAwareOperationResult.liveContentConflict(null));
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,9 @@ Require-Bundle: com.sap.sse.gwt,
|
||||
com.sap.sse,
|
||||
com.sap.sse.shared.android,
|
||||
com.sap.sailing.domain
|
||||
Export-Package: com.google.gwt.user.client.rpc.core.com.sap.sse.landscape.aws.common.shared,
|
||||
Export-Package: com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.common,
|
||||
com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.ui.shared,
|
||||
com.google.gwt.user.client.rpc.core.com.sap.sse.landscape.aws.common.shared,
|
||||
com.google.gwt.user.client.rpc.core.com.sap.sse.landscape.common.shared,
|
||||
com.sap.sailing.landscape.ui.client,
|
||||
com.sap.sailing.landscape.ui.server,
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
|
||||
public final class EventLiveContent_CustomFieldSerializer extends CustomFieldSerializer<EventLiveContent> {
|
||||
public static void serialize(final SerializationStreamWriter writer, final EventLiveContent instance)
|
||||
throws SerializationException {
|
||||
writer.writeString(instance.getEventId());
|
||||
writer.writeString(instance.getEventName());
|
||||
writer.writeObject(instance.getEventStartMillis());
|
||||
writer.writeObject(instance.getEventEndMillis());
|
||||
writer.writeInt(instance.getRacesWithLiveContent().size());
|
||||
for (final RaceLiveContent race : instance.getRacesWithLiveContent()) {
|
||||
writer.writeObject(race);
|
||||
}
|
||||
}
|
||||
|
||||
public static EventLiveContent instantiate(final SerializationStreamReader reader) throws SerializationException {
|
||||
final String eventId = reader.readString();
|
||||
final String eventName = reader.readString();
|
||||
final Long eventStartMillis = (Long) reader.readObject();
|
||||
final Long eventEndMillis = (Long) reader.readObject();
|
||||
final int raceCount = reader.readInt();
|
||||
final List<RaceLiveContent> races = new ArrayList<>(raceCount);
|
||||
for (int i = 0; i < raceCount; i++) {
|
||||
races.add((RaceLiveContent) reader.readObject());
|
||||
}
|
||||
return new EventLiveContent(eventId, eventName, eventStartMillis, eventEndMillis, races);
|
||||
}
|
||||
|
||||
public static void deserialize(final SerializationStreamReader reader, final EventLiveContent instance) {
|
||||
// Fully initialized by instantiate(...)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(final SerializationStreamWriter writer, final EventLiveContent instance)
|
||||
throws SerializationException {
|
||||
serialize(writer, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventLiveContent instantiateInstance(final SerializationStreamReader reader) throws SerializationException {
|
||||
return instantiate(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(final SerializationStreamReader reader, final EventLiveContent instance) {
|
||||
deserialize(reader, instance);
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.common;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.landscape.common.LiveContentAwareOperationResult;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
|
||||
public final class LiveContentAwareOperationResult_CustomFieldSerializer
|
||||
extends CustomFieldSerializer<LiveContentAwareOperationResult<?>> {
|
||||
public static void serialize(final SerializationStreamWriter writer,
|
||||
final LiveContentAwareOperationResult<?> instance) throws SerializationException {
|
||||
writer.writeBoolean(instance.isSuccessful());
|
||||
writer.writeObject(instance.getSuccessfulResult());
|
||||
writer.writeObject(instance.getLiveContentCheckResult());
|
||||
}
|
||||
|
||||
public static LiveContentAwareOperationResult<?> instantiate(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
final boolean successful = reader.readBoolean();
|
||||
final Object successfulResult = reader.readObject();
|
||||
final LiveContentCheckResult liveContentCheckResult = (LiveContentCheckResult) reader.readObject();
|
||||
final LiveContentAwareOperationResult<?> result;
|
||||
if (successful) {
|
||||
result = LiveContentAwareOperationResult.success(successfulResult);
|
||||
} else {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(liveContentCheckResult);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void deserialize(final SerializationStreamReader reader,
|
||||
final LiveContentAwareOperationResult<?> instance) {
|
||||
// Fully initialized by instantiate(...)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(final SerializationStreamWriter writer,
|
||||
final LiveContentAwareOperationResult<?> instance) throws SerializationException {
|
||||
serialize(writer, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveContentAwareOperationResult<?> instantiateInstance(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
return instantiate(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(final SerializationStreamReader reader,
|
||||
final LiveContentAwareOperationResult<?> instance) {
|
||||
deserialize(reader, instance);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
|
||||
public final class LiveContentCheckResult_CustomFieldSerializer extends CustomFieldSerializer<LiveContentCheckResult> {
|
||||
public static void serialize(final SerializationStreamWriter writer, final LiveContentCheckResult instance)
|
||||
throws SerializationException {
|
||||
writer.writeLong(instance.getCheckedAtMillis());
|
||||
writer.writeInt(instance.getReplicaSetsWithLiveContent().size());
|
||||
for (final ReplicaSetLiveContent replicaSet : instance.getReplicaSetsWithLiveContent()) {
|
||||
writer.writeObject(replicaSet);
|
||||
}
|
||||
}
|
||||
|
||||
public static LiveContentCheckResult instantiate(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
final long checkedAtMillis = reader.readLong();
|
||||
final int replicaSetCount = reader.readInt();
|
||||
final List<ReplicaSetLiveContent> replicaSets = new ArrayList<>(replicaSetCount);
|
||||
for (int i = 0; i < replicaSetCount; i++) {
|
||||
replicaSets.add((ReplicaSetLiveContent) reader.readObject());
|
||||
}
|
||||
return new LiveContentCheckResult(checkedAtMillis, replicaSets);
|
||||
}
|
||||
|
||||
public static void deserialize(final SerializationStreamReader reader, final LiveContentCheckResult instance) {
|
||||
// Fully initialized by instantiate(...)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(final SerializationStreamWriter writer, final LiveContentCheckResult instance)
|
||||
throws SerializationException {
|
||||
serialize(writer, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveContentCheckResult instantiateInstance(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
return instantiate(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(final SerializationStreamReader reader, final LiveContentCheckResult instance) {
|
||||
deserialize(reader, instance);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.common;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
|
||||
public final class RaceLiveContent_CustomFieldSerializer extends CustomFieldSerializer<RaceLiveContent> {
|
||||
public static void serialize(final SerializationStreamWriter writer, final RaceLiveContent instance)
|
||||
throws SerializationException {
|
||||
writer.writeString(instance.getRegattaName());
|
||||
writer.writeString(instance.getRaceName());
|
||||
writer.writeLong(instance.getTrackingStartMillis());
|
||||
writer.writeObject(instance.getTrackingEndMillis());
|
||||
}
|
||||
|
||||
public static RaceLiveContent instantiate(final SerializationStreamReader reader) throws SerializationException {
|
||||
return new RaceLiveContent(reader.readString(), reader.readString(), reader.readLong(),
|
||||
(Long) reader.readObject());
|
||||
}
|
||||
|
||||
public static void deserialize(final SerializationStreamReader reader, final RaceLiveContent instance) {
|
||||
// Fully initialized by instantiate(...)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(final SerializationStreamWriter writer, final RaceLiveContent instance)
|
||||
throws SerializationException {
|
||||
serialize(writer, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RaceLiveContent instantiateInstance(final SerializationStreamReader reader) throws SerializationException {
|
||||
return instantiate(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(final SerializationStreamReader reader, final RaceLiveContent instance) {
|
||||
deserialize(reader, instance);
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
|
||||
public final class ReplicaSetLiveContent_CustomFieldSerializer extends CustomFieldSerializer<ReplicaSetLiveContent> {
|
||||
public static void serialize(final SerializationStreamWriter writer, final ReplicaSetLiveContent instance)
|
||||
throws SerializationException {
|
||||
writer.writeString(instance.getReplicaSetName());
|
||||
writer.writeInt(instance.getEventsWithLiveContent().size());
|
||||
for (final EventLiveContent event : instance.getEventsWithLiveContent()) {
|
||||
writer.writeObject(event);
|
||||
}
|
||||
}
|
||||
|
||||
public static ReplicaSetLiveContent instantiate(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
final String replicaSetName = reader.readString();
|
||||
final int eventCount = reader.readInt();
|
||||
final List<EventLiveContent> events = new ArrayList<>(eventCount);
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
events.add((EventLiveContent) reader.readObject());
|
||||
}
|
||||
return new ReplicaSetLiveContent(replicaSetName, events);
|
||||
}
|
||||
|
||||
public static void deserialize(final SerializationStreamReader reader, final ReplicaSetLiveContent instance) {
|
||||
// Fully initialized by instantiate(...)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(final SerializationStreamWriter writer, final ReplicaSetLiveContent instance)
|
||||
throws SerializationException {
|
||||
serialize(writer, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplicaSetLiveContent instantiateInstance(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
return instantiate(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(final SerializationStreamReader reader, final ReplicaSetLiveContent instance) {
|
||||
deserialize(reader, instance);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.google.gwt.user.client.rpc.core.com.sap.sailing.landscape.ui.shared;
|
||||
|
||||
import com.google.gwt.user.client.rpc.CustomFieldSerializer;
|
||||
import com.google.gwt.user.client.rpc.SerializationException;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamReader;
|
||||
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
|
||||
import com.sap.sailing.landscape.ui.shared.MoveAllApplicationProcessesResultDTO;
|
||||
|
||||
public final class MoveAllApplicationProcessesResultDTO_CustomFieldSerializer
|
||||
extends CustomFieldSerializer<MoveAllApplicationProcessesResultDTO> {
|
||||
public static void serialize(final SerializationStreamWriter writer,
|
||||
final MoveAllApplicationProcessesResultDTO instance) throws SerializationException {
|
||||
writer.writeString(instance.getNewHostId());
|
||||
}
|
||||
|
||||
public static MoveAllApplicationProcessesResultDTO instantiate(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
return new MoveAllApplicationProcessesResultDTO(reader.readString());
|
||||
}
|
||||
|
||||
public static void deserialize(final SerializationStreamReader reader,
|
||||
final MoveAllApplicationProcessesResultDTO instance) {
|
||||
// Fully initialized by instantiate(...)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeInstance(final SerializationStreamWriter writer,
|
||||
final MoveAllApplicationProcessesResultDTO instance) throws SerializationException {
|
||||
serialize(writer, instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomInstantiateInstance() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MoveAllApplicationProcessesResultDTO instantiateInstance(final SerializationStreamReader reader)
|
||||
throws SerializationException {
|
||||
return instantiate(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserializeInstance(final SerializationStreamReader reader,
|
||||
final MoveAllApplicationProcessesResultDTO instance) {
|
||||
deserialize(reader, instance);
|
||||
}
|
||||
}
|
||||
+190
-48
@@ -10,6 +10,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.gwt.cell.client.SafeHtmlCell;
|
||||
@@ -34,6 +35,11 @@ import com.google.gwt.user.client.ui.TextBox;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.LiveContentAwareOperationResult;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
import com.sap.sailing.landscape.common.SharedLandscapeConstants;
|
||||
import com.sap.sailing.landscape.ui.client.CreateApplicationReplicaSetDialog.CreateApplicationReplicaSetInstructions;
|
||||
import com.sap.sailing.landscape.ui.client.MoveMasterProcessDialog.MoveMasterToOtherInstanceInstructions;
|
||||
@@ -47,6 +53,7 @@ import com.sap.sailing.landscape.ui.shared.AwsInstanceDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.CompareServersResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoEndpointDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoScalingInstructionsDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MoveAllApplicationProcessesResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ProcessDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReleaseDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReverseProxyDTO;
|
||||
@@ -70,6 +77,7 @@ import com.sap.sse.gwt.client.celltable.TableWrapperWithSingleSelectionAndFilter
|
||||
import com.sap.sse.gwt.client.controls.IntegerBox;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.BusyIndicator;
|
||||
import com.sap.sse.gwt.client.controls.busyindicator.SimpleBusyIndicator;
|
||||
import com.sap.sse.gwt.client.dialog.ConfirmationDialog;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sse.landscape.aws.common.shared.RedirectDTO;
|
||||
@@ -676,9 +684,32 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null ? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
|
||||
instructions.getMasterReplicationBearerToken(), instructions.getReplicaReplicationBearerToken(),
|
||||
instructions.getOptionalMemoryInMegabytesOrNull(), instructions.getOptionalMemoryTotalSizeFactorOrNull(),
|
||||
new ApplicationReplicaSetActionChainingCallback<MoveMasterToOtherInstanceInstructions>(
|
||||
replicaSetIterator, replicaSet, (i, sri)->moveMasterToOtherInstance(instructions, replicaSetIterator, stringMessages), instructions,
|
||||
replicaSetName->stringMessages.successfullyMovedMasterOfReplicaSet(replicaSetName)));
|
||||
/* force */ false,
|
||||
new AsyncCallback<LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>>>() {
|
||||
@Override
|
||||
public void onFailure(final Throwable caught) {
|
||||
errorReporter.reportError(caught.getMessage());
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> result) {
|
||||
if (result.isSuccessful()) {
|
||||
Notification.notify(stringMessages.successfullyMovedMasterOfReplicaSet(
|
||||
replicaSet.getName()), NotificationType.SUCCESS);
|
||||
applicationReplicaSetsTable.replaceBasedOnEntityIdentityComparator(
|
||||
result.getSuccessfulResult());
|
||||
if (replicaSetIterator.hasNext()) {
|
||||
moveMasterToOtherInstance(instructions, replicaSetIterator, stringMessages);
|
||||
} else {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
}
|
||||
} else {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
showLiveContentWarning(result.getLiveContentCheckResult());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -893,44 +924,132 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
final String selectedRegion = regionsTable.getSelectionModel().getSelectedObject();
|
||||
new EnsureReplicaStopReplicatingRemoveMasterFromTargetGroupsDialog(stringMessages, errorReporter, new DialogCallback<String>() {
|
||||
@Override
|
||||
public void ok(String replicaReplicationBearerToken) {
|
||||
public void ok(final String replicaReplicationBearerToken) {
|
||||
final ArrayList<SailingApplicationReplicaSetDTO<String>> selectedReplicaSets = new ArrayList<>();
|
||||
applicationReplicaSetsForWhichToEnsureAtLeastOneReplicaStopReplicatingAndRemoveMasterFromTargetGroups
|
||||
.forEach(selectedReplicaSets::add);
|
||||
applicationReplicaSetsBusy.setBusy(true);
|
||||
final int[] howManyMoreToGo = new int[] { Util.size(applicationReplicaSetsForWhichToEnsureAtLeastOneReplicaStopReplicatingAndRemoveMasterFromTargetGroups) };
|
||||
for (final SailingApplicationReplicaSetDTO<String> applicationReplicaSetForWhichToEnsureAtLeastOneReplicaStopReplicatingAndRemoveMasterFromTargetGroups :
|
||||
applicationReplicaSetsForWhichToEnsureAtLeastOneReplicaStopReplicatingAndRemoveMasterFromTargetGroups) {
|
||||
landscapeManagementService.ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(
|
||||
selectedRegion, applicationReplicaSetForWhichToEnsureAtLeastOneReplicaStopReplicatingAndRemoveMasterFromTargetGroups,
|
||||
sshKeyManagementPanel.getSelectedKeyPair().getName(),
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
|
||||
? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
|
||||
replicaReplicationBearerToken, new AsyncCallback<Boolean>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
decrementHowManyMoreToGoAndSetNonBusyIfDone(howManyMoreToGo);
|
||||
errorReporter.reportError(caught.getMessage());
|
||||
landscapeManagementService.checkForLiveContent(selectedRegion, selectedReplicaSets,
|
||||
replicaReplicationBearerToken, sshKeyManagementPanel.getSelectedKeyPair().getName(),
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() == null ? null
|
||||
: sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes(),
|
||||
new AsyncCallback<LiveContentCheckResult>() {
|
||||
@Override
|
||||
public void onFailure(final Throwable caught) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
errorReporter.reportError(caught.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final LiveContentCheckResult preflightResult) {
|
||||
final Runnable execute = () -> executeStopReplicating(selectedRegion, selectedReplicaSets,
|
||||
replicaReplicationBearerToken, getConflictingReplicaSetNames(preflightResult),
|
||||
stringMessages);
|
||||
if (preflightResult.hasLiveContent()) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
showLiveContentWarning(preflightResult, confirmed -> {
|
||||
if (confirmed) {
|
||||
applicationReplicaSetsBusy.setBusy(true);
|
||||
execute.run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
execute.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Boolean result) {
|
||||
decrementHowManyMoreToGoAndSetNonBusyIfDone(howManyMoreToGo);
|
||||
Notification.notify(stringMessages.successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups(
|
||||
applicationReplicaSetForWhichToEnsureAtLeastOneReplicaStopReplicatingAndRemoveMasterFromTargetGroups.getName()),
|
||||
NotificationType.SUCCESS);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override public void cancel() {}
|
||||
}).show();
|
||||
}
|
||||
|
||||
private Set<String> getConflictingReplicaSetNames(final LiveContentCheckResult liveContentCheckResult) {
|
||||
final Set<String> result = new HashSet<>();
|
||||
for (final ReplicaSetLiveContent replicaSet : liveContentCheckResult.getReplicaSetsWithLiveContent()) {
|
||||
result.add(replicaSet.getReplicaSetName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void executeStopReplicating(final String regionId,
|
||||
final ArrayList<SailingApplicationReplicaSetDTO<String>> replicaSets,
|
||||
final String replicaReplicationBearerToken, final Set<String> forceReplicaSetNames,
|
||||
final StringMessages stringMessages) {
|
||||
final int[] remaining = new int[] { replicaSets.size() };
|
||||
for (final SailingApplicationReplicaSetDTO<String> replicaSet : replicaSets) {
|
||||
landscapeManagementService.ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(
|
||||
regionId, replicaSet, sshKeyManagementPanel.getSelectedKeyPair().getName(),
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() == null ? null
|
||||
: sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes(),
|
||||
replicaReplicationBearerToken, forceReplicaSetNames.contains(replicaSet.getName()),
|
||||
new AsyncCallback<LiveContentAwareOperationResult<Boolean>>() {
|
||||
@Override
|
||||
public void onFailure(final Throwable caught) {
|
||||
decrementHowManyMoreToGoAndSetNonBusyIfDone(remaining);
|
||||
errorReporter.reportError(caught.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(final LiveContentAwareOperationResult<Boolean> result) {
|
||||
decrementHowManyMoreToGoAndSetNonBusyIfDone(remaining);
|
||||
if (result.isSuccessful()) {
|
||||
Notification.notify(stringMessages
|
||||
.successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups(
|
||||
replicaSet.getName()), NotificationType.SUCCESS);
|
||||
} else {
|
||||
showLiveContentWarning(result.getLiveContentCheckResult(), confirmed -> {
|
||||
if (confirmed) {
|
||||
final Set<String> additionalForceReplicaSetNames = new HashSet<>(
|
||||
forceReplicaSetNames);
|
||||
additionalForceReplicaSetNames.add(replicaSet.getName());
|
||||
executeStopReplicating(regionId,
|
||||
new ArrayList<>(Collections.singleton(replicaSet)),
|
||||
replicaReplicationBearerToken, additionalForceReplicaSetNames,
|
||||
stringMessages);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void decrementHowManyMoreToGoAndSetNonBusyIfDone(int[] howManyMoreToGo) {
|
||||
if (--howManyMoreToGo[0] <= 0) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void showLiveContentWarning(final LiveContentCheckResult liveContentCheckResult) {
|
||||
showLiveContentWarning(liveContentCheckResult, /* confirmationCallback */ null);
|
||||
}
|
||||
|
||||
private void showLiveContentWarning(final LiveContentCheckResult liveContentCheckResult,
|
||||
final Consumer<Boolean> confirmationCallback) {
|
||||
final StringBuilder details = new StringBuilder();
|
||||
for (final ReplicaSetLiveContent replicaSet : liveContentCheckResult.getReplicaSetsWithLiveContent()) {
|
||||
details.append(replicaSet.getReplicaSetName()).append(":\n");
|
||||
for (final EventLiveContent event : replicaSet.getEventsWithLiveContent()) {
|
||||
details.append(" ").append(event.getEventName()).append(":\n");
|
||||
for (final RaceLiveContent race : event.getRacesWithLiveContent()) {
|
||||
details.append(" ").append(race.getRegattaName()).append(" / ").append(race.getRaceName())
|
||||
.append(" [").append(race.getTrackingStartMillis()).append(" - ")
|
||||
.append(race.getTrackingEndMillis() == null ? "open" : race.getTrackingEndMillis())
|
||||
.append("]\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (confirmationCallback == null) {
|
||||
Window.alert(StringMessages.INSTANCE.liveContentWarning(details.toString()));
|
||||
} else {
|
||||
ConfirmationDialog.create(StringMessages.INSTANCE.liveContentWarningTitle(),
|
||||
StringMessages.INSTANCE.liveContentWarning(details.toString()),
|
||||
StringMessages.INSTANCE.proceedDespiteLiveContent(), StringMessages.INSTANCE.cancel(),
|
||||
confirmationCallback).center();
|
||||
}
|
||||
}
|
||||
|
||||
private void defineLandingPage(StringMessages stringMessages, String selectedRegion,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToDefineLandingPageFor) {
|
||||
if (sshKeyManagementPanel.getSelectedKeyPair() == null) {
|
||||
@@ -1041,7 +1160,8 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
sshKeyManagementPanel.getSelectedKeyPair()==null?null:sshKeyManagementPanel.getSelectedKeyPair().getName(),
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
|
||||
? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
|
||||
new AsyncCallback<Void>() {
|
||||
Collections.emptySet(),
|
||||
new AsyncCallback<LiveContentAwareOperationResult<MoveAllApplicationProcessesResultDTO>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
@@ -1049,10 +1169,15 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
public void onSuccess(final LiveContentAwareOperationResult<MoveAllApplicationProcessesResultDTO> result) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
Notification.notify(stringMessages.successfullyMovedAllProcessesAwayFromHost(fromHost.getInstanceId()), NotificationType.SUCCESS);
|
||||
refreshApplicationReplicaSetsTable();
|
||||
if (result.isSuccessful()) {
|
||||
Notification.notify(stringMessages.successfullyMovedAllProcessesAwayFromHost(
|
||||
fromHost.getInstanceId()), NotificationType.SUCCESS);
|
||||
refreshApplicationReplicaSetsTable();
|
||||
} else {
|
||||
showLiveContentWarning(result.getLiveContentCheckResult());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1154,18 +1279,26 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
sshKeyManagementPanel.getSelectedKeyPair()==null?null:sshKeyManagementPanel.getSelectedKeyPair().getName(),
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
|
||||
? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
|
||||
new AsyncCallback<String>() {
|
||||
/* force */ false, new AsyncCallback<LiveContentAwareOperationResult<String>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
public void onFailure(final Throwable caught) {
|
||||
applicationReplicaSetActionChainingCallback.onFailure(caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(String mongoDbArchivingErrorMessage) {
|
||||
applicationReplicaSetActionChainingCallback.onSuccess(/* application replica set (removed) */ null);
|
||||
if (mongoDbArchivingErrorMessage != null) {
|
||||
errorReporter.reportError(stringMessages.errorArchivingMongoDBTo(
|
||||
selectedMongoEndpointForDBArchiving.getReplicaSetName(), mongoDbArchivingErrorMessage));
|
||||
public void onSuccess(final LiveContentAwareOperationResult<String> result) {
|
||||
if (result.isSuccessful()) {
|
||||
final String mongoDbArchivingErrorMessage = result.getSuccessfulResult();
|
||||
applicationReplicaSetActionChainingCallback
|
||||
.onSuccess(/* application replica set (removed) */ null);
|
||||
if (mongoDbArchivingErrorMessage != null) {
|
||||
errorReporter.reportError(stringMessages.errorArchivingMongoDBTo(
|
||||
selectedMongoEndpointForDBArchiving.getReplicaSetName(),
|
||||
mongoDbArchivingErrorMessage));
|
||||
}
|
||||
} else {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
showLiveContentWarning(result.getLiveContentCheckResult());
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1222,16 +1355,22 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
selectedMongoEndpointForDBArchiving, sshKeyManagementPanel.getSelectedKeyPair().getName(),
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
|
||||
? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
|
||||
new AsyncCallback<Triple<DataImportProgress, CompareServersResultDTO, String>>() {
|
||||
/* force */ false,
|
||||
new AsyncCallback<LiveContentAwareOperationResult<Triple<DataImportProgress, CompareServersResultDTO, String>>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
public void onFailure(final Throwable caught) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
errorReporter.reportError(caught.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Triple<DataImportProgress, CompareServersResultDTO, String> result) {
|
||||
public void onSuccess(final LiveContentAwareOperationResult<Triple<DataImportProgress, CompareServersResultDTO, String>> operationResult) {
|
||||
applicationReplicaSetsBusy.setBusy(false);
|
||||
if (!operationResult.isSuccessful()) {
|
||||
showLiveContentWarning(operationResult.getLiveContentCheckResult());
|
||||
} else {
|
||||
final Triple<DataImportProgress, CompareServersResultDTO, String> result =
|
||||
operationResult.getSuccessfulResult();
|
||||
final String mongoDBArchivingErrorMessage = result.getC();
|
||||
if (result == null || result.getA() == null || result.getA().failed()) {
|
||||
errorReporter.reportError(stringMessages.errorDuringImport(result==null||result.getA()==null?"":result.getA().getErrorMessage()));
|
||||
@@ -1254,6 +1393,7 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
Notification.notify(stringMessages.successfullyArchivedReplicaSet(
|
||||
applicationReplicaSetToArchive.getName()), NotificationType.SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1424,24 +1564,26 @@ public class LandscapeManagementPanel extends SimplePanel {
|
||||
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
|
||||
? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
|
||||
upgradeInstructions.getReplicaReplicationBearerToken(),
|
||||
new AsyncCallback<SailingApplicationReplicaSetDTO<String>>() {
|
||||
/* force */ false,
|
||||
new AsyncCallback<LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>>>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
public void onFailure(final Throwable caught) {
|
||||
decrementHowManyMoreToGoAndSetNonBusyIfDone(howManyMoreToGo);
|
||||
errorReporter.reportError(caught.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailingApplicationReplicaSetDTO<String> result) {
|
||||
public void onSuccess(final LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> operationResult) {
|
||||
decrementHowManyMoreToGoAndSetNonBusyIfDone(howManyMoreToGo);
|
||||
if (result != null) {
|
||||
if (operationResult.isSuccessful()) {
|
||||
final SailingApplicationReplicaSetDTO<String> result =
|
||||
operationResult.getSuccessfulResult();
|
||||
Notification.notify(stringMessages.successfullyUpgradedApplicationReplicaSet(
|
||||
result.getName(), result.getVersion()), NotificationType.SUCCESS);
|
||||
applicationReplicaSetsTable.replaceBasedOnEntityIdentityComparator(result);
|
||||
applicationReplicaSetsTable.refresh();
|
||||
} else {
|
||||
Notification.notify(stringMessages.upgradingApplicationReplicaSetFailed(replicaSet.getName()),
|
||||
NotificationType.ERROR);
|
||||
showLiveContentWarning(operationResult.getLiveContentCheckResult());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+31
-20
@@ -2,9 +2,12 @@ package com.sap.sailing.landscape.ui.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.rpc.RemoteService;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.common.LiveContentAwareOperationResult;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.ui.shared.AmazonMachineImageDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.AvailabilityZoneDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.AwsInstanceDTO;
|
||||
@@ -13,6 +16,7 @@ import com.sap.sailing.landscape.ui.shared.CompareServersResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.LeaderboardNameDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoEndpointDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoScalingInstructionsDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MoveAllApplicationProcessesResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ProcessDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReleaseDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReverseProxyDTO;
|
||||
@@ -105,28 +109,31 @@ public interface LandscapeManagementWriteService extends RemoteService {
|
||||
|
||||
void defineDefaultRedirect(String regionId, String hostname, RedirectDTO redirect, String keyName, String passphraseForPrivateKeyDecryption);
|
||||
|
||||
String removeApplicationReplicaSet(String regionId,
|
||||
LiveContentAwareOperationResult<String> removeApplicationReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToRemove, MongoEndpointDTO moveDatabaseHere,
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDescryption) throws Exception;
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDescryption, boolean force) throws Exception;
|
||||
|
||||
SailingApplicationReplicaSetDTO<String> createDefaultLoadBalancerMappings(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToCreateLoadBalancerMappingFor,
|
||||
boolean useDynamicLoadBalancer, String optionalDomainName, boolean forceDNSUpdate) throws Exception;
|
||||
|
||||
SailingApplicationReplicaSetDTO<String> upgradeApplicationReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToUpgrade, String releaseOrNullForLatestMaster,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken) throws Exception;
|
||||
LiveContentCheckResult checkForLiveContent(String regionId,
|
||||
Iterable<SailingApplicationReplicaSetDTO<String>> applicationReplicaSets, String bearerToken,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
|
||||
|
||||
LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> upgradeApplicationReplicaSet(
|
||||
String regionId, SailingApplicationReplicaSetDTO<String> applicationReplicaSetToUpgrade,
|
||||
String releaseOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String securityReplicationBearerToken, boolean force) throws Exception;
|
||||
|
||||
ArrayList<ReleaseDTO> getReleases();
|
||||
|
||||
Triple<DataImportProgress, CompareServersResultDTO, String> archiveReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForApplicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers,
|
||||
int maxNumberOfCompareServerAttempts, boolean removeApplicationReplicaSet,
|
||||
MongoEndpointDTO moveDatabaseHere, String optionalKeyName, byte[] passphraseForPrivateKeyDecryption)
|
||||
throws Exception;
|
||||
LiveContentAwareOperationResult<Triple<DataImportProgress, CompareServersResultDTO, String>> archiveReplicaSet(
|
||||
String regionId, SailingApplicationReplicaSetDTO<String> applicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForApplicationReplicaSetToArchive, String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers, int maxNumberOfCompareServerAttempts,
|
||||
boolean removeApplicationReplicaSet, MongoEndpointDTO moveDatabaseHere, String optionalKeyName,
|
||||
byte[] passphraseForPrivateKeyDecryption, boolean force) throws Exception;
|
||||
|
||||
SailingApplicationReplicaSetDTO<String> deployApplicationToExistingHost(String replicaSetName,
|
||||
AwsInstanceDTO hostToDeployTo, String replicaInstanceType, boolean dynamicLoadBalancerMapping,
|
||||
@@ -137,9 +144,11 @@ public interface LandscapeManagementWriteService extends RemoteService {
|
||||
Integer optionalIgtimiRiotPort, AwsInstanceDTO optionalPreferredInstanceToDeployUnmanagedReplicaTo) throws Exception;
|
||||
|
||||
|
||||
Boolean ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSet, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken) throws Exception;
|
||||
LiveContentAwareOperationResult<Boolean>
|
||||
ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSet, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken, boolean force)
|
||||
throws Exception;
|
||||
|
||||
ArrayList<SailingApplicationReplicaSetDTO<String>> updateImageForReplicaSets(String regionId,
|
||||
ArrayList<SailingApplicationReplicaSetDTO<String>> applicationReplicaSetsToUpdate,
|
||||
@@ -156,11 +165,12 @@ public interface LandscapeManagementWriteService extends RemoteService {
|
||||
Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull,
|
||||
String optionalSharedReplicaInstanceType) throws Exception;
|
||||
|
||||
SailingApplicationReplicaSetDTO<String> moveMasterToOtherInstance(
|
||||
LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> moveMasterToOtherInstance(
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetDTO, boolean useSharedInstance,
|
||||
String optionalInstanceTypeOrNull, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String optionalMasterReplicationBearerTokenOrNull, String optionalReplicaReplicationBearerTokenOrNull,
|
||||
Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull) throws Exception;
|
||||
Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, boolean force)
|
||||
throws Exception;
|
||||
|
||||
SailingApplicationReplicaSetDTO<String> changeAutoScalingReplicasInstanceType(
|
||||
SailingApplicationReplicaSetDTO<String> replicaSet, String instanceTypeName,
|
||||
@@ -184,8 +194,9 @@ public interface LandscapeManagementWriteService extends RemoteService {
|
||||
|
||||
void removeShardingKeysFromShard(Iterable<LeaderboardNameDTO> shardingKeysToRemove, String region, String shardName, SailingApplicationReplicaSetDTO<String> replicaSet, String bearerToken, String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
|
||||
|
||||
void moveAllApplicationProcessesAwayFrom(AwsInstanceDTO host, String optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
|
||||
LiveContentAwareOperationResult<MoveAllApplicationProcessesResultDTO> moveAllApplicationProcessesAwayFrom(
|
||||
AwsInstanceDTO host, String optionalInstanceTypeForNewInstance, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, Set<String> forceMasterReplicaSetNames) throws Exception;
|
||||
|
||||
boolean hasDNSResourceRecordsForReplicaSet(String replicaSetName, String optionalDomainName);
|
||||
|
||||
|
||||
+33
-21
@@ -2,10 +2,13 @@ package com.sap.sailing.landscape.ui.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsHost;
|
||||
import com.sap.sailing.landscape.common.LiveContentAwareOperationResult;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.SharedLandscapeConstants;
|
||||
import com.sap.sailing.landscape.ui.shared.AmazonMachineImageDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.AvailabilityZoneDTO;
|
||||
@@ -15,6 +18,7 @@ import com.sap.sailing.landscape.ui.shared.CompareServersResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.LeaderboardNameDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoEndpointDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoScalingInstructionsDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MoveAllApplicationProcessesResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ProcessDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReleaseDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReverseProxyDTO;
|
||||
@@ -27,7 +31,7 @@ import com.sap.sse.landscape.aws.common.shared.RedirectDTO;
|
||||
|
||||
public interface LandscapeManagementWriteServiceAsync {
|
||||
void getRegions(AsyncCallback<ArrayList<String>> callback);
|
||||
|
||||
|
||||
/**
|
||||
* @param canBeDeployedInNlbInstanceBasedTargetGroup
|
||||
* A boolean indicating, if true, that the list of available instance types should not contain those,
|
||||
@@ -39,15 +43,15 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
|
||||
void getMongoEndpoint(String region, String replicaSetName,
|
||||
AsyncCallback<MongoEndpointDTO> callback);
|
||||
|
||||
|
||||
void getReverseProxies(String regionId, AsyncCallback<ArrayList<ReverseProxyDTO>> callback);
|
||||
|
||||
|
||||
/**
|
||||
* Removes a reverse proxy from the given cluster and terminates it.
|
||||
* @return Returns true if a success.
|
||||
*/
|
||||
void removeReverseProxy(ReverseProxyDTO instance, String region, String optionalKeyName, byte[] privateKeyEncryptionPassphrase, AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
/**
|
||||
* Rotates the httpd logs on a proxy instance.
|
||||
* @param optionalKeyName Name of key used to connect to the instance to restart
|
||||
@@ -55,18 +59,18 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
*/
|
||||
void rotateHttpdLogs(ReverseProxyDTO proxy, String region, String optionalKeyName,
|
||||
byte[] passphraseForPrivateKeyDecryption, AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
/**
|
||||
* Adds a reverse proxy to the cluster and the right load balancer's target group.
|
||||
*/
|
||||
void addReverseProxy(String instanceName, String instanceType, String region, String launchKey, AvailabilityZoneDTO availabilityZoneDTO, AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets all availability zones in a region.
|
||||
*/
|
||||
void describeAvailabilityZones(String region,AsyncCallback<ArrayList<AvailabilityZoneDTO>> asyncCallback);
|
||||
|
||||
|
||||
/**
|
||||
* The calling subject will see only those keys for which it has the {@code READ} permission.
|
||||
*/
|
||||
@@ -82,7 +86,7 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
* {@link CREATE_OBJECT} permission on the server on which this is called.
|
||||
*/
|
||||
void generateSshKeyPair(String regionId, String keyName, String privateKeyEncryptionPassphrase, AsyncCallback<SSHKeyPairDTO> callback);
|
||||
|
||||
|
||||
/**
|
||||
* Verifies a passphrase for an SSH private key. Returns {@code true} if the passphrase can decipher the private key
|
||||
* and {@code false} if this does not work or the key is invalid, or the key is {@code null}.
|
||||
@@ -114,7 +118,7 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
* credentials.
|
||||
*/
|
||||
void hasValidSessionCredentials(AsyncCallback<Boolean> callback);
|
||||
|
||||
|
||||
/**
|
||||
* For a combination of an AWS access key ID, the corresponding secret plus an MFA token code produces new session
|
||||
* credentials and stores them in the user's preference store from where they can be obtained again using
|
||||
@@ -139,7 +143,7 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
* {@link #createMfaSessionCredentials(String, String, String)}.
|
||||
*/
|
||||
void clearSessionCredentials(AsyncCallback<Void> callback);
|
||||
|
||||
|
||||
void getApplicationReplicaSets(String regionId, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
AsyncCallback<ArrayList<SailingApplicationReplicaSetDTO<String>>> callback);
|
||||
|
||||
@@ -160,17 +164,23 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
|
||||
void removeApplicationReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToRemove, MongoEndpointDTO moveDatabaseHere,
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDescryption, AsyncCallback<String> callback);
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDescryption, boolean force,
|
||||
AsyncCallback<LiveContentAwareOperationResult<String>> callback);
|
||||
|
||||
void createDefaultLoadBalancerMappings(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToCreateLoadBalancerMappingFor,
|
||||
boolean useDynamicLoadBalancer, String optionalDomainName, boolean forceDNSUpdate,
|
||||
AsyncCallback<SailingApplicationReplicaSetDTO<String>> callback);
|
||||
|
||||
void checkForLiveContent(String regionId,
|
||||
Iterable<SailingApplicationReplicaSetDTO<String>> applicationReplicaSets, String bearerToken,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
AsyncCallback<LiveContentCheckResult> callback);
|
||||
|
||||
void upgradeApplicationReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToUpgrade, String releaseOrNullForLatestMaster,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String replicationBearerToken,
|
||||
AsyncCallback<SailingApplicationReplicaSetDTO<String>> callback);
|
||||
boolean force, AsyncCallback<LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>>> callback);
|
||||
|
||||
void getReleases(AsyncCallback<ArrayList<ReleaseDTO>> asyncCallback);
|
||||
|
||||
@@ -178,8 +188,8 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
String bearerTokenOrNullForApplicationReplicaSetToArchive, String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers, int maxNumberOfCompareServerAttempts,
|
||||
boolean removeApplicationReplicaSet, MongoEndpointDTO moveDatabaseHere, String optionalKeyName,
|
||||
byte[] passphraseForPrivateKeyDecryption,
|
||||
AsyncCallback<Triple<DataImportProgress, CompareServersResultDTO, String>> callback);
|
||||
byte[] passphraseForPrivateKeyDecryption, boolean force,
|
||||
AsyncCallback<LiveContentAwareOperationResult<Triple<DataImportProgress, CompareServersResultDTO, String>>> callback);
|
||||
|
||||
void deployApplicationToExistingHost(String replicaSetName, AwsInstanceDTO hostToDeployTo,
|
||||
String replicaInstanceType, boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster,
|
||||
@@ -189,7 +199,7 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, Integer optionalIgtimiRiotPort,
|
||||
AwsInstanceDTO optionalPreferredInstanceToDeployUnmanagedReplicaTo,
|
||||
AsyncCallback<SailingApplicationReplicaSetDTO<String>> callback);
|
||||
|
||||
|
||||
void createArchiveReplicaSet(String regionId, SailingApplicationReplicaSetDTO<String> applicationReplicaSetToUpgrade,
|
||||
String optionalSharedInstanceType, String releaseOrNullForLatestMaster, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken, String replicaReplicationBearerToken,
|
||||
@@ -198,6 +208,7 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
void makeCandidateArchiveServerGoLive(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> archiveReplicaSetToUpgrade, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, AsyncCallback<Void> callback);
|
||||
|
||||
/**
|
||||
* For the given replica set ensures there is at least one healthy replica, then stops replicating on all replicas and
|
||||
* removes the master from the public and master target groups. This can be used as a preparatory action for upgrading
|
||||
@@ -208,8 +219,8 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
*/
|
||||
void ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSet, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken,
|
||||
AsyncCallback<Boolean> callback);
|
||||
byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken, boolean force,
|
||||
AsyncCallback<LiveContentAwareOperationResult<Boolean>> callback);
|
||||
|
||||
/**
|
||||
* Updates the AMI to use in the launch template version of those of the {@code replicaSets} that have an auto-scaling group.
|
||||
@@ -242,8 +253,8 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
boolean useSharedInstance, String optionalInstanceTypeOrNull, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String optionalMasterReplicationBearerTokenOrNull,
|
||||
String optionalReplicaReplicationBearerTokenOrNull, Integer optionalMemoryInMegabytesOrNull,
|
||||
Integer optionalMemoryTotalSizeFactorOrNull,
|
||||
AsyncCallback<SailingApplicationReplicaSetDTO<String>> callback);
|
||||
Integer optionalMemoryTotalSizeFactorOrNull, boolean force,
|
||||
AsyncCallback<LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>>> callback);
|
||||
|
||||
void changeAutoScalingReplicasInstanceType(SailingApplicationReplicaSetDTO<String> replicaSet,
|
||||
String instanceTypeName, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
@@ -354,7 +365,8 @@ public interface LandscapeManagementWriteServiceAsync {
|
||||
* where the processes are moved away ({@code host})
|
||||
*/
|
||||
void moveAllApplicationProcessesAwayFrom(AwsInstanceDTO host, String optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, AsyncCallback<Void> callback);
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, Set<String> forceMasterReplicaSetNames,
|
||||
AsyncCallback<LiveContentAwareOperationResult<MoveAllApplicationProcessesResultDTO>> callback);
|
||||
|
||||
void hasDNSResourceRecordsForReplicaSet(String replicaSetName, String optionalDomainName, AsyncCallback<Boolean> callback);
|
||||
}
|
||||
+3
@@ -116,6 +116,9 @@ com.sap.sse.gwt.adminconsole.StringMessages {
|
||||
String ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups();
|
||||
String successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups(String replicaSetName);
|
||||
String stopReplicating();
|
||||
String liveContentWarningTitle();
|
||||
String liveContentWarning(String liveContentDetails);
|
||||
String proceedDespiteLiveContent();
|
||||
String sameAsMaster();
|
||||
String firstReplicaOnSharedInstance();
|
||||
String machineImageId();
|
||||
|
||||
+3
@@ -105,6 +105,9 @@ launchAnotherReplicaSetOnThisMaster=Launch another replica set on this master
|
||||
ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups=Ensure at least one replica is running, then stop replication for all replicas and remove master from both target groups
|
||||
successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups=Successfully stopped replicating and removed master from both target groups for replica set {0}
|
||||
stopReplicating=Stop Replicating
|
||||
liveContentWarningTitle=Live race tracking in progress
|
||||
liveContentWarning=The operation was not performed because live race tracking is in progress:\n{0}
|
||||
proceedDespiteLiveContent=Proceed despite live content
|
||||
sameAsMaster=Same as master
|
||||
firstReplicaOnSharedInstance=First replica on shared instance
|
||||
machineImageId=AMI ID
|
||||
|
||||
+3
@@ -104,6 +104,9 @@ memoryTotalSizeFactor=Speicher als Faktor zum gesamten verfügbaren
|
||||
launchAnotherReplicaSetOnThisMaster=Ein zusätzliches Anwendungs-Cluster auf diesem Maste, dass mindestens eine Replika läuft, dann Replikation auf allen Replikas stoppen und Master aus beiden Target Groups entfernen
|
||||
successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups=Replikation erfolgreich angehalten; master wurde erfolgreich aus beiden Target Groups des Anwendungs-Clusters {0} entfernt.
|
||||
stopReplicating=Replikation stoppen
|
||||
liveContentWarningTitle=Live-Regatta-Tracking läuft
|
||||
liveContentWarning=Die Aktion wurde nicht ausgeführt, weil Live-Regatta-Tracking läuft:\n{0}
|
||||
proceedDespiteLiveContent=Trotz Live-Inhalten fortfahren
|
||||
sameAsMaster=Gleich zu Master
|
||||
firstReplicaOnSharedInstance=Erste Replika auf geteilter Instanz
|
||||
machineImageId=AMI ID
|
||||
|
||||
+148
-70
@@ -35,10 +35,13 @@ import com.jcraft.jsch.JSch;
|
||||
import com.jcraft.jsch.JSchException;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.LandscapeService;
|
||||
import com.sap.sailing.landscape.LiveContentConflictException;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsHost;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsMetrics;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsProcess;
|
||||
import com.sap.sailing.landscape.SailingReleaseRepository;
|
||||
import com.sap.sailing.landscape.common.LiveContentAwareOperationResult;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RemoteServiceMappingConstants;
|
||||
import com.sap.sailing.landscape.common.SharedLandscapeConstants;
|
||||
import com.sap.sailing.landscape.impl.SailingAnalyticsHostImpl;
|
||||
@@ -59,6 +62,7 @@ import com.sap.sailing.landscape.ui.shared.LeaderboardNameDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoEndpointDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoProcessDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MongoScalingInstructionsDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.MoveAllApplicationProcessesResultDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ProcessDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReleaseDTO;
|
||||
import com.sap.sailing.landscape.ui.shared.ReverseProxyDTO;
|
||||
@@ -798,26 +802,33 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
}
|
||||
|
||||
@Override
|
||||
public Triple<DataImportProgress, CompareServersResultDTO, String> archiveReplicaSet(String regionId, SailingApplicationReplicaSetDTO<String> applicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForApplicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers,
|
||||
int maxNumberOfCompareServerAttempts, boolean removeApplicationReplicaSet, MongoEndpointDTO moveDatabaseHere,
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDecryption)
|
||||
throws Exception {
|
||||
public LiveContentAwareOperationResult<Triple<DataImportProgress, CompareServersResultDTO, String>> archiveReplicaSet(
|
||||
String regionId, SailingApplicationReplicaSetDTO<String> applicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForApplicationReplicaSetToArchive, String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers, int maxNumberOfCompareServerAttempts,
|
||||
boolean removeApplicationReplicaSet, MongoEndpointDTO moveDatabaseHere, String optionalKeyName,
|
||||
byte[] passphraseForPrivateKeyDecryption, boolean force) throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
if (removeApplicationReplicaSet) {
|
||||
getSecurityService().checkCurrentUserDeletePermission(SecuredSecurityTypes.SERVER.getQualifiedObjectIdentifier(
|
||||
new TypeRelativeObjectIdentifier(applicationReplicaSetToArchive.getReplicaSetName())));
|
||||
}
|
||||
final Triple<DataImportProgress, CompareServersResult, String> result = getLandscapeService().archiveReplicaSet(regionId,
|
||||
convertFromApplicationReplicaSetDTO(new AwsRegion(regionId, getLandscape()), applicationReplicaSetToArchive, optionalKeyName, passphraseForPrivateKeyDecryption),
|
||||
bearerTokenOrNullForApplicationReplicaSetToArchive, bearerTokenOrNullForArchive,
|
||||
durationToWaitBeforeCompareServers, maxNumberOfCompareServerAttempts, removeApplicationReplicaSet,
|
||||
getMongoEndpoint(moveDatabaseHere), optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
final String mongoDBArchivingFailureReason = result.getC();
|
||||
final CompareServersResultDTO compareServersResultDTO = createCompareServersResultDTO(result);
|
||||
return new Triple<>(result.getA(), compareServersResultDTO, mongoDBArchivingFailureReason);
|
||||
LiveContentAwareOperationResult<Triple<DataImportProgress, CompareServersResultDTO, String>> result;
|
||||
try {
|
||||
final Triple<DataImportProgress, CompareServersResult, String> archiveResult = getLandscapeService()
|
||||
.archiveReplicaSet(regionId,
|
||||
convertFromApplicationReplicaSetDTO(new AwsRegion(regionId, getLandscape()),
|
||||
applicationReplicaSetToArchive, optionalKeyName, passphraseForPrivateKeyDecryption),
|
||||
bearerTokenOrNullForApplicationReplicaSetToArchive, bearerTokenOrNullForArchive,
|
||||
durationToWaitBeforeCompareServers, maxNumberOfCompareServerAttempts,
|
||||
removeApplicationReplicaSet, getMongoEndpoint(moveDatabaseHere), optionalKeyName,
|
||||
passphraseForPrivateKeyDecryption, force);
|
||||
result = LiveContentAwareOperationResult.success(new Triple<>(archiveResult.getA(),
|
||||
createCompareServersResultDTO(archiveResult), archiveResult.getC()));
|
||||
} catch (LiveContentConflictException e) {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(e.getLiveContentCheckResult());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private CompareServersResultDTO createCompareServersResultDTO(
|
||||
@@ -831,17 +842,23 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removeApplicationReplicaSet(String regionId,
|
||||
public LiveContentAwareOperationResult<String> removeApplicationReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToRemove, MongoEndpointDTO moveDatabaseHere,
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDecryption)
|
||||
throws Exception {
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDecryption, boolean force) throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
getSecurityService().checkCurrentUserDeletePermission(SecuredSecurityTypes.SERVER.getQualifiedObjectIdentifier(
|
||||
new TypeRelativeObjectIdentifier(applicationReplicaSetToRemove.getReplicaSetName())));
|
||||
final String mongoDbArchivingErrorMessage = getLandscapeService().removeApplicationReplicaSet(regionId, convertFromApplicationReplicaSetDTO(
|
||||
new AwsRegion(regionId, getLandscape()), applicationReplicaSetToRemove, optionalKeyName, passphraseForPrivateKeyDecryption), getMongoEndpoint(moveDatabaseHere),
|
||||
optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
return mongoDbArchivingErrorMessage;
|
||||
LiveContentAwareOperationResult<String> result;
|
||||
try {
|
||||
final String mongoDbArchivingErrorMessage = getLandscapeService().removeApplicationReplicaSet(regionId,
|
||||
convertFromApplicationReplicaSetDTO(new AwsRegion(regionId, getLandscape()),
|
||||
applicationReplicaSetToRemove, optionalKeyName, passphraseForPrivateKeyDecryption),
|
||||
getMongoEndpoint(moveDatabaseHere), optionalKeyName, passphraseForPrivateKeyDecryption, force);
|
||||
result = LiveContentAwareOperationResult.success(mongoDbArchivingErrorMessage);
|
||||
} catch (LiveContentConflictException e) {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(e.getLiveContentCheckResult());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> convertFromApplicationReplicaSetDTO(
|
||||
@@ -911,18 +928,44 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSet,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken) throws Exception {
|
||||
public LiveContentAwareOperationResult<Boolean>
|
||||
ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSet, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken, boolean force)
|
||||
throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
final AwsRegion region = new AwsRegion(regionId, getLandscape());
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet =
|
||||
convertFromApplicationReplicaSetDTO(region, applicationReplicaSet, optionalKeyName, privateKeyEncryptionPassphrase);
|
||||
final String effectiveReplicaReplicationBearerToken = getLandscapeService().getEffectiveBearerToken(replicaReplicationBearerToken);
|
||||
final SailingAnalyticsProcess<String> additionalReplicaStarted = getLandscapeService()
|
||||
.ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(replicaSet,
|
||||
optionalKeyName, privateKeyEncryptionPassphrase, effectiveReplicaReplicationBearerToken);
|
||||
return additionalReplicaStarted != null;
|
||||
convertFromApplicationReplicaSetDTO(region, applicationReplicaSet, optionalKeyName,
|
||||
privateKeyEncryptionPassphrase);
|
||||
final String effectiveReplicaReplicationBearerToken = getLandscapeService()
|
||||
.getEffectiveBearerToken(replicaReplicationBearerToken);
|
||||
LiveContentAwareOperationResult<Boolean> result;
|
||||
try {
|
||||
final SailingAnalyticsProcess<String> additionalReplicaStarted = getLandscapeService()
|
||||
.ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(replicaSet,
|
||||
optionalKeyName, privateKeyEncryptionPassphrase, effectiveReplicaReplicationBearerToken,
|
||||
force);
|
||||
result = LiveContentAwareOperationResult.success(additionalReplicaStarted != null);
|
||||
} catch (LiveContentConflictException e) {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(e.getLiveContentCheckResult());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveContentCheckResult checkForLiveContent(final String regionId,
|
||||
final Iterable<SailingApplicationReplicaSetDTO<String>> applicationReplicaSets, final String bearerToken,
|
||||
final String optionalKeyName, final byte[] privateKeyEncryptionPassphrase) throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
final AwsRegion region = new AwsRegion(regionId, getLandscape());
|
||||
final List<AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>>> replicaSets =
|
||||
new ArrayList<>();
|
||||
for (final SailingApplicationReplicaSetDTO<String> applicationReplicaSet : applicationReplicaSets) {
|
||||
replicaSets.add(convertFromApplicationReplicaSetDTO(region, applicationReplicaSet, optionalKeyName,
|
||||
privateKeyEncryptionPassphrase));
|
||||
}
|
||||
return getLandscapeService().checkForLiveContent(replicaSets, bearerToken);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -932,30 +975,44 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
* for details.
|
||||
*/
|
||||
@Override
|
||||
public SailingApplicationReplicaSetDTO<String> upgradeApplicationReplicaSet(String regionId,
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetToUpgrade, String releaseOrNullForLatestMaster,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String replicaReplicationBearerToken) throws Exception {
|
||||
public LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> upgradeApplicationReplicaSet(
|
||||
String regionId, SailingApplicationReplicaSetDTO<String> applicationReplicaSetToUpgrade,
|
||||
String releaseOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String replicaReplicationBearerToken, boolean force) throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
final AwsRegion region = new AwsRegion(regionId, getLandscape());
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet =
|
||||
convertFromApplicationReplicaSetDTO(region, applicationReplicaSetToUpgrade, optionalKeyName, privateKeyEncryptionPassphrase);
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> upgradedReplicaSet =
|
||||
getLandscapeService().upgradeApplicationReplicaSet(region, replicaSet,
|
||||
releaseOrNullForLatestMaster, optionalKeyName, privateKeyEncryptionPassphrase,
|
||||
replicaReplicationBearerToken);
|
||||
final SailingAnalyticsProcess<String> oldMaster = replicaSet.getMaster();
|
||||
final Release release = upgradedReplicaSet.getVersion(Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
return new SailingApplicationReplicaSetDTO<String>(applicationReplicaSetToUpgrade.getName(),
|
||||
convertToSailingAnalyticsProcessDTO(oldMaster, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase),
|
||||
Util.map(upgradedReplicaSet.getReplicas(), r->{
|
||||
try {
|
||||
return convertToSailingAnalyticsProcessDTO(r, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}),
|
||||
release.getName(), release.getReleaseNotesURL().toString(),
|
||||
applicationReplicaSetToUpgrade.getHostname(), applicationReplicaSetToUpgrade.getDefaultRedirectPath(), applicationReplicaSetToUpgrade.getAutoScalingGroupAmiId());
|
||||
convertFromApplicationReplicaSetDTO(region, applicationReplicaSetToUpgrade, optionalKeyName,
|
||||
privateKeyEncryptionPassphrase);
|
||||
LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> result;
|
||||
try {
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> upgradedReplicaSet =
|
||||
getLandscapeService().upgradeApplicationReplicaSet(region, replicaSet,
|
||||
releaseOrNullForLatestMaster, optionalKeyName, privateKeyEncryptionPassphrase,
|
||||
replicaReplicationBearerToken, force);
|
||||
final SailingAnalyticsProcess<String> oldMaster = replicaSet.getMaster();
|
||||
final Release release = upgradedReplicaSet.getVersion(Landscape.WAIT_FOR_PROCESS_TIMEOUT,
|
||||
Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
final SailingApplicationReplicaSetDTO<String> upgradedReplicaSetDTO =
|
||||
new SailingApplicationReplicaSetDTO<String>(applicationReplicaSetToUpgrade.getName(),
|
||||
convertToSailingAnalyticsProcessDTO(oldMaster, Optional.ofNullable(optionalKeyName),
|
||||
privateKeyEncryptionPassphrase),
|
||||
Util.map(upgradedReplicaSet.getReplicas(), r->{
|
||||
try {
|
||||
return convertToSailingAnalyticsProcessDTO(r, Optional.ofNullable(optionalKeyName),
|
||||
privateKeyEncryptionPassphrase);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}), release.getName(), release.getReleaseNotesURL().toString(),
|
||||
applicationReplicaSetToUpgrade.getHostname(),
|
||||
applicationReplicaSetToUpgrade.getDefaultRedirectPath(),
|
||||
applicationReplicaSetToUpgrade.getAutoScalingGroupAmiId());
|
||||
result = LiveContentAwareOperationResult.success(upgradedReplicaSetDTO);
|
||||
} catch (LiveContentConflictException e) {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(e.getLiveContentCheckResult());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1021,22 +1078,33 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
}
|
||||
|
||||
@Override
|
||||
public SailingApplicationReplicaSetDTO<String> moveMasterToOtherInstance(
|
||||
public LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> moveMasterToOtherInstance(
|
||||
SailingApplicationReplicaSetDTO<String> applicationReplicaSetDTO, boolean useSharedInstance,
|
||||
String optionalInstanceTypeOrNull,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String optionalMasterReplicationBearerTokenOrNull,
|
||||
String optionalReplicaReplicationBearerTokenOrNull, Integer optionalMemoryInMegabytesOrNull,
|
||||
Integer optionalMemoryTotalSizeFactorOrNull) throws Exception {
|
||||
String optionalInstanceTypeOrNull, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String optionalMasterReplicationBearerTokenOrNull, String optionalReplicaReplicationBearerTokenOrNull,
|
||||
Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, boolean force)
|
||||
throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
final AwsRegion region = new AwsRegion(applicationReplicaSetDTO.getMaster().getHost().getRegion(), getLandscape());
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet =
|
||||
convertFromApplicationReplicaSetDTO(region, applicationReplicaSetDTO, optionalKeyName, privateKeyEncryptionPassphrase);
|
||||
return convertToSailingApplicationReplicaSetDTO(
|
||||
getLandscapeService().moveMasterToOtherInstance(replicaSet, useSharedInstance,
|
||||
optionalInstanceTypeOrNull==null?Optional.empty():Optional.of(InstanceType.valueOf(optionalInstanceTypeOrNull)),
|
||||
/* optionalPreferredInstanceToDeployTo */ Optional.empty(), optionalKeyName,
|
||||
privateKeyEncryptionPassphrase, optionalMasterReplicationBearerTokenOrNull, optionalReplicaReplicationBearerTokenOrNull,
|
||||
optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull), Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
convertFromApplicationReplicaSetDTO(region, applicationReplicaSetDTO, optionalKeyName,
|
||||
privateKeyEncryptionPassphrase);
|
||||
LiveContentAwareOperationResult<SailingApplicationReplicaSetDTO<String>> result;
|
||||
try {
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> movedReplicaSet =
|
||||
getLandscapeService().moveMasterToOtherInstance(replicaSet, useSharedInstance,
|
||||
optionalInstanceTypeOrNull == null ? Optional.empty()
|
||||
: Optional.of(InstanceType.valueOf(optionalInstanceTypeOrNull)),
|
||||
/* optionalPreferredInstanceToDeployTo */ Optional.empty(), optionalKeyName,
|
||||
privateKeyEncryptionPassphrase, optionalMasterReplicationBearerTokenOrNull,
|
||||
optionalReplicaReplicationBearerTokenOrNull, optionalMemoryInMegabytesOrNull,
|
||||
optionalMemoryTotalSizeFactorOrNull, force);
|
||||
result = LiveContentAwareOperationResult.success(convertToSailingApplicationReplicaSetDTO(movedReplicaSet,
|
||||
Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase));
|
||||
} catch (LiveContentConflictException e) {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(e.getLiveContentCheckResult());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1141,14 +1209,24 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAllApplicationProcessesAwayFrom(AwsInstanceDTO host, String optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception {
|
||||
public LiveContentAwareOperationResult<MoveAllApplicationProcessesResultDTO> moveAllApplicationProcessesAwayFrom(
|
||||
AwsInstanceDTO host, String optionalInstanceTypeForNewInstance, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, Set<String> forceMasterReplicaSetNames) throws Exception {
|
||||
checkLandscapeManageAwsPermission();
|
||||
final SailingAnalyticsHost<String> sailingAnalyticsHost = getHostFromInstanceDTO(host);
|
||||
getLandscapeService().moveAllApplicationProcessesAwayFrom(sailingAnalyticsHost,
|
||||
Optional.ofNullable(optionalInstanceTypeForNewInstance == null ? null
|
||||
: InstanceType.valueOf(optionalInstanceTypeForNewInstance)),
|
||||
optionalKeyName, privateKeyEncryptionPassphrase);
|
||||
LiveContentAwareOperationResult<MoveAllApplicationProcessesResultDTO> result;
|
||||
try {
|
||||
final Triple<SailingAnalyticsHost<String>, Map<String, SailingAnalyticsProcess<String>>, Map<String, SailingAnalyticsProcess<String>>> moveResult =
|
||||
getLandscapeService().moveAllApplicationProcessesAwayFrom(sailingAnalyticsHost,
|
||||
Optional.ofNullable(optionalInstanceTypeForNewInstance == null ? null
|
||||
: InstanceType.valueOf(optionalInstanceTypeForNewInstance)), optionalKeyName,
|
||||
privateKeyEncryptionPassphrase, forceMasterReplicaSetNames);
|
||||
result = LiveContentAwareOperationResult.success(
|
||||
new MoveAllApplicationProcessesResultDTO(moveResult.getA().getId()));
|
||||
} catch (LiveContentConflictException e) {
|
||||
result = LiveContentAwareOperationResult.liveContentConflict(e.getLiveContentCheckResult());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.sap.sailing.landscape.ui.shared;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/** Identifies the destination host created while moving all application processes away from another host. */
|
||||
public final class MoveAllApplicationProcessesResultDTO implements Serializable {
|
||||
private static final long serialVersionUID = -3986005892785249498L;
|
||||
private final String newHostId;
|
||||
|
||||
public MoveAllApplicationProcessesResultDTO(final String newHostId) {
|
||||
this.newHostId = newHostId;
|
||||
}
|
||||
|
||||
public String getNewHostId() {
|
||||
return newHostId;
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,12 @@ import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.SharedLandscapeConstants;
|
||||
import com.sap.sailing.landscape.procedures.DeployProcessOnMultiServer;
|
||||
import com.sap.sailing.landscape.procedures.SailingAnalyticsMasterConfiguration;
|
||||
@@ -221,12 +223,15 @@ public interface LandscapeService {
|
||||
/**
|
||||
* @return the reports on the master data import and content comparison;
|
||||
*/
|
||||
LiveContentCheckResult checkForLiveContent(Iterable<AwsApplicationReplicaSet<String, SailingAnalyticsMetrics,
|
||||
SailingAnalyticsProcess<String>>> applicationReplicaSets, String bearerToken) throws Exception;
|
||||
|
||||
Triple<DataImportProgress, CompareServersResult, String> archiveReplicaSet(String regionId,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> applicationReplicaSetToArchive,
|
||||
String bearerTokenOrNullForApplicationReplicaSetToArchive, String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers, int maxNumberOfCompareServerAttempts,
|
||||
boolean removeApplicationReplicaSet, MongoEndpoint moveDatabaseHere, String optionalKeyName,
|
||||
byte[] passphraseForPrivateKeyDecryption) throws Exception;
|
||||
byte[] passphraseForPrivateKeyDecryption, boolean force) throws Exception;
|
||||
|
||||
/**
|
||||
* If the replica set is mapped through DNS, the DNS record is removed first, before any attempts are made to shut
|
||||
@@ -244,7 +249,8 @@ public interface LandscapeService {
|
||||
*/
|
||||
String removeApplicationReplicaSet(String regionId,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> applicationReplicaSetToRemove,
|
||||
MongoEndpoint moveDatabaseHere, String optionalKeyName, byte[] passphraseForPrivateKeyDecryption) throws Exception;
|
||||
MongoEndpoint moveDatabaseHere, String optionalKeyName, byte[] passphraseForPrivateKeyDecryption,
|
||||
boolean force) throws Exception;
|
||||
|
||||
Release getRelease(String releaseNameOrNullForLatestMaster);
|
||||
|
||||
@@ -289,7 +295,7 @@ public interface LandscapeService {
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> upgradeApplicationReplicaSet(AwsRegion region,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
|
||||
String releaseOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String replicaReplicationBearerToken) throws InterruptedException, ExecutionException,
|
||||
String replicaReplicationBearerToken, boolean force) throws InterruptedException, ExecutionException,
|
||||
MalformedURLException, IOException, TimeoutException, Exception;
|
||||
|
||||
/**
|
||||
@@ -299,8 +305,8 @@ public interface LandscapeService {
|
||||
SailingAnalyticsProcess<String> ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String effectiveReplicaReplicationBearerToken) throws Exception, MalformedURLException, IOException,
|
||||
TimeoutException, InterruptedException, ExecutionException;
|
||||
String effectiveReplicaReplicationBearerToken, boolean force) throws Exception, MalformedURLException,
|
||||
IOException, TimeoutException, InterruptedException, ExecutionException;
|
||||
|
||||
/**
|
||||
* For an existing replica set deploys a new replica onto an existing host. The host may be shared by multiple
|
||||
@@ -443,8 +449,8 @@ public interface LandscapeService {
|
||||
Optional<SailingAnalyticsHost<String>> optionalPreferredInstanceToDeployTo, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String optionalMasterReplicationBearerTokenOrNull,
|
||||
String optionalReplicaReplicationBearerTokenOrNull, Integer optionalMemoryInMegabytesOrNull,
|
||||
Integer optionalMemoryTotalSizeFactorOrNull) throws MalformedURLException, IOException, TimeoutException,
|
||||
InterruptedException, ExecutionException, Exception;
|
||||
Integer optionalMemoryTotalSizeFactorOrNull, boolean force) throws MalformedURLException, IOException,
|
||||
TimeoutException, InterruptedException, ExecutionException, Exception;
|
||||
|
||||
/**
|
||||
* If the {@code replicaSet} provided has one or more auto-scaling groups, their default launch template version is
|
||||
@@ -517,7 +523,8 @@ public interface LandscapeService {
|
||||
Triple<SailingAnalyticsHost<String>, Map<String, SailingAnalyticsProcess<String>>, Map<String, SailingAnalyticsProcess<String>>>
|
||||
moveAllApplicationProcessesAwayFrom(SailingAnalyticsHost<String> host,
|
||||
Optional<InstanceType> optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
Set<String> forceMasterReplicaSetNames) throws Exception;
|
||||
|
||||
String getHostname(String replicaSetName, String optionalDomainName);
|
||||
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.sap.sailing.landscape;
|
||||
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
|
||||
/** Raised before a landscape operation would affect a replica set containing live tracked races. */
|
||||
public final class LiveContentConflictException extends Exception {
|
||||
private static final long serialVersionUID = 291018425020458180L;
|
||||
private final LiveContentCheckResult liveContentCheckResult;
|
||||
|
||||
public LiveContentConflictException(final LiveContentCheckResult liveContentCheckResult) {
|
||||
super("The operation would affect " + liveContentCheckResult.getReplicaSetsWithLiveContent().size()
|
||||
+ " application replica set(s) containing live tracked races");
|
||||
this.liveContentCheckResult = liveContentCheckResult;
|
||||
}
|
||||
|
||||
public LiveContentCheckResult getLiveContentCheckResult() {
|
||||
return liveContentCheckResult;
|
||||
}
|
||||
}
|
||||
+70
-14
@@ -37,11 +37,14 @@ import com.sap.sailing.landscape.ALBToReverseProxyArchiveRedirectMapper;
|
||||
import com.sap.sailing.landscape.AwsSessionCredentialsWithExpiry;
|
||||
import com.sap.sailing.landscape.EligibleInstanceForReplicaSetFindingStrategy;
|
||||
import com.sap.sailing.landscape.LandscapeService;
|
||||
import com.sap.sailing.landscape.LiveContentConflictException;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsHost;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsMetrics;
|
||||
import com.sap.sailing.landscape.SailingAnalyticsProcess;
|
||||
import com.sap.sailing.landscape.SailingReleaseRepository;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RemoteServiceMappingConstants;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
import com.sap.sailing.landscape.common.SharedLandscapeConstants;
|
||||
import com.sap.sailing.landscape.procedures.CreateLaunchTemplateAndAutoScalingGroup;
|
||||
import com.sap.sailing.landscape.procedures.DeployProcessOnMultiServer;
|
||||
@@ -588,6 +591,32 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
return replica;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveContentCheckResult checkForLiveContent(
|
||||
final Iterable<AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>>> applicationReplicaSets,
|
||||
final String bearerToken) throws Exception {
|
||||
final String effectiveBearerToken = getEffectiveBearerToken(bearerToken);
|
||||
final long checkedAtMillis = TimePoint.now().asMillis();
|
||||
final List<ReplicaSetLiveContent> replicaSetsWithLiveContent = new ArrayList<>();
|
||||
for (final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet : applicationReplicaSets) {
|
||||
final SailingServer server = sailingServerFactoryTracker.getService().getSailingServer(new URL("https", replicaSet.getHostname(), "/"), effectiveBearerToken);
|
||||
final LiveContentCheckResult replicaSetResult = server.getLiveContent(checkedAtMillis);
|
||||
replicaSetsWithLiveContent.addAll(replicaSetResult.getReplicaSetsWithLiveContent());
|
||||
}
|
||||
return new LiveContentCheckResult(checkedAtMillis, replicaSetsWithLiveContent);
|
||||
}
|
||||
|
||||
private void checkForLiveContentUnlessForced(
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
|
||||
final String bearerToken, final boolean force) throws Exception {
|
||||
if (!force) {
|
||||
final LiveContentCheckResult liveContentCheckResult = checkForLiveContent(Collections.singleton(replicaSet), bearerToken);
|
||||
if (liveContentCheckResult.hasLiveContent()) {
|
||||
throw new LiveContentConflictException(liveContentCheckResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Util.Triple<DataImportProgress, CompareServersResult, String> archiveReplicaSet(String regionId,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> applicationReplicaSetToArchive,
|
||||
@@ -595,8 +624,9 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
String bearerTokenOrNullForArchive,
|
||||
Duration durationToWaitBeforeCompareServers,
|
||||
int maxNumberOfCompareServerAttempts, boolean removeApplicationReplicaSet, MongoEndpoint moveDatabaseHere,
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDecryption)
|
||||
String optionalKeyName, byte[] passphraseForPrivateKeyDecryption, boolean force)
|
||||
throws Exception {
|
||||
checkForLiveContentUnlessForced(applicationReplicaSetToArchive, bearerTokenOrNullForApplicationReplicaSetToArchive, force);
|
||||
if (removeApplicationReplicaSet && applicationReplicaSetToArchive.isLocalReplicaSet()) {
|
||||
throw new IllegalArgumentException("A replica set cannot archive itself if it is going to be removed. Current replica set: "+ServerInfo.getName());
|
||||
}
|
||||
@@ -661,6 +691,7 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
getLandscape().getCentralReverseProxy(region);
|
||||
// TODO bug5311: when refactoring this for general scope migration, moving to a dedicated replica set will not require this
|
||||
// TODO bug5311: when refactoring this for general scope migration, moving into a cold storage server other than ARCHIVE will require ALBToReverseProxyRedirectMapper instead
|
||||
checkForLiveContentUnlessForced(applicationReplicaSetToArchive, bearerTokenOrNullForApplicationReplicaSetToArchive, force);
|
||||
logger.info("Adding reverse proxy rules for migrated content pointing to ARCHIVE");
|
||||
defaultRedirect.accept(new ALBToReverseProxyArchiveRedirectMapper<>(
|
||||
reverseProxyCluster, hostnameFromWhichToArchive, Optional.ofNullable(optionalKeyName), passphraseForPrivateKeyDecryption));
|
||||
@@ -674,7 +705,7 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
"; probably such a reference didn't exist");
|
||||
}
|
||||
logger.info("Removing the application replica set archived ("+from+") was requested");
|
||||
mongoDbArchivingErrorMessage = removeApplicationReplicaSet(regionId, applicationReplicaSetToArchive, moveDatabaseHere, optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
mongoDbArchivingErrorMessage = removeApplicationReplicaSetInternal(regionId, applicationReplicaSetToArchive, moveDatabaseHere, optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
} else {
|
||||
mongoDbArchivingErrorMessage = null;
|
||||
logger.info("Removing remote sailing server references to events on "+from+" with IDs "+eventIDs+" from archive server "+archive);
|
||||
@@ -721,7 +752,15 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String removeApplicationReplicaSet(String regionId,
|
||||
public String removeApplicationReplicaSet(final String regionId,
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> applicationReplicaSet,
|
||||
final MongoEndpoint moveDatabaseHere, final String optionalKeyName,
|
||||
final byte[] passphraseForPrivateKeyDecryption, final boolean force) throws Exception {
|
||||
checkForLiveContentUnlessForced(applicationReplicaSet, /* bearerToken */ null, force);
|
||||
return removeApplicationReplicaSetInternal(regionId, applicationReplicaSet, moveDatabaseHere, optionalKeyName, passphraseForPrivateKeyDecryption);
|
||||
}
|
||||
|
||||
private String removeApplicationReplicaSetInternal(String regionId,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> applicationReplicaSet,
|
||||
MongoEndpoint moveDatabaseHere, String optionalKeyName, byte[] passphraseForPrivateKeyDecryption)
|
||||
throws Exception {
|
||||
@@ -1209,8 +1248,9 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
public AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> upgradeApplicationReplicaSet(AwsRegion region,
|
||||
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
|
||||
String releaseOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
String replicaReplicationBearerToken)
|
||||
String replicaReplicationBearerToken, boolean force)
|
||||
throws MalformedURLException, IOException, TimeoutException, Exception {
|
||||
checkForLiveContentUnlessForced(replicaSet, replicaReplicationBearerToken, force);
|
||||
if (replicaSet.isLocalReplicaSet()) {
|
||||
throw new IllegalArgumentException(
|
||||
"A replica set cannot upgrade itself. Current replica set: " + ServerInfo.getName());
|
||||
@@ -1241,7 +1281,8 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
final Set<SailingAnalyticsProcess<String>> replicasToStopAfterUpgradingMaster = new HashSet<>();
|
||||
Util.addAll(replicaSet.getReplicas(), replicasToStopAfterUpgradingMaster);
|
||||
final SailingAnalyticsProcess<String> additionalReplicaStarted = ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(
|
||||
replicaSet, optionalKeyName, privateKeyEncryptionPassphrase, effectiveReplicaReplicationBearerToken);
|
||||
replicaSet, optionalKeyName, privateKeyEncryptionPassphrase, effectiveReplicaReplicationBearerToken,
|
||||
/* force: outer operation already checked */ true);
|
||||
if (replicaSet.getAutoScalingGroup() != null) {
|
||||
getLandscape().updateReleaseInAutoScalingGroups(region, replicaSet.getAutoScalingGroup().getLaunchTemplate(),
|
||||
affectedAutoScalingGroups, replicaSet.getName(), release);
|
||||
@@ -1477,8 +1518,9 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
public SailingAnalyticsProcess<String> ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(
|
||||
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase,
|
||||
final String effectiveReplicaReplicationBearerToken) throws Exception, MalformedURLException, IOException,
|
||||
final String effectiveReplicaReplicationBearerToken, final boolean force) throws Exception, MalformedURLException, IOException,
|
||||
TimeoutException, InterruptedException, ExecutionException {
|
||||
checkForLiveContentUnlessForced(replicaSet, effectiveReplicaReplicationBearerToken, force);
|
||||
final Set<SailingAnalyticsProcess<String>> replicasToStopReplicating = new HashSet<>();
|
||||
Util.addAll(replicaSet.getReplicas(), replicasToStopReplicating);
|
||||
final SailingAnalyticsProcess<String> additionalReplicaStarted;
|
||||
@@ -1770,16 +1812,18 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
final boolean useSharedInstance, Optional<InstanceType> optionalInstanceType,
|
||||
Optional<SailingAnalyticsHost<String>> optionalPreferredInstanceToDeployTo, String optionalKeyName,
|
||||
byte[] privateKeyEncryptionPassphrase, String optionalMasterReplicationBearerTokenOrNull, final String optionalReplicaReplicationBearerTokenOrNull, Integer optionalMemoryInMegabytesOrNull,
|
||||
Integer optionalMemoryTotalSizeFactorOrNull)
|
||||
Integer optionalMemoryTotalSizeFactorOrNull, final boolean force)
|
||||
throws MalformedURLException,
|
||||
IOException, TimeoutException, InterruptedException, ExecutionException, Exception {
|
||||
checkForLiveContentUnlessForced(replicaSet, optionalMasterReplicationBearerTokenOrNull, force);
|
||||
final Integer igtimiRiotPort = replicaSet.getMaster().getIgtimiRiotPort(Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
if (replicaSet.isLocalReplicaSet()) {
|
||||
throw new IllegalArgumentException("A replica set cannot move its own master process. Current replica set: "+ServerInfo.getName());
|
||||
}
|
||||
final SailingAnalyticsProcess<String> newTemporaryReplica = ensureAtLeastOneReplicaExistsStopReplicatingAndRemoveMasterFromTargetGroups(replicaSet,
|
||||
optionalKeyName, privateKeyEncryptionPassphrase,
|
||||
getEffectiveBearerToken(optionalReplicaReplicationBearerTokenOrNull));
|
||||
getEffectiveBearerToken(optionalReplicaReplicationBearerTokenOrNull),
|
||||
/* force: move operation already checked */ true);
|
||||
// important to obtain the release before stopping master:
|
||||
final Release release = replicaSet.getVersion(Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
final AwsRegion region = replicaSet.getMaster().getHost().getRegion();
|
||||
@@ -2153,7 +2197,7 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
public Triple<SailingAnalyticsHost<String>, Map<String, SailingAnalyticsProcess<String>>, Map<String, SailingAnalyticsProcess<String>>>
|
||||
moveAllApplicationProcessesAwayFrom(SailingAnalyticsHost<String> host,
|
||||
Optional<InstanceType> optionalInstanceTypeForNewInstance,
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception {
|
||||
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, Set<String> forceMasterReplicaSetNames) throws Exception {
|
||||
if (!host.getInstance().tags().stream().anyMatch(tag->
|
||||
tag.key().equals(SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG) &&
|
||||
tag.value().equals(SharedLandscapeConstants.MULTI_PROCESS_INSTANCE_TAG_VALUE))) {
|
||||
@@ -2164,6 +2208,21 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
logger.info("Moving all application processes from shared host "+host+" to a newly started shared host.");
|
||||
final AwsRegion region = host.getRegion();
|
||||
final HostSupplier<String, SailingAnalyticsHost<String>> hostSupplier = new SailingAnalyticsHostSupplier<>();
|
||||
final Iterable<AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>>> replicaSets = getLandscape()
|
||||
.getApplicationReplicaSetsByTag(region, SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG,
|
||||
hostSupplier, Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName),
|
||||
privateKeyEncryptionPassphrase);
|
||||
final List<AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>>> unforcedMasterReplicaSets = new ArrayList<>();
|
||||
for (final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet : replicaSets) {
|
||||
if (replicaSet.getMaster().getHost().getId().equals(host.getId())
|
||||
&& !forceMasterReplicaSetNames.contains(replicaSet.getName())) {
|
||||
unforcedMasterReplicaSets.add(replicaSet);
|
||||
}
|
||||
}
|
||||
final LiveContentCheckResult liveContentCheckResult = checkForLiveContent(unforcedMasterReplicaSets, /* bearerToken */ null);
|
||||
if (liveContentCheckResult.hasLiveContent()) {
|
||||
throw new LiveContentConflictException(liveContentCheckResult);
|
||||
}
|
||||
final SailingAnalyticsHost<String> targetHost = createEmptyMultiServer(region,
|
||||
Optional.of(optionalInstanceTypeForNewInstance.orElse(host.getInstanceType())),
|
||||
Optional.of(host.getAvailabilityZone()),
|
||||
@@ -2171,10 +2230,7 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
|
||||
final Map<String, SailingAnalyticsProcess<String>> masterProcessesMoved = new HashMap<>();
|
||||
final Map<String, SailingAnalyticsProcess<String>> replicaProcessesMoved = new HashMap<>();
|
||||
for (final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet : getLandscape()
|
||||
.getApplicationReplicaSetsByTag(region, SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG,
|
||||
hostSupplier, Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName),
|
||||
privateKeyEncryptionPassphrase)) {
|
||||
for (final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet : replicaSets) {
|
||||
if (replicaSet.getMaster().getHost().getId().equals(host.getId())) {
|
||||
// We're moving a master process:
|
||||
logger.info("Found master process "+replicaSet.getMaster()+" on host "+host+" to move to "+targetHost);
|
||||
@@ -2208,7 +2264,7 @@ public class LandscapeServiceImpl implements LandscapeService {
|
||||
privateKeyEncryptionPassphrase),
|
||||
replicaReplicationBearerToken,
|
||||
totalMemorySizeFactor == null ? getMemoryInMegabytes(optionalKeyName, privateKeyEncryptionPassphrase, replicaSet.getMaster()) : null,
|
||||
totalMemorySizeFactor);
|
||||
totalMemorySizeFactor, /* force: all affected masters were checked above */ true);
|
||||
logger.info("Done moving master of "+replicaSet.getName()+" from "+host+" to "+targetHost);
|
||||
} else {
|
||||
final SailingAnalyticsProcess<String> replica;
|
||||
|
||||
@@ -8,6 +8,7 @@ Automatic-Module-Name: com.sap.sailing.server.gateway.interface
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Export-Package: com.sap.sailing.server.gateway.interfaces
|
||||
Import-Package: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.landscape.common,
|
||||
com.sap.sse.common,
|
||||
com.sap.sse.security.util
|
||||
Require-Bundle: org.json.simple,
|
||||
|
||||
+3
@@ -12,6 +12,7 @@ import org.json.simple.parser.ParseException;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sse.security.util.SecuredServer;
|
||||
import com.sap.sse.shared.json.JsonDeserializationException;
|
||||
|
||||
@@ -55,6 +56,8 @@ public interface SailingServer extends SecuredServer {
|
||||
*/
|
||||
Iterable<EventBase> getEvents() throws Exception;
|
||||
|
||||
LiveContentCheckResult getLiveContent(long checkedAtMillis) throws Exception;
|
||||
|
||||
MasterDataImportResult importMasterData(SailingServer from, Iterable<UUID> leaderboardGroupIds, boolean override,
|
||||
boolean compress, boolean exportWind, boolean exportDeviceConfigs,
|
||||
boolean exportTrackedRacesAndStartTracking, Optional<UUID> progressTrackingUuid) throws Exception;
|
||||
|
||||
@@ -7,6 +7,7 @@ Bundle-Vendor: SAP
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Import-Package:
|
||||
com.sap.sailing.declination,
|
||||
com.sap.sailing.landscape.common,
|
||||
org.json.simple
|
||||
Require-Bundle: com.sap.sailing.domain.common,
|
||||
com.sap.sailing.domain.shared.android,
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.sap.sailing.server.gateway.deserialization.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.LiveContentCheckResultJsonSerializer;
|
||||
import com.sap.sse.shared.json.JsonDeserializationException;
|
||||
import com.sap.sse.shared.json.JsonDeserializer;
|
||||
|
||||
public final class LiveContentCheckResultJsonDeserializer implements JsonDeserializer<LiveContentCheckResult> {
|
||||
@Override
|
||||
public LiveContentCheckResult deserialize(final JSONObject object) throws JsonDeserializationException {
|
||||
final List<ReplicaSetLiveContent> replicaSets = new ArrayList<>();
|
||||
for (final Object serializedReplicaSetObject : (JSONArray) object.get(
|
||||
LiveContentCheckResultJsonSerializer.REPLICA_SETS)) {
|
||||
final JSONObject serializedReplicaSet = (JSONObject) serializedReplicaSetObject;
|
||||
final List<EventLiveContent> events = new ArrayList<>();
|
||||
for (final Object serializedEventObject : (JSONArray) serializedReplicaSet.get(
|
||||
LiveContentCheckResultJsonSerializer.EVENTS)) {
|
||||
final JSONObject serializedEvent = (JSONObject) serializedEventObject;
|
||||
final List<RaceLiveContent> races = new ArrayList<>();
|
||||
for (final Object serializedRaceObject : (JSONArray) serializedEvent.get(
|
||||
LiveContentCheckResultJsonSerializer.RACES)) {
|
||||
final JSONObject serializedRace = (JSONObject) serializedRaceObject;
|
||||
races.add(new RaceLiveContent(
|
||||
(String) serializedRace.get(LiveContentCheckResultJsonSerializer.REGATTA_NAME),
|
||||
(String) serializedRace.get(LiveContentCheckResultJsonSerializer.RACE_NAME),
|
||||
((Number) serializedRace.get(LiveContentCheckResultJsonSerializer.TRACKING_START_MILLIS))
|
||||
.longValue(),
|
||||
asLong(serializedRace.get(LiveContentCheckResultJsonSerializer.TRACKING_END_MILLIS))));
|
||||
}
|
||||
events.add(new EventLiveContent(
|
||||
(String) serializedEvent.get(LiveContentCheckResultJsonSerializer.EVENT_ID),
|
||||
(String) serializedEvent.get(LiveContentCheckResultJsonSerializer.EVENT_NAME),
|
||||
asLong(serializedEvent.get(LiveContentCheckResultJsonSerializer.EVENT_START_MILLIS)),
|
||||
asLong(serializedEvent.get(LiveContentCheckResultJsonSerializer.EVENT_END_MILLIS)), races));
|
||||
}
|
||||
replicaSets.add(new ReplicaSetLiveContent(
|
||||
(String) serializedReplicaSet.get(LiveContentCheckResultJsonSerializer.REPLICA_SET_NAME), events));
|
||||
}
|
||||
return new LiveContentCheckResult(
|
||||
((Number) object.get(LiveContentCheckResultJsonSerializer.CHECKED_AT_MILLIS)).longValue(), replicaSets);
|
||||
}
|
||||
|
||||
private Long asLong(final Object value) {
|
||||
return value == null ? null : ((Number) value).longValue();
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.sap.sailing.server.gateway.serialization.impl;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
import com.sap.sse.shared.json.JsonSerializer;
|
||||
|
||||
public final class LiveContentCheckResultJsonSerializer implements JsonSerializer<LiveContentCheckResult> {
|
||||
public static final String CHECKED_AT_MILLIS = "checkedAtMillis";
|
||||
public static final String REPLICA_SETS = "replicaSets";
|
||||
public static final String REPLICA_SET_NAME = "replicaSetName";
|
||||
public static final String EVENTS = "events";
|
||||
public static final String EVENT_ID = "eventId";
|
||||
public static final String EVENT_NAME = "eventName";
|
||||
public static final String EVENT_START_MILLIS = "eventStartMillis";
|
||||
public static final String EVENT_END_MILLIS = "eventEndMillis";
|
||||
public static final String RACES = "races";
|
||||
public static final String REGATTA_NAME = "regattaName";
|
||||
public static final String RACE_NAME = "raceName";
|
||||
public static final String TRACKING_START_MILLIS = "trackingStartMillis";
|
||||
public static final String TRACKING_END_MILLIS = "trackingEndMillis";
|
||||
|
||||
@Override
|
||||
public JSONObject serialize(final LiveContentCheckResult liveContentCheckResult) {
|
||||
final JSONObject result = new JSONObject();
|
||||
result.put(CHECKED_AT_MILLIS, liveContentCheckResult.getCheckedAtMillis());
|
||||
final JSONArray replicaSets = new JSONArray();
|
||||
for (final ReplicaSetLiveContent replicaSet : liveContentCheckResult.getReplicaSetsWithLiveContent()) {
|
||||
final JSONObject serializedReplicaSet = new JSONObject();
|
||||
serializedReplicaSet.put(REPLICA_SET_NAME, replicaSet.getReplicaSetName());
|
||||
final JSONArray events = new JSONArray();
|
||||
for (final EventLiveContent event : replicaSet.getEventsWithLiveContent()) {
|
||||
final JSONObject serializedEvent = new JSONObject();
|
||||
serializedEvent.put(EVENT_ID, event.getEventId());
|
||||
serializedEvent.put(EVENT_NAME, event.getEventName());
|
||||
serializedEvent.put(EVENT_START_MILLIS, event.getEventStartMillis());
|
||||
serializedEvent.put(EVENT_END_MILLIS, event.getEventEndMillis());
|
||||
final JSONArray races = new JSONArray();
|
||||
for (final RaceLiveContent race : event.getRacesWithLiveContent()) {
|
||||
final JSONObject serializedRace = new JSONObject();
|
||||
serializedRace.put(REGATTA_NAME, race.getRegattaName());
|
||||
serializedRace.put(RACE_NAME, race.getRaceName());
|
||||
serializedRace.put(TRACKING_START_MILLIS, race.getTrackingStartMillis());
|
||||
serializedRace.put(TRACKING_END_MILLIS, race.getTrackingEndMillis());
|
||||
races.add(serializedRace);
|
||||
}
|
||||
serializedEvent.put(RACES, races);
|
||||
events.add(serializedEvent);
|
||||
}
|
||||
serializedReplicaSet.put(EVENTS, events);
|
||||
replicaSets.add(serializedReplicaSet);
|
||||
}
|
||||
result.put(REPLICA_SETS, replicaSets);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,8 @@ Require-Bundle: com.sap.sailing.domain,
|
||||
org.apache.httpcomponents.httpclient,
|
||||
org.apache.httpcomponents.httpcore,
|
||||
com.sap.sailing.server.gateway.interfaces,
|
||||
com.sap.sailing.landscape.common
|
||||
com.sap.sailing.landscape.common,
|
||||
com.sap.sse.landscape.common
|
||||
Bundle-ClassPath: .
|
||||
Web-ContextPath: /sailingserver
|
||||
Export-Package: com.sap.sailing.server.gateway,
|
||||
|
||||
+13
@@ -29,11 +29,13 @@ import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.RemoteSailingServerReference;
|
||||
import com.sap.sailing.domain.common.DataImportProgress;
|
||||
import com.sap.sailing.domain.common.sharding.ShardingType;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.CompareServersResultJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.CourseAreaJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.DataImportProgressJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.EventBaseJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.LeaderboardGroupBaseJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.LiveContentCheckResultJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.MasterDataImportResultJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.RemoteSailingServerReferenceJsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.TrackingConnectorInfoJsonDeserializer;
|
||||
@@ -45,6 +47,7 @@ import com.sap.sailing.server.gateway.jaxrs.api.CompareServersResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.api.EventsResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.api.LeaderboardGroupsResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.api.LeaderboardsResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.api.LiveContentResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.api.MasterDataImportResource;
|
||||
import com.sap.sailing.server.gateway.jaxrs.api.RemoteServerReferenceResource;
|
||||
import com.sap.sailing.server.gateway.serialization.LeaderboardGroupConstants;
|
||||
@@ -126,6 +129,16 @@ public class SailingServerImpl extends SecuredServerImpl implements SailingServe
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiveContentCheckResult getLiveContent(final long checkedAtMillis) throws ClientProtocolException, IOException,
|
||||
ParseException, JsonDeserializationException {
|
||||
final URL liveContentUrl = new URL(getBaseUrl(), GATEWAY_URL_PREFIX + LiveContentResource.V1_LIVE_CONTENT +
|
||||
"?" + LiveContentResource.CHECKED_AT_MILLIS_QUERY_PARAM + "=" + checkedAtMillis);
|
||||
final HttpGet getLiveContent = new HttpGet(liveContentUrl.toString());
|
||||
final JSONObject jsonResponse = (JSONObject) getJsonParsedResponse(getLiveContent).getA();
|
||||
return new LiveContentCheckResultJsonDeserializer().deserialize(jsonResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MasterDataImportResult importMasterData(SailingServer from, Iterable<UUID> leaderboardGroupIds,
|
||||
boolean override, boolean compress, boolean exportWind, boolean exportDeviceConfigs,
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package com.sap.sailing.server.gateway.jaxrs.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.landscape.common.EventLiveContent;
|
||||
import com.sap.sailing.landscape.common.LiveContentCheckResult;
|
||||
import com.sap.sailing.landscape.common.RaceLiveContent;
|
||||
import com.sap.sailing.landscape.common.ReplicaSetLiveContent;
|
||||
import com.sap.sailing.server.gateway.serialization.impl.LiveContentCheckResultJsonSerializer;
|
||||
import com.sap.sailing.shared.server.gateway.jaxrs.AbstractSailingServerResource;
|
||||
import com.sap.sse.ServerInfo;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.landscape.common.shared.SecuredLandscapeTypes;
|
||||
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
|
||||
|
||||
@Path(LiveContentResource.V1_LIVE_CONTENT)
|
||||
public final class LiveContentResource extends AbstractSailingServerResource {
|
||||
public static final String V1_LIVE_CONTENT = "/v1/livecontent";
|
||||
public static final String CHECKED_AT_MILLIS_QUERY_PARAM = "checkedAtMillis";
|
||||
|
||||
@GET
|
||||
@Produces("application/json;charset=UTF-8")
|
||||
public Response getLiveContent(@QueryParam(CHECKED_AT_MILLIS_QUERY_PARAM) final Long checkedAtMillis) {
|
||||
SecurityUtils.getSubject().checkPermission(SecuredLandscapeTypes.LANDSCAPE.getStringPermissionForTypeRelativeIdentifier(
|
||||
SecuredLandscapeTypes.LandscapeActions.MANAGE, new TypeRelativeObjectIdentifier("AWS")));
|
||||
final TimePoint checkedAt = checkedAtMillis == null ? TimePoint.now() : TimePoint.of(checkedAtMillis);
|
||||
final List<EventLiveContent> eventsWithLiveContent = new ArrayList<>();
|
||||
for (final Event event : getService().getAllEvents()) {
|
||||
if (mayBeLiveAt(event, checkedAt)) {
|
||||
final List<RaceLiveContent> racesWithLiveContent = new ArrayList<>();
|
||||
for (final TrackedRace trackedRace : getService().getAllTrackedRacesForEventTrackingAt(event,
|
||||
checkedAt)) {
|
||||
racesWithLiveContent.add(new RaceLiveContent(trackedRace.getRaceIdentifier().getRegattaName(),
|
||||
trackedRace.getRaceIdentifier().getRaceName(), trackedRace.getStartOfTracking().asMillis(),
|
||||
trackedRace.getEndOfTracking() == null ? null : trackedRace.getEndOfTracking().asMillis()));
|
||||
}
|
||||
racesWithLiveContent.sort(Comparator.comparing(RaceLiveContent::getRegattaName)
|
||||
.thenComparing(RaceLiveContent::getRaceName));
|
||||
if (!racesWithLiveContent.isEmpty()) {
|
||||
eventsWithLiveContent.add(new EventLiveContent(event.getId().toString(), event.getName(),
|
||||
event.getStartDate() == null ? null : event.getStartDate().asMillis(),
|
||||
event.getEndDate() == null ? null : event.getEndDate().asMillis(), racesWithLiveContent));
|
||||
}
|
||||
}
|
||||
}
|
||||
eventsWithLiveContent.sort(Comparator.comparing(EventLiveContent::getEventName)
|
||||
.thenComparing(EventLiveContent::getEventId));
|
||||
final List<ReplicaSetLiveContent> replicaSetsWithLiveContent = new ArrayList<>();
|
||||
if (!eventsWithLiveContent.isEmpty()) {
|
||||
replicaSetsWithLiveContent.add(new ReplicaSetLiveContent(ServerInfo.getName(), eventsWithLiveContent));
|
||||
}
|
||||
final LiveContentCheckResult result = new LiveContentCheckResult(checkedAt.asMillis(),
|
||||
replicaSetsWithLiveContent);
|
||||
return Response.ok(streamingOutput(new LiveContentCheckResultJsonSerializer().serialize(result))).build();
|
||||
}
|
||||
|
||||
private boolean mayBeLiveAt(final Event event, final TimePoint checkedAt) {
|
||||
return (event.getStartDate() == null || !event.getStartDate().after(checkedAt))
|
||||
&& (event.getEndDate() == null || !event.getEndDate().before(checkedAt));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user