java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/ApplicationReplicaSetsImagesBarCell.java
... ...
@@ -14,6 +14,7 @@ import com.sap.sse.security.ui.client.UserService;
14 14
public class ApplicationReplicaSetsImagesBarCell extends ImagesBarCell {
15 15
static final String ACTION_REMOVE = DefaultActions.DELETE.name();
16 16
static final String ACTION_UPGRADE = "UPGRADE";
17
+ static final String ACTION_ACTIVATE_ARCHIVE_CANDIDATE = "ACTIVATE_ARCHIVE_CANDIDATE";
17 18
static final String ACTION_ARCHIVE = "ARCHIVE";
18 19
static final String ACTION_DEFINE_LANDING_PAGE = "DEFINE_LANDING_PAGE";
19 20
static final String ACTION_CREATE_LOAD_BALANCER_MAPPING = "CREATE_LOAD_BALANGER_MAPPING";
... ...
@@ -63,6 +64,9 @@ public class ApplicationReplicaSetsImagesBarCell extends ImagesBarCell {
63 64
if (!applicationReplicaSet.isLocalReplicaSet(userService) && !applicationReplicaSet.isArchive()) {
64 65
result.add(new ImageSpec(ACTION_UPGRADE, stringMessages.upgrade(), IconResources.INSTANCE.refreshIcon()));
65 66
}
67
+ if (applicationReplicaSet.isArchive()) {
68
+ result.add(new ImageSpec(ACTION_ACTIVATE_ARCHIVE_CANDIDATE, stringMessages.activateArchiveCandidate(), IconResources.INSTANCE.check()));
69
+ }
66 70
if (!applicationReplicaSet.isArchive()) {
67 71
result.add(
68 72
new ImageSpec(ACTION_ENSURE_ONE_REPLICA_THEN_STOP_REPLICATING_AND_REMOVE_MASTER_FROM_TARGET_GROUPS,
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementPanel.java
... ...
@@ -334,6 +334,9 @@ public class LandscapeManagementPanel extends SimplePanel {
334 334
}
335 335
}
336 336
);
337
+ applicationReplicaSetsActionColumn.addAction(ApplicationReplicaSetsImagesBarCell.ACTION_ACTIVATE_ARCHIVE_CANDIDATE,
338
+ applicationReplicaSetToActivateAsNewArchive -> makeCandidateArchiveServerGoLive(stringMessages,
339
+ regionsTable.getSelectionModel().getSelectedObject(), applicationReplicaSetToActivateAsNewArchive));
337 340
applicationReplicaSetsActionColumn.addAction(ApplicationReplicaSetsImagesBarCell.ACTION_DEFINE_LANDING_PAGE,
338 341
applicationReplicaSetForWhichToDefineLandingPage -> defineLandingPage(stringMessages,
339 342
regionsTable.getSelectionModel().getSelectedObject(), applicationReplicaSetForWhichToDefineLandingPage));
... ...
@@ -1458,7 +1461,7 @@ public class LandscapeManagementPanel extends SimplePanel {
1458 1461
}
1459 1462
1460 1463
private void upgradeArchiveServer(StringMessages stringMessages, String regionId,
1461
- SailingApplicationReplicaSetDTO<String> replicaSet) {
1464
+ SailingApplicationReplicaSetDTO<String> archiveReplicaSet) {
1462 1465
landscapeManagementService.getReleases(new AsyncCallback<ArrayList<ReleaseDTO>>() {
1463 1466
@Override
1464 1467
public void onFailure(Throwable caught) {
... ...
@@ -1471,7 +1474,7 @@ public class LandscapeManagementPanel extends SimplePanel {
1471 1474
stringMessages, errorReporter, new DialogCallback<UpgradeArchiveServerDialog.UpgradeArchiveServerInstructions>() {
1472 1475
@Override
1473 1476
public void ok(UpgradeArchiveServerInstructions upgradeInstructions) {
1474
- landscapeManagementService.createArchiveReplicaSet(regionId, replicaSet, upgradeInstructions.getInstanceTypeOrNull(),
1477
+ landscapeManagementService.createArchiveReplicaSet(regionId, archiveReplicaSet, upgradeInstructions.getInstanceTypeOrNull(),
1475 1478
upgradeInstructions.getReleaseNameOrNullForLatestMaster(), sshKeyManagementPanel.getSelectedKeyPair()==null?null:sshKeyManagementPanel.getSelectedKeyPair().getName(),
1476 1479
sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
1477 1480
? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes() : null,
... ...
@@ -1486,7 +1489,7 @@ public class LandscapeManagementPanel extends SimplePanel {
1486 1489
@Override
1487 1490
public void onSuccess(Void result) {
1488 1491
Notification.notify(stringMessages.successfullyLaunchedNewArchiveCandidate(
1489
- replicaSet.getName(), upgradeInstructions.getReleaseNameOrNullForLatestMaster()),
1492
+ archiveReplicaSet.getName(), upgradeInstructions.getReleaseNameOrNullForLatestMaster()),
1490 1493
NotificationType.SUCCESS);
1491 1494
}
1492 1495
});
... ...
@@ -1500,6 +1503,26 @@ public class LandscapeManagementPanel extends SimplePanel {
1500 1503
});
1501 1504
}
1502 1505
1506
+ private void makeCandidateArchiveServerGoLive(StringMessages stringMessages, String regionId, SailingApplicationReplicaSetDTO<String> archiveReplicaSetToUpgrade) {
1507
+ landscapeManagementService.makeCandidateArchiveServerGoLive(regionId, archiveReplicaSetToUpgrade,
1508
+ sshKeyManagementPanel.getSelectedKeyPair() == null ? null
1509
+ : sshKeyManagementPanel.getSelectedKeyPair().getName(),
1510
+ sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption() != null
1511
+ ? sshKeyManagementPanel.getPassphraseForPrivateKeyDecryption().getBytes()
1512
+ : null,
1513
+ new AsyncCallback<Void>() {
1514
+ @Override
1515
+ public void onFailure(Throwable caught) {
1516
+ errorReporter.reportError(caught.getMessage());
1517
+ }
1518
+
1519
+ @Override
1520
+ public void onSuccess(Void result) {
1521
+ Notification.notify(stringMessages.successfullySwitchedToNewArchiveCandidate(archiveReplicaSetToUpgrade.getName()), NotificationType.SUCCESS);
1522
+ }
1523
+ });
1524
+ }
1525
+
1503 1526
private void refreshRegionsTable(UserService userService) {
1504 1527
landscapeManagementService.getRegions(new AsyncCallback<ArrayList<String>>() {
1505 1528
@Override
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteService.java
... ...
@@ -188,4 +188,8 @@ public interface LandscapeManagementWriteService extends RemoteService {
188 188
String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
189 189
190 190
boolean hasDNSResourceRecordsForReplicaSet(String replicaSetName, String optionalDomainName);
191
+
192
+ void makeCandidateArchiveServerGoLive(String regionId,
193
+ SailingApplicationReplicaSetDTO<String> archiveReplicaSetToUpgrade, String optionalKeyName,
194
+ byte[] privateKeyEncryptionPassphrase) throws Exception;
191 195
}
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementWriteServiceAsync.java
... ...
@@ -195,6 +195,9 @@ public interface LandscapeManagementWriteServiceAsync {
195 195
byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken, String replicaReplicationBearerToken,
196 196
Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull, AsyncCallback<Void> callback);
197 197
198
+ void makeCandidateArchiveServerGoLive(String regionId,
199
+ SailingApplicationReplicaSetDTO<String> archiveReplicaSetToUpgrade, String optionalKeyName,
200
+ byte[] privateKeyEncryptionPassphrase, AsyncCallback<Void> callback);
198 201
/**
199 202
* For the given replica set ensures there is at least one healthy replica, then stops replicating on all replicas and
200 203
* removes the master from the public and master target groups. This can be used as a preparatory action for upgrading
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java
... ...
@@ -181,4 +181,6 @@ com.sap.sse.gwt.adminconsole.StringMessages {
181 181
String igtimiRiotPort();
182 182
String examplePort(int examplePort);
183 183
String successfullyLaunchedNewArchiveCandidate(String replicaSetName, String releaseName);
184
+ String successfullySwitchedToNewArchiveCandidate(String replicaSetName);
185
+ String activateArchiveCandidate();
184 186
}
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.properties
... ...
@@ -169,4 +169,6 @@ publicIp=Public IP address
169 169
privateIp=Private IP address
170 170
igtimiRiotPort=Igtimi Riot Port
171 171
examplePort=e.g., {0}
172
-successfullyLaunchedNewArchiveCandidate=Successfully launched new {0} candidate with release {1}. You will receive an e-mail when the candidate is ready for spot checks and rotation to production. This can take several hours, depending on the number of events to load.
... ...
\ No newline at end of file
0
+successfullyLaunchedNewArchiveCandidate=Successfully launched new {0} candidate with release {1}. You will receive an e-mail when the candidate is ready for spot checks and rotation to production. This can take several hours, depending on the number of events to load.
1
+successfullySwitchedToNewArchiveCandidate=Successfully switched to new {0} server
2
+activateArchiveCandidate=Activate ARCHIVE candidate (must have run an upgrade before and received the success e-mail!)
... ...
\ No newline at end of file
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages_de.properties
... ...
@@ -168,4 +168,6 @@ publicIp=Öffentlich IP-Adresse
168 168
privateIP=Private IP-Adresse
169 169
igtimiRiotPort=Igtimi Riot Port
170 170
examplePort=z.B. {0}
171
-successfullyLaunchedNewArchiveCandidate=Neuen Kandidaten für {0} mit Version {1} gestartet. Es erfolgt eine Benachrichtigung per e-Mail. Das kann, je nach Umfang der zu ladenden Daten, etliche Stunden dauern.
... ...
\ No newline at end of file
0
+successfullyLaunchedNewArchiveCandidate=Neuen Kandidaten für {0} mit Version {1} gestartet. Es erfolgt eine Benachrichtigung per e-Mail. Das kann, je nach Umfang der zu ladenden Daten, etliche Stunden dauern.
1
+successfullySwitchedToNewArchiveCandidate=Erfolgreich auf neuen Server {0} umgeschaltet
2
+activateArchiveCandidate=ARCHIVE-Kandidaten aktivieren (zuvor muss ein Upgrade-Versuch per e-Mail als erfolgreich markiert worden sein!)
... ...
\ No newline at end of file
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/server/LandscapeManagementWriteServiceImpl.java
... ...
@@ -683,7 +683,6 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
683 683
String instanceType, String releaseNameOrNullForLatestMaster, String optionalKeyName,
684 684
byte[] privateKeyEncryptionPassphrase, String securityReplicationBearerToken,
685 685
String replicaReplicationBearerToken, Integer optionalMemoryInMegabytesOrNull, Integer optionalMemoryTotalSizeFactorOrNull) throws Exception {
686
- // TODO bug6203: we also should provide a possibility to specify memory size; if not provided, we should clone the current archive's settings
687 686
checkLandscapeManageAwsPermission();
688 687
final String userSetOrArchiveServerSecurityReplicationBearerToken;
689 688
final AwsRegion region = new AwsRegion(regionId, getLandscape());
... ...
@@ -706,10 +705,17 @@ public class LandscapeManagementWriteServiceImpl extends ResultCachingProxiedRem
706 705
.createArchiveReplicaSet(regionId, replicaSetName, instanceType, releaseNameOrNullForLatestMaster,
707 706
databaseConfiguration, optionalKeyName, privateKeyEncryptionPassphrase,
708 707
userSetOrArchiveServerSecurityReplicationBearerToken, replicaReplicationBearerToken, domainName,
709
- /* optionalMemoryInMegabytesOrNull TODO bug6203 */ null, /* optionalMemoryTotalSizeFactorOrNull TODO bug6203 */ null,
708
+ optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull,
710 709
/* optionalIgtimiRiotPort */ null);
711 710
}
712 711
712
+ @Override
713
+ public void makeCandidateArchiveServerGoLive(String regionId, SailingApplicationReplicaSetDTO<String> archiveReplicaSetToUpgrade,
714
+ String optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception {
715
+ final String domainName = AwsLandscape.getHostedZoneName(archiveReplicaSetToUpgrade.getHostname());
716
+ getLandscapeService().makeCandidateArchiveServerGoLive(regionId, optionalKeyName, privateKeyEncryptionPassphrase, domainName);
717
+ }
718
+
713 719
/**
714 720
* Starts a first master process of a new replica set whose name is provided by the {@code replicaSetName}
715 721
* parameter. The process is started on the host identified by the {@code hostToDeployTo} parameter. A set of
java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/LandscapeService.java
... ...
@@ -157,6 +157,16 @@ public interface LandscapeService {
157 157
Integer optionalIgtimiRiotPort, Optional<Integer> minimumAutoScalingGroupSize, Optional<Integer> maximumAutoScalingGroupSize)
158 158
throws Exception;
159 159
160
+ /**
161
+ * Runs phase 1 of an ARCHIVE server upgrade. This includes launching the new instance in a favorable availability
162
+ * zone where ideally we have a reverse proxy and that ideally is different from the AZ in which the current
163
+ * production ARCHIVE server runs. It then installs a {@link ArchiveCandidateMonitoringBackgroundTask background
164
+ * task} that keeps applying a sequence of checks. When any of the checks keeps failing beyond a timeout, the
165
+ * activity is aborted, and the user who triggered it receives an e-mail about this. If all checks pass, the user
166
+ * receives an e-mail that asks for manual spot checks and a confirmation about the rotation. A link embedded in the
167
+ * e-mail grants the user easy access to the
168
+ * {@link #makeCandidateArchiveServerGoLive(String, String, byte[], String)} method which then performs phase 2.
169
+ */
160 170
void createArchiveReplicaSet(
161 171
String regionId, String name, String instanceType, String releaseNameOrNullForLatestMaster, Database databaseConfiguration,
162 172
String optionalKeyName, byte[] privateKeyEncryptionPassphrase, String securityServiceReplicationBearerToken,
... ...
@@ -164,6 +174,15 @@ public interface LandscapeService {
164 174
Integer optionalMemoryTotalSizeFactorOrNull, Integer optionalIgtimiRiotPort) throws Exception;
165 175
166 176
/**
177
+ * Phase 2 of an ARCHIVE server upgrade. This is to be triggered ideally after a "human in the loop" step
178
+ * where a user makes some spot checks and then confirms that the archive candidate can be installed as the
179
+ * new production server, with the previous production server then becoming the failover, and the old failover
180
+ * instance being terminated.
181
+ */
182
+ void makeCandidateArchiveServerGoLive(String regionId, String optionalKeyName,
183
+ byte[] privateKeyEncryptionPassphrase, String optionalDomainName) throws Exception;
184
+
185
+ /**
167 186
* Starts a first master process of a new replica set whose name is provided by the {@code replicaSetName}
168 187
* parameter. The process is started on the host identified by the {@code hostToDeployTo} parameter. A set of
169 188
* available ports is identified and chosen automatically. The target groups and load balancing set-up is created.
... ...
@@ -519,7 +538,4 @@ public interface LandscapeService {
519 538
throws MailException;
520 539
521 540
SailingServerFactory getSailingServerFactory();
522
-
523
- void makeCandidateArchiveServerGoLive(String regionId, String optionalKeyName,
524
- byte[] privateKeyEncryptionPassphrase, String optionalDomainName) throws Exception;
525 541
}
java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/ArchiveCandidateMonitoringBackgroundTask.java
... ...
@@ -41,6 +41,7 @@ import com.sap.sse.security.shared.impl.User;
41 41
* <li>the one-minute system load average must be below 2 (per cent)</li>
42 42
* <li>the default foreground thread pool queue must contain less than 10 tasks</li>
43 43
* <li>the default background thread pool queue must contain less than 10 tasks</li>
44
+ * <li>the old and new ARCHIVE must compare equal with the {@link SailingServer#compareServers(Optional, SailingServer, Optional)} method</li>
44 45
* </ol>
45 46
*
46 47
* When any of these conditions is not fulfilled, the task will re-schedule itself after some delay to check again until
java/com.sap.sailing.landscape/src/com/sap/sailing/landscape/impl/LandscapeServiceImpl.java
... ...
@@ -253,8 +253,15 @@ public class LandscapeServiceImpl implements LandscapeService {
253 253
}
254 254
final AwsRegion region = new AwsRegion(regionId, landscape);
255 255
final Release release = getRelease(releaseNameOrNullForLatestMaster);
256
+ final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> oldArchiveReplicaSet = getApplicationReplicaSet(
257
+ region, SharedLandscapeConstants.ARCHIVE_SERVER_APPLICATION_REPLICA_SET_NAME,
258
+ Landscape.WAIT_FOR_PROCESS_TIMEOUT.map(Duration::asMillis).orElse(null),
259
+ optionalKeyName, privateKeyEncryptionPassphrase);
260
+ final Integer oldArchiveMemoryInMB = getMemoryInMegabytes(optionalKeyName, privateKeyEncryptionPassphrase, oldArchiveReplicaSet.getMaster());
256 261
final com.sap.sailing.landscape.procedures.SailingAnalyticsMasterConfiguration.Builder<?, String> masterConfigurationBuilder =
257
- createArchiveConfigurationBuilder(replicaSetName, databaseConfiguration, securityServiceReplicationBearerToken, optionalMemoryInMegabytesOrNull,
262
+ createArchiveConfigurationBuilder(replicaSetName, databaseConfiguration, securityServiceReplicationBearerToken,
263
+ // if no memory size is specified, use that of existing production ARCHIVE server
264
+ optionalMemoryInMegabytesOrNull == null && optionalMemoryTotalSizeFactorOrNull == null ? oldArchiveMemoryInMB : optionalMemoryInMegabytesOrNull,
258 265
optionalMemoryTotalSizeFactorOrNull, optionalIgtimiRiotPort, region, release);
259 266
final String bearerTokenUsedByReplicas = getEffectiveBearerToken(replicaReplicationBearerToken);
260 267
final InboundReplicationConfiguration inboundMasterReplicationConfiguration = masterConfigurationBuilder.getInboundReplicationConfiguration().get();
... ...
@@ -277,6 +284,7 @@ public class LandscapeServiceImpl implements LandscapeService {
277 284
final StartSailingAnalyticsMasterHost<String> masterHostStartProcedure = masterHostBuilder.build();
278 285
masterHostStartProcedure.run();
279 286
final SailingAnalyticsProcess<String> master = masterHostStartProcedure.getSailingAnalyticsProcess();
287
+ master.getHost().setTerminationProtection(true);
280 288
final AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet =
281 289
landscape.getApplicationReplicaSet(region, replicaSetName, master, /* replicas */ Collections.emptySet(),
282 290
Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
... ...
@@ -358,6 +366,7 @@ public class LandscapeServiceImpl implements LandscapeService {
358 366
archiveAndFailoverIPs.getB(), new SailingAnalyticsHostSupplier<>());
359 367
logger.info("Terminating old failover host " + oldFailover.getInstanceId() + " with internal IP "
360 368
+ oldFailover.getPrivateAddress());
369
+ oldFailover.setTerminationProtection(false);
361 370
oldFailover.terminate();
362 371
logger.info("Removing reverse proxy rule for archive candidate with hostname "+ candidateHostname);
363 372
reverseProxyCluster.removeRedirect(candidateHostname, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/check.png
... ...
Binary files /dev/null and b/java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/check.png differ
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/IconResources.java
... ...
@@ -85,4 +85,7 @@ public interface IconResources extends ClientBundle {
85 85
86 86
@Source("images/command_symbol.png")
87 87
ImageResource commandSymbol();
88
+
89
+ @Source("images/check.png")
90
+ ImageResource check();
88 91
}
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsInstance.java
... ...
@@ -53,6 +53,8 @@ public interface AwsInstance<ShardingKey> extends Host {
53 53
default String getId() {
54 54
return getInstanceId();
55 55
}
56
+
57
+ void setTerminationProtection(boolean terminationProtection);
56 58
57 59
void terminate();
58 60
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/AwsLandscape.java
... ...
@@ -288,6 +288,8 @@ public interface AwsLandscape<ShardingKey> extends Landscape<ShardingKey> {
288 288
*/
289 289
SSHKeyPair importKeyPair(Region region, byte[] publicKey, byte[] encryptedPrivateKey, String keyName) throws JSchException;
290 290
291
+ void setTerminationProtection(AwsInstance<ShardingKey> host, boolean terminationProtection);
292
+
291 293
void terminate(AwsInstance<ShardingKey> host);
292 294
293 295
/**
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/ReverseProxy.java
... ...
@@ -133,5 +133,5 @@ public interface ReverseProxy<ShardingKey, MetricsT extends ApplicationProcessMe
133 133
*/
134 134
Pair<String, String> getArchiveAndFailoverIPs(Optional<String> optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception;
135 135
136
- void setArchiveAndFailoverIPs(String hostAddress, String b, Optional<String> ofNullable, byte[] privateKeyEncryptionPassphrase);
136
+ void setArchiveAndFailoverIPs(String hostAddress, String b, Optional<String> ofNullable, byte[] privateKeyEncryptionPassphrase) throws Exception;
137 137
}
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApacheReverseProxy.java
... ...
@@ -123,8 +123,9 @@ implements com.sap.sse.landscape.Process<RotatingFileBasedLog, MetricsT> {
123 123
124 124
@Override
125 125
public Pair<String, String> getArchiveAndFailoverIPs(Optional<String> optionalKeyName, byte[] privateKeyEncryptionPassphrase) throws Exception {
126
- final String command = "cat "+CONFIG_REPO_PATH+"/"+RELATIVE_CONFIG_PATH+"/"+CONFIG_FILE_FOR_ARCHIVE_AND_FAILOVER_DEFINITION+" | grep \"^Define "+ARCHIVE_IP+"\" | sed -e 's/^Define "+ARCHIVE_IP+" //'; "
127
- + "cat "+CONFIG_REPO_PATH+"/"+RELATIVE_CONFIG_PATH+"/"+CONFIG_FILE_FOR_ARCHIVE_AND_FAILOVER_DEFINITION+" | grep \"^Define "+ARCHIVE_FAILOVER_IP+"\" | sed -e 's/^Define "+ARCHIVE_FAILOVER_IP+" //'";
126
+ final String absolute000MacrosConfigFilePath = getAbsoluteConfigFilePath(CONFIG_FILE_FOR_ARCHIVE_AND_FAILOVER_DEFINITION);
127
+ final String command = "cat "+absolute000MacrosConfigFilePath+" | grep \"^Define "+ARCHIVE_IP+"\" | sed -e 's/^Define "+ARCHIVE_IP+" //'; "
128
+ + "cat "+absolute000MacrosConfigFilePath+" | grep \"^Define "+ARCHIVE_FAILOVER_IP+"\" | sed -e 's/^Define "+ARCHIVE_FAILOVER_IP+" //'";
128 129
final String[] archiveAndFailoverIPs = runCommandAndReturnStdoutAndLogStderr(command,
129 130
"Standard error from getting "+ARCHIVE_IP+" and "+ARCHIVE_FAILOVER_IP+": ",
130 131
Level.INFO, optionalKeyName, privateKeyEncryptionPassphrase).split("\n");
... ...
@@ -132,10 +133,17 @@ implements com.sap.sse.landscape.Process<RotatingFileBasedLog, MetricsT> {
132 133
}
133 134
134 135
@Override
135
- public void setArchiveAndFailoverIPs(String hostAddress, String b, Optional<String> ofNullable,
136
- byte[] privateKeyEncryptionPassphrase) {
137
- // TODO Auto-generated method stub
138
-
136
+ public void setArchiveAndFailoverIPs(String productionArchiveIP, String failoverArchiveIP, Optional<String> optionalKeyName,
137
+ byte[] privateKeyEncryptionPassphrase) throws Exception {
138
+ final String absolute000MacrosConfigFilePath = getAbsoluteConfigFilePath(CONFIG_FILE_FOR_ARCHIVE_AND_FAILOVER_DEFINITION);
139
+ final SshCommandChannel sshChannel = getHost().createRootSshChannel(TIMEOUT, optionalKeyName, privateKeyEncryptionPassphrase);
140
+ String patch000MacrosCommand = "su - " + CONFIG_USER + " -c 'cd " + CONFIG_REPO_PATH + " && git checkout "
141
+ + CONFIG_REPO_MAIN_BRANCH_NAME
142
+ + " && sed -i -e \"s/^Define "+ARCHIVE_IP+" .*$/Define "+ARCHIVE_IP+" "+productionArchiveIP+"/\" -e \"s/^Define "+ARCHIVE_FAILOVER_IP+" .*$/Define "+ARCHIVE_FAILOVER_IP+" "+failoverArchiveIP+"/\" "+absolute000MacrosConfigFilePath
143
+ + " && " + createCommitAndPushString(CONFIG_FILE_FOR_ARCHIVE_AND_FAILOVER_DEFINITION, "Switching to new ARCHIVE server", /* performPush */ true)
144
+ + "'"; // concludes the "su"; re-loading is expected to happen through the post-receive hook triggered by the push
145
+ final String stdout = sshChannel.runCommandAndReturnStdoutAndLogStderr(patch000MacrosCommand, "Standard error from switching to new ARCHIVE server", Level.WARNING);
146
+ logger.info("Stdout from upgrading to new ARCHIVE: "+stdout);
139 147
}
140 148
141 149
/**
... ...
@@ -165,7 +173,7 @@ implements com.sap.sse.landscape.Process<RotatingFileBasedLog, MetricsT> {
165 173
+ CONFIG_REPO_MAIN_BRANCH_NAME + " && echo \"Use " + macroName + " " + hostname + " "
166 174
+ String.join(" ", macroArguments) + "\" > " + getAbsoluteConfigFilePath(configFileNameForHostname);
167 175
if (doCommit) {
168
- command = command + " && cd "
176
+ command = command + " && cd "
169 177
+ CONFIG_REPO_PATH + " && " + createCommitAndPushString(configFileNameForHostname,
170 178
"Set " + configFileNameForHostname + " redirect", doPush);
171 179
}
... ...
@@ -199,10 +207,16 @@ implements com.sap.sse.landscape.Process<RotatingFileBasedLog, MetricsT> {
199 207
}
200 208
201 209
/**
202
- * Creates a command, that can be ran on an instance to commit, and optionally push, changes to a file (within a git repository). ASSUMES the command is ran from within the repository.
203
- * @param editedFileName The file name edited, created or deleted to commit. This includes the {@link #CONFIG_FILE_EXTENSION}, but not a path. The method appends the relative path.
204
- * @param commitMsg The commit message, without escaped speech marks.
205
- * @param performPush Boolean indicating whether to push changes or not. True for performing a push.
210
+ * Creates a command, that can be ran on an instance to commit, and optionally push, changes to a file (within a git
211
+ * repository). ASSUMES the command is ran from within the repository.
212
+ *
213
+ * @param editedFileName
214
+ * The file name edited, created or deleted to commit. This includes the {@link #CONFIG_FILE_EXTENSION},
215
+ * but not a path. The method appends the relative path.
216
+ * @param commitMsg
217
+ * The commit message, without escaped speech marks.
218
+ * @param performPush
219
+ * Boolean indicating whether to push changes or not. True for performing a push.
206 220
* @return Returns the created command (in String form) to perform a commit and optional push.
207 221
*/
208 222
private String createCommitAndPushString(String editedFileName, String commitMsg, boolean performPush) {
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/ApacheReverseProxyCluster.java
... ...
@@ -259,4 +259,13 @@ public class ApacheReverseProxyCluster<ShardingKey, MetricsT extends Application
259 259
byte[] privateKeyEncryptionPassphrase) throws Exception {
260 260
return getReverseProxies().iterator().next().getArchiveAndFailoverIPs(optionalKeyName, privateKeyEncryptionPassphrase);
261 261
}
262
+
263
+ @Override
264
+ public void setArchiveAndFailoverIPs(String hostAddress, String b, Optional<String> optionalKeyName,
265
+ byte[] privateKeyEncryptionPassphrase) throws Exception {
266
+ if (getReverseProxies().iterator().hasNext()) {
267
+ final ApacheReverseProxy<ShardingKey, MetricsT, ProcessT> proxy = getReverseProxies().iterator().next();
268
+ proxy.getArchiveAndFailoverIPs(optionalKeyName, privateKeyEncryptionPassphrase);
269
+ }
270
+ }
262 271
}
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsInstanceImpl.java
... ...
@@ -334,6 +334,11 @@ public class AwsInstanceImpl<ShardingKey> implements AwsInstance<ShardingKey> {
334 334
}
335 335
336 336
@Override
337
+ public void setTerminationProtection(boolean terminationProtection) {
338
+ landscape.setTerminationProtection(this, terminationProtection);
339
+ }
340
+
341
+ @Override
337 342
public void terminate() {
338 343
landscape.terminate(this);
339 344
}
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java
... ...
@@ -1069,6 +1069,12 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey>
1069 1069
}
1070 1070
1071 1071
@Override
1072
+ public void setTerminationProtection(AwsInstance<ShardingKey> host, boolean terminationProtection) {
1073
+ logger.info("Setting termination protection for instance "+host+" to "+terminationProtection);
1074
+ getEc2Client(getRegion(host.getAvailabilityZone().getRegion())).modifyInstanceAttribute(b->b.disableApiTermination(a->a.value(terminationProtection)));
1075
+ }
1076
+
1077
+ @Override
1072 1078
public void terminate(AwsInstance<ShardingKey> host) {
1073 1079
logger.info("Terminating instance "+host);
1074 1080
getEc2Client(getRegion(host.getAvailabilityZone().getRegion())).terminateInstances(