diff --git a/java/com.sap.sailing.landscape.common/META-INF/MANIFEST.MF b/java/com.sap.sailing.landscape.common/META-INF/MANIFEST.MF index f1452e5e628..d6fed08c8bf 100755 --- a/java/com.sap.sailing.landscape.common/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.landscape.common/META-INF/MANIFEST.MF @@ -10,3 +10,4 @@ Require-Bundle: com.sap.sse.security.common, com.sap.sse.common, com.sap.sse.landscape.aws.common Bundle-ActivationPolicy: lazy +Export-Package: com.sap.sailing.landscape.common diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/SharedLandscapeConstants.java b/java/com.sap.sailing.landscape.common/src/com/sap/sailing/landscape/common/SharedLandscapeConstants.java similarity index 84% rename from java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/SharedLandscapeConstants.java rename to java/com.sap.sailing.landscape.common/src/com/sap/sailing/landscape/common/SharedLandscapeConstants.java index b2d2fc44ef9..a571147a92f 100755 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/SharedLandscapeConstants.java +++ b/java/com.sap.sailing.landscape.common/src/com/sap/sailing/landscape/common/SharedLandscapeConstants.java @@ -1,4 +1,4 @@ -package com.sap.sailing.landscape; +package com.sap.sailing.landscape.common; public interface SharedLandscapeConstants { /** @@ -52,4 +52,15 @@ public interface SharedLandscapeConstants { * Default value for the {@code Name} tag for shared instances expected to run multiple application processes. */ String MULTI_PROCESS_INSTANCE_DEFAULT_NAME = "SL Multi-Server"; + + String DEFAULT_DEDICATED_INSTANCE_TYPE_NAME = "C4_2_XLARGE"; + + String DEFAULT_SHARED_INSTANCE_TYPE_NAME = "I3_2_XLARGE"; + + /** + * Tells how to size process heaps on shared instances by default, based on the instance's physical memory. + * Harmonizes with the {@link #DEFAULT_SHARED_INSTANCE_TYPE_NAME} and the expected approximate memory requirements + * of a typical process instance. + */ + int DEFAULT_NUMBER_OF_PROCESSES_IN_MEMORY = 4; } diff --git a/java/com.sap.sailing.landscape.gateway/src/com/sap/sailing/landscape/gateway/jaxrs/api/SailingLandscapeResource.java b/java/com.sap.sailing.landscape.gateway/src/com/sap/sailing/landscape/gateway/jaxrs/api/SailingLandscapeResource.java index 39a376adfe3..6219028d93c 100755 --- a/java/com.sap.sailing.landscape.gateway/src/com/sap/sailing/landscape/gateway/jaxrs/api/SailingLandscapeResource.java +++ b/java/com.sap.sailing.landscape.gateway/src/com/sap/sailing/landscape/gateway/jaxrs/api/SailingLandscapeResource.java @@ -45,9 +45,10 @@ public class SailingLandscapeResource extends AbstractLandscapeResource { private static final Logger logger = Logger.getLogger(SailingLandscapeResource.class.getName()); private static final String REGION_FORM_PARAM = "regionId"; + private static final String SHARED_MASTER_INSTANCE_FORM_PARAM = "sharedMasterInstance"; private static final String REPLICA_SET_NAME_FORM_PARAM = "replicaSetName"; - private static final String MASTER_INSTANCE_TYPE_FORM_PARAM = "masterInstanceType"; - private static final String REPLICA_INSTANCE_TYPE_FORM_PARAM = "replicaInstanceType"; + private static final String DEDICATED_INSTANCE_TYPE_FORM_PARAM = "dedicatedInstanceType"; + private static final String SHARED_INSTANCE_TYPE_FORM_PARAM = "sharedInstanceType"; private static final String DYNAMIC_LOAD_BALANCER_MAPPING_FORM_PARAM = "dynamicLoadBalancerMapping"; private static final String RELEASE_NAME_FORM_PARAM = "releaseName"; private static final String KEY_NAME_FORM_PARAM = "keyName"; @@ -143,9 +144,10 @@ public class SailingLandscapeResource extends AbstractLandscapeResource { @Produces("application/json;charset=UTF-8") public Response createApplicationReplicaSet( @FormParam(REGION_FORM_PARAM) String regionId, + @FormParam(SHARED_MASTER_INSTANCE_FORM_PARAM) @DefaultValue("false") boolean sharedMasterInstance, @FormParam(REPLICA_SET_NAME_FORM_PARAM) String replicaSetName, - @FormParam(MASTER_INSTANCE_TYPE_FORM_PARAM) String masterInstanceType, - @FormParam(REPLICA_INSTANCE_TYPE_FORM_PARAM) String replicaInstanceTypeOrNull, + @FormParam(DEDICATED_INSTANCE_TYPE_FORM_PARAM) String dedicatedInstanceType, + @FormParam(SHARED_INSTANCE_TYPE_FORM_PARAM) String sharedInstanceTypeOrNull, @FormParam(DYNAMIC_LOAD_BALANCER_MAPPING_FORM_PARAM) @DefaultValue("false") boolean dynamicLoadBalancerMapping, @FormParam(RELEASE_NAME_FORM_PARAM) String releaseNameOrNullForLatestMaster, @FormParam(KEY_NAME_FORM_PARAM) String optionalKeyName, @@ -162,12 +164,11 @@ public class SailingLandscapeResource extends AbstractLandscapeResource { try { final Release release = getLandscapeService().getRelease(releaseNameOrNullForLatestMaster); final AwsApplicationReplicaSet> replicaSet = getLandscapeService() - .createApplicationReplicaSet(regionId, replicaSetName, masterInstanceType, replicaInstanceTypeOrNull, - dynamicLoadBalancerMapping, release.getName(), - optionalKeyName, - privateKeyEncryptionPassphrase == null ? null : privateKeyEncryptionPassphrase.getBytes(), masterReplicationBearerToken, replicaReplicationBearerToken, - domainName, optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull, - Optional.ofNullable(optionalMinimumAutoScalingGroupSize), Optional.ofNullable(optionalMaximumAutoScalingGroupSize)); + .createApplicationReplicaSet(regionId, replicaSetName, sharedMasterInstance, sharedInstanceTypeOrNull, + dedicatedInstanceType, dynamicLoadBalancerMapping, release.getName(), + optionalKeyName, privateKeyEncryptionPassphrase == null ? null : privateKeyEncryptionPassphrase.getBytes(), masterReplicationBearerToken, + replicaReplicationBearerToken, domainName, optionalMemoryInMegabytesOrNull, + optionalMemoryTotalSizeFactorOrNull, Optional.ofNullable(optionalMinimumAutoScalingGroupSize), Optional.ofNullable(optionalMaximumAutoScalingGroupSize)); final JSONObject result = new AwsApplicationReplicaSetJsonSerializer(release.getName()).serialize(replicaSet); response = Response.ok(streamingOutput(result)).build(); } catch (Exception e) { @@ -360,7 +361,7 @@ public class SailingLandscapeResource extends AbstractLandscapeResource { response = badRequest("Application replica set with name "+replicaSetName+" not found in region "+regionId); } else { final JSONArray result = new JSONArray(); - for (final SailingAnalyticsHost host : getLandscapeService().getEligibleHostsForReplicaSet(region, replicaSet, optionalKeyName, passphraseForPrivateKeyDecryption)) { + for (final SailingAnalyticsHost host : getLandscapeService().getEligibleSharedHostsForReplicaSet(region, replicaSet, optionalKeyName, passphraseForPrivateKeyDecryption)) { result.add(new HostJsonSerializer().serialize(host)); } response = Response.ok().entity(streamingOutput(result)).build(); diff --git a/java/com.sap.sailing.landscape.gateway/webservices/api/createapplicationreplicaset.html b/java/com.sap.sailing.landscape.gateway/webservices/api/createapplicationreplicaset.html index 87e22e15484..0e1dc77bd02 100644 --- a/java/com.sap.sailing.landscape.gateway/webservices/api/createapplicationreplicaset.html +++ b/java/com.sap.sailing.landscape.gateway/webservices/api/createapplicationreplicaset.html @@ -32,8 +32,8 @@
regionId, region where to set up the replica set, e.g., eu-west-1
replicaSetName, name of the replica set; used as the hostname to which the domain name is appended, as well as for the database and RabbitMQ exchange name
-
masterInstanceType, instance type to use in the hyperscaler for the master node (by default also for the - replicas if replicaInstanceType is not specified), e.g., C5_4_XLARGE; +
dedicatedInstanceType, instance type to use in the hyperscaler for a dedicated non-shared master node and for the + auto-scaling replicas, e.g., C5_4_XLARGE; see here
keyName, the name of the SSH key to use; must identify an existing SSH key by that name in the region specified and will be used to log on to existing and new instances using a root ssh connection.
@@ -43,11 +43,16 @@ Optional form parameters: -
replicaInstanceType, instance type to use in the hyperscaler for replica nodes managed by the auto-scaling group, e.g., C5_4_XLARGE; +
sharedMasterInstance defaults to false; if set to true, the instance launched for the master process + will be named "SL Multi-Server" and will be tagged with sailing-analytics-server:___multi___ which + makes it eligible for automated deployment of other Sailing Analytics processes, such as unmanaged replicas. + Otherwise, the master instance will be named and tagged after the replica set's name.
+
sharedInstanceType, instance type to use in the hyperscaler for a new shared master instance (if sharedMasterInstance was + set to true) as well as for a new instance that needs to be launched for a shared first replica + in case minimumAutoScalingGroupSize is set to 0; e.g., I3_2_XLARGE; see here. - If not provided, the auto-scaling group will be configured to use the same instance type for the replicas that is used - by the master. If you'd like to configure your master to run on an instance intended to be shared with other - replica sets you may want to size your master instance type larger and with much swap space (e.g., i3.2xlarge) + If you'd like to configure your master to run on an instance intended to be shared with other + replica sets you may want to size your shared instance type with much swap space (e.g., i3.2xlarge) whereas your auto scaling group-managed replicas will not be shared and hence may get along with smaller instance types.
.
dynamicLoadBalancerMappingionId, boolean value (false or true; defaulting to false); if true, the rules will be entered diff --git a/java/com.sap.sailing.landscape.test/src/com/sap/sailing/landscape/test/TestProcedures.java b/java/com.sap.sailing.landscape.test/src/com/sap/sailing/landscape/test/TestProcedures.java index a511d825524..ab46cadc6a7 100755 --- a/java/com.sap.sailing.landscape.test/src/com/sap/sailing/landscape/test/TestProcedures.java +++ b/java/com.sap.sailing.landscape.test/src/com/sap/sailing/landscape/test/TestProcedures.java @@ -27,7 +27,7 @@ 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.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.impl.BearerTokenReplicationCredentials; import com.sap.sailing.landscape.impl.SailingAnalyticsHostImpl; import com.sap.sailing.landscape.impl.SailingAnalyticsProcessImpl; diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/CreateApplicationReplicaSetDialog.java b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/CreateApplicationReplicaSetDialog.java index 194b0b23067..a9cefef2a71 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/CreateApplicationReplicaSetDialog.java +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/CreateApplicationReplicaSetDialog.java @@ -7,36 +7,78 @@ import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.ListBox; import com.google.gwt.user.client.ui.TextBox; import com.google.gwt.user.client.ui.Widget; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.ui.client.i18n.StringMessages; import com.sap.sse.common.Util; import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.controls.IntegerBox; import com.sap.sse.gwt.client.dialog.DataEntryDialog; +/** + * Allows the user to specify the parameters required for launching an application replica set. It produces an output in + * the form of an {@link CreateApplicationReplicaSetInstructions} object (a static inner class) which can then be used + * by a caller to parameterize subsequent calls to the landscape management service. + *

+ * + * The dialog can itself be parameterized to launch different scenarios: + *

    + *
  • master on dedicated or pre-selected/arbitrary shared instance
  • + *
  • initial replica provided through auto-scaling group on dedicated instance, or on a shared instance
  • + *
  • dynamic load balancing may or may not be allowed (usually depending on the region)
  • + *
+ * + * Different instance type choices and defaulting rules are required in the different scenarios: + *
    + *
  • When a new master is to be launched (dedicated or shared), the master instance type must be specified. A + * different default is suggested if we know the user wants to launch a shared master instance.
  • + *
  • For the auto-scaling group that creates dedicated replica instances an instance type must always be specified. If + * a dedicated master instance is requested, its instance type is a good default for the type of instances launched by + * the auto-scaling group. In case of a shared master instance, however, a default instance type for dedicated instances + * will be suggested for the auto-scaling group's instance type.
  • + *
  • If a first replica is requested to run on a shared instance, that instance may need to be launched in case no + * eligible instance can be found in an availability zone different from the master instance's AZ with the necessary + * available port(s). To be prepared for this case, the instance type must be specified if a first replica is desired + * to run on a shared / sharable instance. If the master is also to run on a shared instance, the instance type selected + * for the new shared master instance serves as a default for launching a shared replica instance. If the master is + * configured to run on a dedicated instance, its instance type is not a good default for a shared replica instance, but it + * is for the auto-scaling group's replica instances. Instead, the user then needs to specify the shared instance type + * to use in case a shared replica instance needs to be launched.
  • + *
+ * We can boil this down to two instance types: the one for shared and the one for dedicated instances. The instance + * type for dedicated instances is always required for the auto-scaling group configuration. The one for shared + * instances, however, is required only if the master or a first replica shall run on a shared instance. If the + * master shall run on a dedicated instance and the replicas shall be managed entirely by the auto-scaling group, + * no specification for a shared instance type is required.

+ * + * @author Axel Uhl (d043530) + * + */ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplicaSetDialog { - private static final String DEFAULT_INSTANCE_TYPE = "C4_2_XLARGE"; public static class CreateApplicationReplicaSetInstructions extends AbstractApplicationReplicaSetDialog.AbstractApplicationReplicaSetInstructions { private final String name; - private final String instanceType; - private final String optionalReplicaInstanceType; + private final boolean sharedMasterInstance; + private final String dedicatedInstanceType; + private final String optionalSharedInstanceType; private final boolean dynamicLoadBalancerMapping; private final String optionalDomainName; private final Integer optionalMemoryInMegabytesOrNull; private final Integer optionalMemoryTotalSizeFactorOrNull; private final boolean firstReplicaOnSharedInstance; - public CreateApplicationReplicaSetInstructions(String name, String instanceType, - String optionalReplicaInstanceType, String releaseNameOrNullForLatestMaster, - boolean dynamicLoadBalancerMapping, String masterReplicationBearerToken, String replicaReplicationBearerToken, - String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, boolean firstReplicaOnSharedInstance) { + public CreateApplicationReplicaSetInstructions(String name, boolean sharedMasterInstance, String dedicatedInstanceType, + String optionalSharedInstanceType, String releaseNameOrNullForLatestMaster, + boolean dynamicLoadBalancerMapping, String masterReplicationBearerToken, + String replicaReplicationBearerToken, String optionalDomainName, + Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, + boolean firstReplicaOnSharedInstance) { super(releaseNameOrNullForLatestMaster, masterReplicationBearerToken, replicaReplicationBearerToken); this.name = name; + this.sharedMasterInstance = sharedMasterInstance; this.dynamicLoadBalancerMapping = dynamicLoadBalancerMapping; this.optionalDomainName = Util.hasLength(optionalDomainName) ? optionalDomainName : null; - this.instanceType = instanceType; - this.optionalReplicaInstanceType = optionalReplicaInstanceType; + this.dedicatedInstanceType = dedicatedInstanceType; + this.optionalSharedInstanceType = optionalSharedInstanceType; this.optionalMemoryInMegabytesOrNull = optionalMemoryInMegabytesOrNull; this.optionalMemoryTotalSizeFactorOrNull = optionalMemoryTotalSizeFactorOrNull; this.firstReplicaOnSharedInstance = firstReplicaOnSharedInstance; @@ -44,17 +86,20 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic public String getName() { return name; } + public boolean isSharedMasterInstance() { + return sharedMasterInstance; + } public boolean isDynamicLoadBalancerMapping() { return dynamicLoadBalancerMapping; } public String getOptionalDomainName() { return optionalDomainName; } - public String getInstanceType() { - return instanceType; + public String getDedicatedInstanceType() { + return dedicatedInstanceType; } - public String getOptionalReplicaInstanceType() { - return optionalReplicaInstanceType; + public String getOptionalSharedInstanceType() { + return optionalSharedInstanceType; } public Integer getOptionalMemoryInMegabytesOrNull() { return optionalMemoryInMegabytesOrNull; @@ -77,7 +122,7 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic @Override public String getErrorMessage(CreateApplicationReplicaSetInstructions valueToValidate) { final String result; - if (!Util.hasLength(valueToValidate.getInstanceType())) { + if (!Util.hasLength(valueToValidate.getDedicatedInstanceType())) { result = stringMessages.pleaseSelectInstanceTypeForNewMaster(); } else if (!Util.hasLength(valueToValidate.getMasterReplicationBearerToken())) { result = stringMessages.pleaseProvideBearerTokenForSecurityReplication(); @@ -89,41 +134,99 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic return result; } } - + private final StringMessages stringMessages; + private final boolean useExistingSharedMasterInstance; private final TextBox nameBox; + private final CheckBox sharedMasterInstanceBox; + private final CheckBox startWithReplicaOnSharedInstanceBox; + private final ListBox dedicatedInstanceTypeListBox; + private final Label dedicatedInstanceTypeLabel; + private final ListBox sharedInstanceTypeListBox; + private final Label sharedInstanceTypeLabel; private final CheckBox dynamicLoadBalancerCheckBox; private final TextBox domainNameBox; - private final ListBox instanceTypeListBox; - private final ListBox replicaInstanceTypeListBox; private final IntegerBox memoryInMegabytesBox; private final IntegerBox memoryTotalSizeFactorBox; - private final CheckBox startWithReplicaOnSharedInstanceBox; - private final String SAME_AS_MASTER_VALUE = "___same_as_master___"; + private boolean memoryAsFactorToTotalMemoryAdjusted; - public CreateApplicationReplicaSetDialog(LandscapeManagementWriteServiceAsync landscapeManagementService, Iterable releaseNames, - StringMessages stringMessages, ErrorReporter errorReporter, DialogCallback callback) { - super(stringMessages.createApplicationReplicaSet(), landscapeManagementService, releaseNames, stringMessages, errorReporter, new Validator(stringMessages), callback); + public CreateApplicationReplicaSetDialog(LandscapeManagementWriteServiceAsync landscapeManagementService, + boolean useExistingSharedMasterInstance, Iterable releaseNames, + StringMessages stringMessages, ErrorReporter errorReporter, DialogCallback callback, + boolean mayUseDynamicLoadBalancer) { + super(stringMessages + .createApplicationReplicaSet(), landscapeManagementService, releaseNames, stringMessages, + errorReporter, new Validator(stringMessages), callback); this.stringMessages = stringMessages; + this.useExistingSharedMasterInstance = useExistingSharedMasterInstance; nameBox = createTextBox("", 40); - dynamicLoadBalancerCheckBox = createCheckbox(stringMessages.useDynamicLoadBalancer()); + dynamicLoadBalancerCheckBox = mayUseDynamicLoadBalancer ? createCheckbox(stringMessages.useDynamicLoadBalancer()) : null; domainNameBox = createTextBox(SharedLandscapeConstants.DEFAULT_DOMAIN_NAME, 40); - instanceTypeListBox = LandscapeDialogUtil.createInstanceTypeListBox(this, landscapeManagementService, stringMessages, DEFAULT_INSTANCE_TYPE, errorReporter); - replicaInstanceTypeListBox = LandscapeDialogUtil.createInstanceTypeListBoxWithAdditionalDefaultEntry(this, - stringMessages.sameAsMaster(), SAME_AS_MASTER_VALUE, landscapeManagementService, stringMessages, - /* default instance type */ null, errorReporter); + dedicatedInstanceTypeListBox = LandscapeDialogUtil.createInstanceTypeListBox(this, landscapeManagementService, + stringMessages, SharedLandscapeConstants.DEFAULT_DEDICATED_INSTANCE_TYPE_NAME, errorReporter); + dedicatedInstanceTypeLabel = new Label(); + sharedInstanceTypeListBox = LandscapeDialogUtil.createInstanceTypeListBox(this, landscapeManagementService, + stringMessages, SharedLandscapeConstants.DEFAULT_SHARED_INSTANCE_TYPE_NAME, errorReporter); + sharedInstanceTypeLabel = new Label(); memoryInMegabytesBox = createIntegerBox(null, 7); memoryTotalSizeFactorBox = createIntegerBox(null, 2); + memoryTotalSizeFactorBox.addValueChangeHandler(e->memoryAsFactorToTotalMemoryAdjusted=true); + if (useExistingSharedMasterInstance) { + memoryTotalSizeFactorBox.setValue(SharedLandscapeConstants.DEFAULT_NUMBER_OF_PROCESSES_IN_MEMORY); + } memoryInMegabytesBox.addValueChangeHandler(e->memoryTotalSizeFactorBox.setEnabled(e.getValue() == null)); startWithReplicaOnSharedInstanceBox = createCheckbox(stringMessages.firstReplicaOnSharedInstance()); + startWithReplicaOnSharedInstanceBox.addValueChangeHandler(e->updateInstanceTypesBasedOnSharedMasterInstanceBox()); + startWithReplicaOnSharedInstanceBox.setValue(useExistingSharedMasterInstance); + sharedMasterInstanceBox = createCheckbox(stringMessages.sharedMasterInstance()); + sharedMasterInstanceBox.addValueChangeHandler(e->updateInstanceTypesBasedOnSharedMasterInstanceBox()); + sharedMasterInstanceBox.setValue(useExistingSharedMasterInstance); + sharedMasterInstanceBox.setEnabled(!useExistingSharedMasterInstance); + updateInstanceTypesBasedOnSharedMasterInstanceBox(); } - protected ListBox getInstanceTypeListBox() { - return instanceTypeListBox; + private void updateInstanceTypesBasedOnSharedMasterInstanceBox() { + dedicatedInstanceTypeLabel.setText(sharedMasterInstanceBox.getValue() + ? stringMessages.autoScalingReplicaInstanceType() + : stringMessages.dedicatedMasterAndAutoScalingReplicaInstanceType()); + if (sharedMasterInstanceBox.getValue()) { + if (startWithReplicaOnSharedInstanceBox.getValue()) { + setVisibilityOfSharedInstanceTypeSelection(true); + sharedInstanceTypeLabel.setText(useExistingSharedMasterInstance + ? stringMessages.sharedReplicaInstanceType() + : stringMessages.sharedMasterAndReplicaInstanceType()); + } else { + setVisibilityOfSharedInstanceTypeSelection(!useExistingSharedMasterInstance); + sharedInstanceTypeLabel.setText(stringMessages.sharedMasterInstanceType()); + } + } else { + if (startWithReplicaOnSharedInstanceBox.getValue()) { + setVisibilityOfSharedInstanceTypeSelection(true); + sharedInstanceTypeLabel.setText(stringMessages.sharedReplicaInstanceType()); + } else { + setVisibilityOfSharedInstanceTypeSelection(false); + } + } + if (!memoryAsFactorToTotalMemoryAdjusted) { + if ((!useExistingSharedMasterInstance && sharedMasterInstanceBox.getValue()) || startWithReplicaOnSharedInstanceBox.getValue()) { + memoryTotalSizeFactorBox.setValue(SharedLandscapeConstants.DEFAULT_NUMBER_OF_PROCESSES_IN_MEMORY); + } else { + memoryTotalSizeFactorBox.setText(""); + } + } } - protected ListBox getReplicaInstanceTypeListBox() { - return replicaInstanceTypeListBox; + private void setVisibilityOfSharedInstanceTypeSelection(boolean show) { + sharedInstanceTypeLabel.setVisible(show); + sharedInstanceTypeListBox.setVisible(show); + } + + protected ListBox getDedicatedInstanceTypeListBox() { + return dedicatedInstanceTypeListBox; + } + + protected ListBox getSharedInstanceTypeListBox() { + return sharedInstanceTypeListBox; } protected CheckBox getStartWithReplicaOnSharedInstanceBox() { @@ -132,20 +235,26 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic @Override protected Widget getAdditionalWidget() { - final Grid result = new Grid(11, 2); + final Grid result = new Grid(12, 2); int row=0; result.setWidget(row, 0, new Label(stringMessages.name())); result.setWidget(row++, 1, nameBox); result.setWidget(row, 0, new Label(stringMessages.release())); result.setWidget(row++, 1, getReleaseNameBox()); - result.setWidget(row, 0, new Label(stringMessages.instanceType())); - result.setWidget(row++, 1, getInstanceTypeListBox()); - result.setWidget(row, 0, new Label(stringMessages.replicaInstanceType())); - result.setWidget(row++, 1, getReplicaInstanceTypeListBox()); + if (!useExistingSharedMasterInstance) { + result.setWidget(row, 0, new Label(stringMessages.sharedMasterInstance())); + result.setWidget(row++, 1, sharedMasterInstanceBox); + } result.setWidget(row, 0, new Label(stringMessages.firstReplicaOnSharedInstance())); result.setWidget(row++, 1, getStartWithReplicaOnSharedInstanceBox()); - result.setWidget(row, 0, new Label(stringMessages.useDynamicLoadBalancer())); - result.setWidget(row++, 1, dynamicLoadBalancerCheckBox); + result.setWidget(row, 0, dedicatedInstanceTypeLabel); + result.setWidget(row++, 1, getDedicatedInstanceTypeListBox()); + result.setWidget(row, 0, sharedInstanceTypeLabel); + result.setWidget(row++, 1, getSharedInstanceTypeListBox()); + if (dynamicLoadBalancerCheckBox != null) { + result.setWidget(row, 0, new Label(stringMessages.useDynamicLoadBalancer())); + result.setWidget(row++, 1, dynamicLoadBalancerCheckBox); + } result.setWidget(row, 0, new Label(stringMessages.bearerTokenForSecurityReplication())); result.setWidget(row++, 1, getMasterReplicationBearerTokenBox()); result.setWidget(row, 0, new Label(stringMessages.replicaReplicationBearerToken())); @@ -166,11 +275,12 @@ public class CreateApplicationReplicaSetDialog extends AbstractApplicationReplic @Override protected CreateApplicationReplicaSetInstructions getResult() { - return new CreateApplicationReplicaSetInstructions(nameBox.getValue(), - getInstanceTypeListBox().getSelectedValue(), - getReplicaInstanceTypeListBox().getSelectedValue().equals(SAME_AS_MASTER_VALUE) ? null : getReplicaInstanceTypeListBox().getSelectedValue(), - getReleaseNameBoxValue(), dynamicLoadBalancerCheckBox.getValue(), + return new CreateApplicationReplicaSetInstructions(nameBox.getValue(), sharedMasterInstanceBox.getValue(), + getDedicatedInstanceTypeListBox().getSelectedValue(), + getSharedInstanceTypeListBox().getSelectedValue(), + getReleaseNameBoxValue(), dynamicLoadBalancerCheckBox==null?false:dynamicLoadBalancerCheckBox.getValue(), getMasterReplicationBearerTokenBox().getValue(), getReplicaReplicationBearerTokenBox().getValue(), - domainNameBox.getValue(), memoryInMegabytesBox.getValue(), memoryTotalSizeFactorBox.getValue(), startWithReplicaOnSharedInstanceBox.getValue()); + domainNameBox.getValue(), memoryInMegabytesBox.getValue(), memoryTotalSizeFactorBox.getValue(), + startWithReplicaOnSharedInstanceBox.getValue()); } } diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeDialogUtil.java b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeDialogUtil.java index 2a6cd400d46..865131788dd 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeDialogUtil.java +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeDialogUtil.java @@ -13,10 +13,10 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog; public class LandscapeDialogUtil { public static ListBox createInstanceTypeListBox(DataEntryDialog dialog, LandscapeManagementWriteServiceAsync landscapeManagementService, StringMessages stringMessages, - String defaultInstanceType, ErrorReporter errorReporter) { + String defaultInstanceTypeName, ErrorReporter errorReporter) { return createInstanceTypeListBoxWithAdditionalDefaultEntry(dialog, /* additionalItem */ null, /* additionalValue */ null, - landscapeManagementService, stringMessages, defaultInstanceType, errorReporter); + landscapeManagementService, stringMessages, defaultInstanceTypeName, errorReporter); } /** @@ -28,13 +28,13 @@ public class LandscapeDialogUtil { public static ListBox createInstanceTypeListBoxWithAdditionalDefaultEntry(DataEntryDialog dialog, String additionalItem, String additionalValue, LandscapeManagementWriteServiceAsync landscapeManagementService, StringMessages stringMessages, - String defaultInstanceType, ErrorReporter errorReporter) { + String defaultInstanceTypeNamr, ErrorReporter errorReporter) { final ListBox instanceTypeBox = dialog.createListBox(/*isMultipleSelect*/false); if (additionalItem != null) { instanceTypeBox.addItem(additionalItem, additionalValue); instanceTypeBox.setSelectedIndex(0); } - landscapeManagementService.getInstanceTypes(new AsyncCallback>() { + landscapeManagementService.getInstanceTypeNames(new AsyncCallback>() { @Override public void onFailure(Throwable caught) { errorReporter.reportError(caught.getMessage()); @@ -46,7 +46,7 @@ public class LandscapeDialogUtil { int i=0; for (final String instanceType : result) { instanceTypeBox.addItem(instanceType, instanceType); - if (additionalItem == null && instanceType.equals(defaultInstanceType)) { + if (additionalItem == null && instanceType.equals(defaultInstanceTypeNamr)) { instanceTypeBox.setSelectedIndex(i); } i++; @@ -55,4 +55,13 @@ public class LandscapeDialogUtil { }); return instanceTypeBox; } + + public static void selectInstanceType(ListBox instanceTypeListBox, String instanceTypeName) { + for (int i=0; i result) { - new CreateApplicationReplicaSetDialog(landscapeManagementService, result.stream().map(r->r.getName())::iterator, + new CreateApplicationReplicaSetDialog(landscapeManagementService, /* sharedMasterInstanceAlreadyExists */ false, + result.stream().map(r->r.getName())::iterator, stringMessages, errorReporter, new DialogCallback() { - @Override - public void ok(CreateApplicationReplicaSetInstructions instructions) { - applicationReplicaSetsBusy.setBusy(true); - landscapeManagementService.createApplicationReplicaSet(regionId, instructions.getName(), instructions.getInstanceType(), - instructions.getOptionalReplicaInstanceType(), - instructions.isDynamicLoadBalancerMapping(), instructions.getReleaseNameOrNullForLatestMaster(), - sshKeyManagementPanel.getSelectedKeyPair()==null?null:sshKeyManagementPanel.getSelectedKeyPair().getName(), - sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null ? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null, - instructions.getMasterReplicationBearerToken(), instructions.getReplicaReplicationBearerToken(), - instructions.getOptionalDomainName(), instructions.getOptionalMemoryInMegabytesOrNull(), - instructions.getOptionalMemoryTotalSizeFactorOrNull(), - /* minimum auto-scaling group size: */ instructions.isFirstReplicaOnSharedInstance()?0:null, - /* maximum auto-scaling group size remains at default: */ null, - new AsyncCallback>() { - @Override - public void onFailure(Throwable caught) { - applicationReplicaSetsBusy.setBusy(false); - errorReporter.reportError(caught.getMessage()); - } - - @Override - public void onSuccess(SailingApplicationReplicaSetDTO result) { - applicationReplicaSetsBusy.setBusy(false); - Notification.notify(stringMessages.successfullyCreatedReplicaSet(instructions.getName()), NotificationType.SUCCESS); - if (result != null) { - applicationReplicaSetsTable.getFilterPanel().add(result); - } - } - }); - } - - @Override - public void cancel() { - } - }).show(); + @Override + public void ok(CreateApplicationReplicaSetInstructions instructions) { + applicationReplicaSetsBusy.setBusy(true); + landscapeManagementService.createApplicationReplicaSet(regionId, + instructions.getName(), instructions.isSharedMasterInstance(), + instructions.getOptionalSharedInstanceType(), + instructions.getDedicatedInstanceType(), + instructions.isDynamicLoadBalancerMapping(), instructions.getReleaseNameOrNullForLatestMaster(), + sshKeyManagementPanel.getSelectedKeyPair()==null?null:sshKeyManagementPanel.getSelectedKeyPair().getName(), + sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null ? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null, + instructions.getMasterReplicationBearerToken(), instructions.getReplicaReplicationBearerToken(), + instructions.getOptionalDomainName(), instructions.getOptionalMemoryInMegabytesOrNull(), + instructions.getOptionalMemoryTotalSizeFactorOrNull(), + /* minimum auto-scaling group size: */ instructions.isFirstReplicaOnSharedInstance()?0:null, + /* maximum auto-scaling group size remains at default: */ null, + new AsyncCallback>() { + @Override + public void onFailure(Throwable caught) { + applicationReplicaSetsBusy.setBusy(false); + errorReporter.reportError(caught.getMessage()); + } + + @Override + public void onSuccess(SailingApplicationReplicaSetDTO result) { + applicationReplicaSetsBusy.setBusy(false); + Notification.notify(stringMessages.successfullyCreatedReplicaSet(instructions.getName()), NotificationType.SUCCESS); + if (result != null) { + applicationReplicaSetsTable.getFilterPanel().add(result); + } + } + }); + } + + @Override + public void cancel() { + } + }, regionId.equals(SharedLandscapeConstants.REGION_WITH_DEFAULT_LOAD_BALANCER)).show(); } }); } @@ -635,13 +638,13 @@ public class LandscapeManagementPanel extends SimplePanel { @Override public void onSuccess(ArrayList result) { - new CreateApplicationReplicaSetDialog(landscapeManagementService, result.stream().map(r->r.getName())::iterator, - stringMessages, errorReporter, new DialogCallback() { - @Override - public void ok(CreateApplicationReplicaSetInstructions instructions) { + new CreateApplicationReplicaSetDialog(landscapeManagementService, /* sharedMasterInstanceAlreadyExists */ true, + result.stream().map(r->r.getName())::iterator, stringMessages, errorReporter, new DialogCallback() { + @Override + public void ok(CreateApplicationReplicaSetInstructions instructions) { applicationReplicaSetsBusy.setBusy(true); landscapeManagementService.deployApplicationToExistingHost(instructions.getName(), applicationReplicaSetOnWhichToDeployMaster.getMaster().getHost(), - instructions.getInstanceType(), instructions.isDynamicLoadBalancerMapping(), + instructions.getDedicatedInstanceType(), instructions.isDynamicLoadBalancerMapping(), instructions.getReleaseNameOrNullForLatestMaster(), sshKeyManagementPanel.getSelectedKeyPair()==null?null:sshKeyManagementPanel.getSelectedKeyPair().getName(), sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null ? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null, @@ -664,12 +667,14 @@ public class LandscapeManagementPanel extends SimplePanel { } } }); - } - - @Override - public void cancel() { - } - }).show(); + } + + @Override + public void cancel() { + } + }, + regionsTable.getSelectionModel().getSelectedObject().equals(SharedLandscapeConstants.REGION_WITH_DEFAULT_LOAD_BALANCER)) + .show(); } }); } diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteService.java b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteService.java index bf1ca5dca1e..8ecb99cf1d2 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteService.java +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteService.java @@ -19,7 +19,7 @@ import com.sap.sse.landscape.aws.common.shared.RedirectDTO; public interface LandscapeManagementWriteService extends RemoteService { ArrayList getRegions(); - ArrayList getInstanceTypes(); + ArrayList getInstanceTypeNames(); ArrayList getMongoEndpoints(String region) throws Exception; @@ -69,11 +69,11 @@ public interface LandscapeManagementWriteService extends RemoteService { SerializationDummyDTO serializationDummy(ProcessDTO mongoProcessDTO, AwsInstanceDTO awsInstanceDTO, SailingApplicationReplicaSetDTO sailingApplicationReplicationSetDTO); - SailingApplicationReplicaSetDTO createApplicationReplicaSet(String regionId, String name, String masterInstanceType, - String optionalReplicaInstanceTypeOrNull, boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster, - String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken, String replicaReplicationBearerToken, - String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, - Integer minimumAutoScalingGroupSizeOrNull, Integer maximumAutoScalingGroupSizeOrNull) throws Exception; + SailingApplicationReplicaSetDTO createApplicationReplicaSet(String regionId, String name, boolean sharedMasterInstance, + String masterInstanceType, String optionalReplicaInstanceTypeOrNull, boolean dynamicLoadBalancerMapping, + String releaseNameOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken, + String replicaReplicationBearerToken, String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, + Integer optionalMemoryTotalSizeFactorOrNull, Integer minimumAutoScalingGroupSizeOrNull, Integer maximumAutoScalingGroupSizeOrNull) throws Exception; void defineDefaultRedirect(String regionId, String hostname, RedirectDTO redirect, String keyName, String passphraseForPrivateKeyDecryption); diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteServiceAsync.java b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteServiceAsync.java index beaa2c1ecbb..f98e8047316 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteServiceAsync.java +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteServiceAsync.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.UUID; import com.google.gwt.user.client.rpc.AsyncCallback; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.ui.shared.AmazonMachineImageDTO; import com.sap.sailing.landscape.ui.shared.AwsInstanceDTO; import com.sap.sailing.landscape.ui.shared.MongoEndpointDTO; @@ -20,7 +20,7 @@ import com.sap.sse.landscape.aws.common.shared.RedirectDTO; public interface LandscapeManagementWriteServiceAsync { void getRegions(AsyncCallback> callback); - void getInstanceTypes(AsyncCallback> callback); + void getInstanceTypeNames(AsyncCallback> callback); void getMongoEndpoints(String regionId, AsyncCallback> callback); @@ -88,8 +88,8 @@ public interface LandscapeManagementWriteServiceAsync { void getApplicationReplicaSets(String regionId, String optionalKeyName, byte[] privateKeyEncryptionPassphrase, AsyncCallback>> callback); - void createApplicationReplicaSet(String regionId, String name, String masterInstanceType, - String optionalReplicaInstanceTypeOrNull, boolean dynamicLoadBalancerMapping, + void createApplicationReplicaSet(String regionId, String name, boolean sharedMasterInstance, + String sharedInstanceType, String dedicatedInstanceType, boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken, String replicaReplicationBearerToken, String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java index f916fe3698b..cb150c7b940 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java @@ -116,9 +116,15 @@ com.sap.sse.gwt.adminconsole.StringMessages { String stopReplicating(); String sameAsMaster(); String firstReplicaOnSharedInstance(); - String replicaInstanceType(); String machineImageId(); String updateAmiForAutoScalingReplicas(); String successfullyUpdatedMachineImageForAutoScalingReplicas(String replicaSetName, String autoScalingGroupAmiId); String updateSelectedReplicaSetAmisToo(String listOfReplicaSetsToUpdate); + String sharedMasterInstance(); + String autoScalingReplicaInstanceType(); + String dedicatedInstanceType(); + String dedicatedMasterAndAutoScalingReplicaInstanceType(); + String sharedMasterInstanceType(); + String sharedMasterAndReplicaInstanceType(); + String sharedReplicaInstanceType(); } diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.properties b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.properties index 9864039b75a..ae8184e524b 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.properties +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.properties @@ -105,8 +105,14 @@ successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups=Successfully stop stopReplicating=Stop Replicating sameAsMaster=Same as master firstReplicaOnSharedInstance=First replica on shared instance -replicaInstanceType=Instance type for dedicated replicas machineImageId=AMI ID updateAmiForAutoScalingReplicas=Update machine image for auto-scaling replicas successfullyUpdatedMachineImageForAutoScalingReplicas=Successfully updated replica set {0}''s auto-scaling group to machine image {1} -updateSelectedReplicaSetAmisToo=Update the following replica sets to the new machine image, too?\n{0} \ No newline at end of file +updateSelectedReplicaSetAmisToo=Update the following replica sets to the new machine image, too?\n{0} +sharedMasterInstance=Create a shared instance for master process +autoScalingReplicaInstanceType=Instance type for auto-scaling replicas +dedicatedInstanceType=Instance type for dedicated master/replica instances +dedicatedMasterAndAutoScalingReplicaInstanceType=Instance type for dedicated master instance and auto-scaling replicas +sharedMasterInstanceType=Instance type for shared master instance +sharedMasterAndReplicaInstanceType=Instance type for shared master and replica instances +sharedReplicaInstanceType=Instance type for shared replica instance \ No newline at end of file diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages_de.properties b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages_de.properties index e131da72a64..9f5616f20dd 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages_de.properties +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages_de.properties @@ -105,8 +105,14 @@ successfullyStoppedReplicatingAndRemovedMasterFromTargetGroups=Replikation erfol stopReplicating=Replikation stoppen sameAsMaster=Gleich zu Master firstReplicaOnSharedInstance=Erste Replika auf geteilter Instanz -replicaInstanceType=Instanz-Typ der dedizierten Replikas machineImageId=AMI ID updateAmiForAutoScalingReplicas=Maschinen-Abbild für autoskalierende Replikas aktualisieren successfullyUpdatedMachineImageForAutoScalingReplicas=Maschinen-Abbild für autoskalierende Replikas des Anwendungs-Clusters {0} erfolgreich auf {1} aktualisiert. -updateSelectedReplicaSetAmisToo=Sollen die folgenden Anwendungs-Cluster auf das neue Machinen-Abbild aktualisiert werden?\n{0} \ No newline at end of file +updateSelectedReplicaSetAmisToo=Sollen die folgenden Anwendungs-Cluster auf das neue Machinen-Abbild aktualisiert werden?\n{0} +sharedMasterInstance=Teilbare Instanz für Master-Prozess erzeugen +autoScalingReplicaInstanceType=Instanz-Typ der autoskalierungs-Replikas +dedicatedInstanceType=Instanz-Typ für dedizierte Master-/Replika-Instanzen +dedicatedMasterAndAutoScalingReplicaInstanceType=Instanz-Typ für dedizierte Master-Instanz und autoskalierungs-Replikas +sharedMasterInstanceType=Instanz-Typ für geteilte Master-Instanz +sharedMasterAndReplicaInstanceType=Instanz-Typ für geteilte Master- und Replica-Instanzen +sharedReplicaInstanceType=Instanz-Typ für geteilte Replica-Instanz \ No newline at end of file diff --git a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/server/LandscapeManagementWriteServiceImpl.java b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/server/LandscapeManagementWriteServiceImpl.java index d698d7d75a2..76f422cc400 100755 --- a/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/server/LandscapeManagementWriteServiceImpl.java +++ b/java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/server/LandscapeManagementWriteServiceImpl.java @@ -35,7 +35,7 @@ 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.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.impl.SailingAnalyticsHostImpl; import com.sap.sailing.landscape.impl.SailingAnalyticsProcessImpl; import com.sap.sailing.landscape.procedures.DeployProcessOnMultiServer; @@ -176,7 +176,7 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem } @Override - public ArrayList getInstanceTypes() { + public ArrayList getInstanceTypeNames() { final ArrayList result = new ArrayList<>(); Util.addAll(Util.map(Arrays.asList(InstanceType.values()), instanceType->instanceType.name()), result); return result; @@ -461,21 +461,21 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem } @Override - public SailingApplicationReplicaSetDTO createApplicationReplicaSet(String regionId, String name, String masterInstanceType, - String optionalReplicaInstanceTypeOrNull, boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster, - String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String masterReplicationBearerToken, String replicaReplicationBearerToken, - String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, - Integer minimumAutoScalingGroupSizeOrNull, Integer maximumAutoScalingGroupSizeOrNull) + public SailingApplicationReplicaSetDTO createApplicationReplicaSet(String regionId, String name, boolean sharedMasterInstance, + String sharedInstanceType, String dedicatedInstanceType, boolean dynamicLoadBalancerMapping, + String releaseNameOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String masterReplicationBearerToken, + String replicaReplicationBearerToken, String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, + Integer optionalMemoryTotalSizeFactorOrNull, Integer minimumAutoScalingGroupSizeOrNull, Integer maximumAutoScalingGroupSizeOrNull) throws Exception { checkLandscapeManageAwsPermission(); final Release release = getLandscapeService().getRelease(releaseNameOrNullForLatestMaster); final AwsApplicationReplicaSet> result = getLandscapeService() - .createApplicationReplicaSet(regionId, name, masterInstanceType, optionalReplicaInstanceTypeOrNull, - dynamicLoadBalancerMapping, release.getName(), optionalKeyName, privateKeyEncryptionPassphrase, - masterReplicationBearerToken, replicaReplicationBearerToken, optionalDomainName, - optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull, - Optional.ofNullable(minimumAutoScalingGroupSizeOrNull), - Optional.ofNullable(maximumAutoScalingGroupSizeOrNull)); + .createApplicationReplicaSet(regionId, name, sharedMasterInstance, sharedInstanceType, + dedicatedInstanceType, dynamicLoadBalancerMapping, release.getName(), optionalKeyName, + privateKeyEncryptionPassphrase, masterReplicationBearerToken, replicaReplicationBearerToken, + optionalDomainName, optionalMemoryInMegabytesOrNull, + optionalMemoryTotalSizeFactorOrNull, + Optional.ofNullable(minimumAutoScalingGroupSizeOrNull), Optional.ofNullable(maximumAutoScalingGroupSizeOrNull)); return new SailingApplicationReplicaSetDTO(result.getName(), convertToSailingAnalyticsProcessDTO(result .getMaster(), Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase), Util.map(result.getReplicas(), r->{ diff --git a/java/com.sap.sailing.landscape/META-INF/MANIFEST.MF b/java/com.sap.sailing.landscape/META-INF/MANIFEST.MF index f40b30cbceb..6052afb9fc2 100755 --- a/java/com.sap.sailing.landscape/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.landscape/META-INF/MANIFEST.MF @@ -22,7 +22,8 @@ Require-Bundle: com.sap.sse.landscape, com.sap.sailing.server.gateway.interfaces, com.sap.sse.landscape.aws.common, com.sap.sailing.domain.shared.android, - com.sap.sailing.domain + com.sap.sailing.domain, + com.sap.sailing.landscape.common Export-Package: com.sap.sailing.landscape, com.sap.sailing.landscape.impl, com.sap.sailing.landscape.procedures diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/LandscapeService.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/LandscapeService.java index f4024925237..522fceb891f 100644 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/LandscapeService.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/LandscapeService.java @@ -7,6 +7,7 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.procedures.SailingAnalyticsReplicaConfiguration; import com.sap.sailing.landscape.procedures.SailingAnalyticsReplicaConfiguration.Builder; import com.sap.sailing.landscape.procedures.StartMultiServer; @@ -67,12 +68,78 @@ public interface LandscapeService { */ void clearSessionCredentials(); + /** + * Creates a new application replica set by launching a new instance that runs the master process, and if the + * {@code minimumAutoScalingGroupSize} is 0, a replica process running on a shared instance. In this case an + * eligible shared instance is looked for (based on the + * {@link SharedLandscapeConstants#MULTI_PROCESS_INSTANCE_TAG_VALUE} value of the + * {@link SharedLandscapeConstants#SAILING_ANALYTICS_APPLICATION_HOST_TAG} tag), and if not found, a new one is + * launched. If the {@code minimumAutoScalingGroupSize} is greater than 0, no unmanaged replica is launched because + * the auto-scaling group will launch one or more of them on dedicated instances. + * + * @param name + * the name for the new replica set; defines the "server name" from which the server group name, the + * replica channel / exchange name and the database name will be derived. + * @param newSharedMasterInstance + * if {@code true} the instance launched for the master process will be created such that it can be + * shared by other application processes as well. In particular, it's name will be set to + * {@link SharedLandscapeConstants#MULTI_PROCESS_INSTANCE_DEFAULT_NAME} and the + * {@link SharedLandscapeConstants#SAILING_ANALYTICS_APPLICATION_HOST_TAG} tag will be set to + * {@link SharedLandscapeConstants#MULTI_PROCESS_INSTANCE_TAG_VALUE}. + * @param sharedInstanceType + * specifies the type of instance launched for hosting the new master process in case a shared masted + * instance is requested by setting {@code newSharedMasterInstance} to {@code true}, and for launching an + * instance for a first replica not managed by an auto-scaling group in case + * {@code minimumAutoScalingGroupSize} is 0. Make sure to use one that is good for sharing by multiple + * processes; e.g., use an instance type with plenty of fast swap space, such as + * {@link SharedLandscapeConstants#DEFAULT_SHARED_INSTANCE_TYPE_NAME}. The instance type is specified as + * a string that must match one of the {@link InstanceType} {@link Enum#name() literal names}. The + * parameter is ignored if neither a shared master nor a first shared replica are requested. + * @param dedicatedInstanceType + * defines the instance type to use for the master (unless a shared master instance is requested by + * setting the {@code newSharedMasterInstance} parameter to {@code true}) and for the auto-scaling + * replicas. Must not be {@code null}. + * @param dynamicLoadBalancerMapping + * If {@code true}, no DNS entry is created for the new application replica set. Instead, the + * fall-through logic in the landscape's default mapping for the {@code optionalDomainName} (defaulting + * to {@code sapsailing.com}) is used, assuming it points to a default Application Load Balancer (ALB) in + * our default region (see {@link SharedLandscapeConstants#REGION_WITH_DEFAULT_LOAD_BALANCER}). + * @param optionalDomainName + * defaults to {@link SharedLandscapeConstants#DEFAULT_DOMAIN_NAME}. + * @param optionalMemoryInMegabytesOrNull + * if not {@code null}, specifies the heap size to allocate for the master and replica processes each, in + * MB (1024*1024B); if provided, this takes precedence over anything specified in + * {@code optionalMemoryTotalSizeFactorOrNull}. + * @param optionalMemoryTotalSizeFactorOrNull + * if not {@code null} and if {@code optionalMemoryInMegabytesOrNull} does not specify an absolute heap + * size, this parameter specifies how much memory to allocate for application processes on shared + * instances (which does not include dedicated auto-scaling replicas); the amount is specified as a + * fraction of the "physical" RAM (as seen by the operating system running on the instance) minus some + * space reserved for the operating system itself and for the Java VM. It can be thought of as an + * approximation for how many processes configured this way will fit into the instance's physical memory + * without the need for massive swapping activity. + * @param minimumAutoScalingGroupSize + * if {@code 0}, a replica process will be started on a shared host that must run in an availability zone + * different from the one on which the master process runs. If no such shared host exists that is + * eligible to receive a process deployment for the new replica set (e.g., based on available port + * restrictions), a new shared host is launched, using the same instance type specification provided for + * the master ({@code masterInstanceType}). Note that for the probably somewhat unusual combination of a + * non-shared master instance ({@code newSharedMasterInstance==false}) and a + * {@code minimumAutoScalingGroupSize} of 0, a "shared" host that needs to be launched for the first + * replica will inherit an instance type from the master's configuration that may not be suited too well + * for sharing. Eligibility considerations and precedence rules are then hoped to rank such instances to + * the bottom of the list based, e.g., on their available physical / swap memory ratio, so that they + * would hardly ever get chosen as a deployment target for other replica's shared instances. + */ AwsApplicationReplicaSet> createApplicationReplicaSet( - String regionId, String name, String masterInstanceType, String replicaInstanceTypeOrNull, - boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster, String optionalKeyName, - byte[] privateKeyEncryptionPassphrase, String masterReplicationBearerToken, String replicaReplicationBearerToken, - String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, Optional minimumAutoScalingGroupSize, Optional maximumAutoScalingGroupSize) throws Exception; - + String regionId, String name, boolean newSharedMasterInstance, String sharedInstanceType, + String dedicatedInstanceType, boolean dynamicLoadBalancerMapping, + String releaseNameOrNullForLatestMaster, String optionalKeyName, byte[] privateKeyEncryptionPassphrase, + String masterReplicationBearerToken, String replicaReplicationBearerToken, String optionalDomainName, + Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, + Optional minimumAutoScalingGroupSize, Optional maximumAutoScalingGroupSize) + throws Exception; + /** * Starts a first master process of a new replica set whose name is provided by the {@code replicaSetName} parameter. * The process is started on the host identified by the {@code hostToDeployTo} parameter. A set of available ports @@ -177,8 +244,8 @@ public interface LandscapeService { /** * In the {@code region} specified, searches through all hosts tagged with the - * {@link SharedLandscapeConstants#SAILING_ANALYTICS_APPLICATION_HOST_TAG} tag (regardless the tag's value) for - * hosts that are + * {@link SharedLandscapeConstants#SAILING_ANALYTICS_APPLICATION_HOST_TAG} tag set to + * {@link SharedLandscapeConstants#MULTI_PROCESS_INSTANCE_TAG_VALUE} for hosts that are * {@link AwsApplicationReplicaSet#isEligibleForDeployment(com.sap.sse.landscape.aws.ApplicationProcessHost, Optional, Optional, byte[]) * eligible} for receiving a deployment of a process that belongs to the {@code replicaSet}. This could be a master * or a replica; both will require the same set of resources that the eligibility check is looking for: the HTTP @@ -186,7 +253,7 @@ public interface LandscapeService { * * @return the hosts eligible for receiving a process deployment for the {@code replicaSet}. */ - Iterable> getEligibleHostsForReplicaSet(AwsRegion region, + Iterable> getEligibleSharedHostsForReplicaSet(AwsRegion region, AwsApplicationReplicaSet> replicaSet, String optionalKeyName, byte[] privateKeyEncryptionPassphrase); diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/EligbleInstanceForReplicaSetFindingStrategyImpl.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/EligbleInstanceForReplicaSetFindingStrategyImpl.java index 3df284e8296..c400d588d7c 100644 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/EligbleInstanceForReplicaSetFindingStrategyImpl.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/EligbleInstanceForReplicaSetFindingStrategyImpl.java @@ -14,7 +14,7 @@ import com.sap.sailing.landscape.LandscapeService; import com.sap.sailing.landscape.SailingAnalyticsHost; import com.sap.sailing.landscape.SailingAnalyticsMetrics; import com.sap.sailing.landscape.SailingAnalyticsProcess; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sse.common.Util; import com.sap.sse.landscape.AvailabilityZone; import com.sap.sse.landscape.aws.ApplicationProcessHost; @@ -88,8 +88,9 @@ public class EligbleInstanceForReplicaSetFindingStrategyImpl implements Eligible * replica set's master process. * @param optionalInstanceType * if a new instance must be launched because no eligible one is found, this parameter can be used to - * specify its instance type. It defaults to {@link InstanceType#I3_2_XLARGE} which is reasonably suited - * for a multi-process set-up. + * specify its instance type. It defaults to + * {@link SharedLandscapeConstants#DEFAULT_SHARED_INSTANCE_TYPE_NAME} which is reasonably suited for a + * multi-process set-up. * @param optionalPreferredInstanceToDeployTo * If {@link Optional#isPresent() present}, specifies a preferred host for the answer given by * {@link #getInstanceToDeployTo(AwsApplicationReplicaSet)}. However, if the instance turns out not to be @@ -110,7 +111,7 @@ public class EligbleInstanceForReplicaSetFindingStrategyImpl implements Eligible this.privateKeyEncryptionPassphrase = privateKeyEncryptionPassphrase; this.master = master; this.mustBeDifferentAvailabilityZone = mustBeDifferentAvailabilityZone; - this.instanceType = optionalInstanceType.orElse(InstanceType.I3_2_XLARGE); + this.instanceType = optionalInstanceType.orElse(InstanceType.valueOf(SharedLandscapeConstants.DEFAULT_SHARED_INSTANCE_TYPE_NAME)); this.optionalPreferredInstanceToDeployTo = optionalPreferredInstanceToDeployTo; } @@ -128,7 +129,7 @@ public class EligbleInstanceForReplicaSetFindingStrategyImpl implements Eligible }).orElseGet(()->{ logger.info("Preferred instance not specified or not eligible. Computing default..."); final Optional> bestExistingCandidate = - Util.stream(landscapeService.getEligibleHostsForReplicaSet(region, replicaSet, optionalKeyName, privateKeyEncryptionPassphrase)) + Util.stream(landscapeService.getEligibleSharedHostsForReplicaSet(region, replicaSet, optionalKeyName, privateKeyEncryptionPassphrase)) .filter(host->{ try { return !isArchiveServer(host) && isAcceptableAvailabilityZone(host.getAvailabilityZone(), replicaSet); diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java index ba192d284ca..9ad017ea05a 100644 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java @@ -33,7 +33,7 @@ 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.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.procedures.CreateLaunchConfigurationAndAutoScalingGroup; import com.sap.sailing.landscape.procedures.DeployProcessOnMultiServer; import com.sap.sailing.landscape.procedures.SailingAnalyticsHostSupplier; @@ -126,20 +126,22 @@ public class LandscapeServiceImpl implements LandscapeService { @Override public AwsApplicationReplicaSet> createApplicationReplicaSet( - String regionId, String name, String masterInstanceType, String replicaInstanceTypeOrNull, - boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster, String optionalKeyName, - byte[] privateKeyEncryptionPassphrase, String masterReplicationBearerToken, String replicaReplicationBearerToken, - String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, - Optional minimumAutoScalingGroupSize, Optional maximumAutoScalingGroupSize) throws Exception { + String regionId, String name, boolean newSharedMasterInstance, String sharedInstanceType, + String dedicatedInstanceType, boolean dynamicLoadBalancerMapping, String releaseNameOrNullForLatestMaster, + String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String masterReplicationBearerToken, + String replicaReplicationBearerToken, String optionalDomainName, Integer optionalMemoryInMegabytesOrNull, + Integer optionalMemoryTotalSizeFactorOrNull, Optional minimumAutoScalingGroupSize, + Optional maximumAutoScalingGroupSize) throws Exception { final AwsLandscape landscape = getLandscape(); final AwsRegion region = new AwsRegion(regionId, landscape); final Release release = getRelease(releaseNameOrNullForLatestMaster); establishServerGroupAndTryToMakeCurrentUserItsOwnerAndMember(name); final com.sap.sailing.landscape.procedures.SailingAnalyticsMasterConfiguration.Builder masterConfigurationBuilder = - createMasterConfigurationBuilder(name, masterReplicationBearerToken, optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull, region, release); + createMasterConfigurationBuilder(name, masterReplicationBearerToken, optionalMemoryInMegabytesOrNull, + newSharedMasterInstance ? optionalMemoryTotalSizeFactorOrNull : null, region, release); final com.sap.sailing.landscape.procedures.StartSailingAnalyticsMasterHost.Builder masterHostBuilder = StartSailingAnalyticsMasterHost.masterHostBuilder(masterConfigurationBuilder); masterHostBuilder - .setInstanceType(InstanceType.valueOf(masterInstanceType)) + .setInstanceType(InstanceType.valueOf(newSharedMasterInstance ? sharedInstanceType : dedicatedInstanceType)) .setOptionalTimeout(WAIT_FOR_HOST_TIMEOUT) .setLandscape(landscape) .setRegion(region) @@ -147,13 +149,17 @@ public class LandscapeServiceImpl implements LandscapeService { if (optionalKeyName != null) { masterHostBuilder.setKeyName(optionalKeyName); } + if (newSharedMasterInstance) { + masterHostBuilder + .setInstanceName(SharedLandscapeConstants.MULTI_PROCESS_INSTANCE_DEFAULT_NAME) + .setTags(Tags.with(SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG, SharedLandscapeConstants.MULTI_PROCESS_INSTANCE_TAG_VALUE)); + } final StartSailingAnalyticsMasterHost masterHostStartProcedure = masterHostBuilder.build(); masterHostStartProcedure.run(); final SailingAnalyticsProcess master = masterHostStartProcedure.getSailingAnalyticsProcess(); final String bearerTokenUsedByReplicas = Util.hasLength(replicaReplicationBearerToken) ? replicaReplicationBearerToken : getSecurityService().getOrCreateAccessToken(SessionUtils.getPrincipal().toString()); final AwsApplicationReplicaSet> result = - createLoadBalancingAndAutoScalingSetup(landscape, region, name, master, release, - replicaInstanceTypeOrNull == null ? masterInstanceType : replicaInstanceTypeOrNull, + createLoadBalancingAndAutoScalingSetup(landscape, region, name, master, release, dedicatedInstanceType, dynamicLoadBalancerMapping, optionalKeyName, privateKeyEncryptionPassphrase, optionalDomainName, Optional.of(masterHostBuilder.getMachineImage()), bearerTokenUsedByReplicas, minimumAutoScalingGroupSize, maximumAutoScalingGroupSize); @@ -164,7 +170,7 @@ public class LandscapeServiceImpl implements LandscapeService { try { unmanagedReplicas.add(launchUnmanagedReplica(result, region, optionalKeyName, privateKeyEncryptionPassphrase, replicaReplicationBearerToken, optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull, - Optional.of(InstanceType.valueOf(masterInstanceType)), // use master's instance type as this may be an all-shared use case + Optional.of(InstanceType.valueOf(sharedInstanceType)), /* optionalPreferredInstanceToDeployTo */ Optional.empty())); } catch (Exception e) { throw new RuntimeException(e); @@ -300,6 +306,9 @@ public class LandscapeServiceImpl implements LandscapeService { * If a new instance needs to be launched, the instance type can optionally be specified. It defaults to something * with large fast swap space and a reasonable amount of physical RAM that would allow somewhere between two and * four processes to share the physical RAM even during a live event. + * + * @param optionalInstanceType + * defaults to {@link SharedLandscapeConstants#DEFAULT_SHARED_INSTANCE_TYPE_NAME} */ private SailingAnalyticsProcess launchUnmanagedReplica( final AwsApplicationReplicaSet> replicaSet, @@ -800,11 +809,12 @@ public class LandscapeServiceImpl implements LandscapeService { } @Override - public Iterable> getEligibleHostsForReplicaSet(AwsRegion region, + public Iterable> getEligibleSharedHostsForReplicaSet(AwsRegion region, final AwsApplicationReplicaSet> replicaSet, String optionalKeyName, byte[] privateKeyEncryptionPassphrase) { - return Util.filter(getLandscape().getRunningHostsWithTag(region, SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG, new SailingAnalyticsHostSupplier()), - h->{ + return Util.filter(getLandscape().getRunningHostsWithTagValue(region, + SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG, SharedLandscapeConstants.MULTI_PROCESS_INSTANCE_TAG_VALUE, + new SailingAnalyticsHostSupplier()), h->{ try { return replicaSet.isEligibleForDeployment(h, LandscapeService.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase); } catch (Exception e) { diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartMultiServer.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartMultiServer.java index 0808890322d..f55ab0008e0 100755 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartMultiServer.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartMultiServer.java @@ -3,7 +3,7 @@ package com.sap.sailing.landscape.procedures; import java.util.Optional; import com.sap.sailing.landscape.SailingAnalyticsHost; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sse.common.Duration; import com.sap.sse.landscape.aws.HostSupplier; import com.sap.sse.landscape.aws.Tags; diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartSailingAnalyticsHost.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartSailingAnalyticsHost.java index db022d82b5d..acd17a7bc26 100755 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartSailingAnalyticsHost.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/StartSailingAnalyticsHost.java @@ -6,7 +6,7 @@ import java.util.logging.Logger; import com.sap.sailing.landscape.SailingAnalyticsHost; import com.sap.sailing.landscape.SailingAnalyticsMetrics; import com.sap.sailing.landscape.SailingAnalyticsProcess; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.impl.SailingAnalyticsProcessImpl; import com.sap.sse.landscape.aws.AmazonMachineImage; import com.sap.sse.landscape.aws.ApplicationProcessHost; @@ -37,16 +37,17 @@ implements Procedure, StartFromSailingAnalyticsImage { * {@link StartAwsApplicationHost.Builder}, are: *

    *
  • If no {@link #setInstanceName(String) instance name} is provided, the instance name is constructed from the - * {@link #getServerName() server name} by pre-pending the prefix "SL " (see {@link StartSailingAnalyticsHost#INSTANCE_NAME_DEFAULT_PREFIX}).
  • + * {@link #getServerName() server name} by pre-pending the prefix "SL " (see + * {@link StartSailingAnalyticsHost#INSTANCE_NAME_DEFAULT_PREFIX}). *
  • Uses the latest machine image of the type described by * {@link StartSailingAnalyticsHost#IMAGE_TYPE_TAG_VALUE_SAILING} if no explicit * {@link #setMachineImage(AmazonMachineImage) machine image is set} and no {@link #setImageType(String) image type * is set} of which the latest version would be used otherwise.
  • *
  • The {@link #getServerDirectory() server directory} defaults to {@code /home/sailing/servers/} * (see {@link ApplicationProcessHost#DEFAULT_SERVER_PATH})
  • - *
  • The tag {@link SharedLandscapeConstants#SAILING_ANALYTICS_APPLICATION_HOST_TAG} is set, with the value equaling the - * {@link SailingAnalyticsApplicationConfiguration.Builder#setServerName(String) server name} set in the application - * configuration.
  • + *
  • If the tag {@link SharedLandscapeConstants#SAILING_ANALYTICS_APPLICATION_HOST_TAG} is not set, it defaults to + * the value equaling the {@link SailingAnalyticsApplicationConfiguration.Builder#setServerName(String) server name} + * set in the application configuration.
  • *
* * @author Axel Uhl (D043530) @@ -86,7 +87,9 @@ implements Procedure, StartFromSailingAnalyticsImage { @Override protected Optional getTags() { - return Optional.of(super.getTags().orElse(Tags.empty()).and(SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG, getApplicationConfigurationBuilder().getServerName())); + return Optional.of( + Tags.with(SharedLandscapeConstants.SAILING_ANALYTICS_APPLICATION_HOST_TAG, getApplicationConfigurationBuilder().getServerName()) + .andAll(super.getTags().orElse(Tags.empty()))); } @Override diff --git a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/UpgradeAmi.java b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/UpgradeAmi.java index ce6f30fb4c9..3d9953b92ba 100755 --- a/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/UpgradeAmi.java +++ b/java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/procedures/UpgradeAmi.java @@ -15,7 +15,7 @@ import com.jcraft.jsch.JSchException; import com.sap.sailing.landscape.SailingAnalyticsHost; import com.sap.sailing.landscape.SailingAnalyticsMetrics; import com.sap.sailing.landscape.SailingAnalyticsProcess; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.impl.SailingAnalyticsHostImpl; import com.sap.sailing.landscape.impl.SailingAnalyticsProcessImpl; import com.sap.sse.common.Duration; @@ -147,7 +147,6 @@ implements Procedure, StartFromSailingAnalyticsImage { private BuilderImpl() { super(); - setNoShutdown(false); } @Override diff --git a/java/com.sap.sailing.www/release_notes_admin.html b/java/com.sap.sailing.www/release_notes_admin.html index 6a73f3dda75..6762573b25b 100755 --- a/java/com.sap.sailing.www/release_notes_admin.html +++ b/java/com.sap.sailing.www/release_notes_admin.html @@ -23,6 +23,22 @@

Release Notes - Administration Console

+

January 2022

+
    +
  • Landscape management now offers to upgrade auto-scaling groups after an AMI update.
  • +
  • Replica sets can now also be managed on shared instances. This goes for new master processes which + can be deployed into the instance hosting another replica set's master process, or into a new + instance prepared for being shared. Alternatively to having the auto-scaling group provide a + dedicated first replica to increase availability, users can now choose to have a replica be deployed + to a shared instance that runs in an availability zone different from that of the one hosting the + replica set's master process. If no such shared instance with the port required by the new + replica set available, a new one is created in an availability zone other than the one hosting + this replica set's master process, and the first replica is deployed onto that.

    + With these steps, operators are now able to set up new replica sets using only shared + instances when starting. While auto-scaling replicas will still be launched into new + dedicated instances when the workload requires it, small-scale set-ups with low workloads + can now be mapped very cost-effectively.

  • +

December 2021

  • The import of data from another server ("Advanced - Master Data Import") now waits for tracked races diff --git a/java/com.sap.sse.landscape.aws.test/META-INF/MANIFEST.MF b/java/com.sap.sse.landscape.aws.test/META-INF/MANIFEST.MF index 37a30779dd7..c291da2e37b 100755 --- a/java/com.sap.sse.landscape.aws.test/META-INF/MANIFEST.MF +++ b/java/com.sap.sse.landscape.aws.test/META-INF/MANIFEST.MF @@ -13,6 +13,7 @@ Require-Bundle: org.hamcrest;bundle-version="1.1.0", com.sap.sailing.landscape, org.mongodb.bson;bundle-version="4.3.1", org.mongodb.driver-core;bundle-version="4.3.1", - org.mongodb.driver-sync;bundle-version="4.3.1" + org.mongodb.driver-sync;bundle-version="4.3.1", + com.sap.sailing.landscape.common Import-Package: org.mockito, org.mockito.stubbing;version="1.10.14" diff --git a/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java b/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java index c4f557ff142..b146914fabc 100755 --- a/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java +++ b/java/com.sap.sse.landscape.aws.test/src/com/sap/sse/landscape/aws/ConnectivityTest.java @@ -33,7 +33,7 @@ import com.jcraft.jsch.JSchException; import com.jcraft.jsch.KeyPair; import com.sap.sailing.landscape.SailingAnalyticsMetrics; import com.sap.sailing.landscape.SailingReleaseRepository; -import com.sap.sailing.landscape.SharedLandscapeConstants; +import com.sap.sailing.landscape.common.SharedLandscapeConstants; import com.sap.sailing.landscape.impl.SailingAnalyticsProcessImpl; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/Tags.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/Tags.java index 5f7d4ccb14e..f6c02f18d76 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/Tags.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/Tags.java @@ -9,7 +9,22 @@ public interface Tags extends Iterable>{ return new TagsImpl(key, value); } + /** + * Adds the {@code key} to the map and sets its value. If the key was already + * part of these {@link Tags} then its value is overwritten by this call. + */ Tags and(String key, String value); + + /** + * {@link #and(String, String) Adds} all tags from {@code tags} to this map of tags. + * Keys from {@code tags} that already exist in this tags map are overwritten. + */ + default Tags andAll(Tags tags) { + for (final Entry tag : tags) { + and(tag.getKey(), tag.getValue()); + } + return this; + } static Tags empty() { return new TagsImpl(); diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java index 8c9327aac96..841c3d07875 100644 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java @@ -1696,7 +1696,7 @@ public class AwsLandscapeImpl implements AwsLandscape logger.info("Adjusting AMI for auto-scaling group "+autoScalingGroup.getName()+" to "+ami); final AutoScalingClient autoScalingClient = getAutoScalingClient(getRegion(region)); final LaunchConfiguration oldLaunchConfiguration = autoScalingGroup.getLaunchConfiguration(); - final String newLaunchConfigurationName = getLaunchConfigurationName(replicaSetName, "ami-"+ami.getId()); + final String newLaunchConfigurationName = getLaunchConfigurationName(replicaSetName, ami.getId()); logger.info("Creating new launch configuration "+newLaunchConfigurationName); autoScalingClient.createLaunchConfiguration(b->b .associatePublicIpAddress(oldLaunchConfiguration.associatePublicIpAddress()) diff --git a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/orchestration/StartEmptyServer.java b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/orchestration/StartEmptyServer.java index 36dc818c31e..3a89a872a6e 100755 --- a/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/orchestration/StartEmptyServer.java +++ b/java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/orchestration/StartEmptyServer.java @@ -45,7 +45,7 @@ implements Procedure { ShardingKey, HostT extends AwsInstance> extends StartAwsHost.BuilderImpl implements Builder { - private boolean noShutdown = true; + private boolean noShutdown = false; protected boolean isNoShutdown() { return noShutdown;