bug5730: preparing for sending mail to server owner about significant landscape events

This commit is contained in:
Axel Uhl
2023-02-28 13:16:15 +01:00
parent 6e0ed4335c
commit ac10c1db38
8 changed files with 67 additions and 7 deletions
@@ -3,5 +3,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="resources"/>
<classpathentry kind="output" path="bin"/>
</classpath>
@@ -1,2 +1,3 @@
eclipse.preferences.version=1
encoding//resources/stringmessages/SailingLandscape_StringMessages_de.properties=UTF-8
encoding/<project>=UTF-8
@@ -1,4 +1,5 @@
source.. = src/
source.. = src/,\
resources/
output.. = bin/
bin.includes = META-INF/,\
.
@@ -0,0 +1,4 @@
MasterUnavailableMailSubject=Primary server of replica set {0} temporarily unavailable
MasterUnavailableMailBody=The primary server of replica set {0} is temporarily unavailable.\nModifying access will be suspended.\nModifications incurred by a replica will be queued and will be applied when the primary is available again.
MasterAvailableMailSubject=Primary server of replica set {0} available again
MasterAvailableMailBody=The primary server of replica set {0} is available again.\nModifying access is possible again.\nQueued modifications will now process.
@@ -0,0 +1,4 @@
MasterUnavailableMailSubject=
MasterUnavailableMailBody=
MasterAvailableMailSubject=
MasterAvailableMailBody=
@@ -62,6 +62,8 @@ import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.mail.MailException;
import com.sap.sse.i18n.impl.ResourceBundleStringMessagesImpl;
import com.sap.sse.landscape.DefaultProcessConfigurationVariables;
import com.sap.sse.landscape.InboundReplicationConfiguration;
import com.sap.sse.landscape.Landscape;
@@ -101,9 +103,12 @@ import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.SessionUtils;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.OwnershipAnnotation;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.util.RemoteServerUtil;
import com.sap.sse.shared.util.Wait;
import com.sap.sse.util.JvmUtils;
@@ -121,6 +126,8 @@ import software.amazon.awssdk.services.sts.model.Credentials;
public class LandscapeServiceImpl implements LandscapeService {
private static final Logger logger = Logger.getLogger(LandscapeServiceImpl.class.getName());
private static final String STRING_MESSAGES_BASE_NAME = "stringmessages/SailingLandscape_StringMessages";
private static final String TEMPORARY_UPGRADE_REPLICA_NAME_SUFFIX = " (Upgrade Replica)";
@@ -746,6 +753,10 @@ public class LandscapeServiceImpl implements LandscapeService {
Integer optionalMemoryTotalSizeFactorOrNull, final AwsRegion region, final Release release) {
final AppConfigBuilderT masterConfigurationBuilder = SailingAnalyticsMasterConfiguration.masterBuilder();
final String bearerTokenUsedByMaster = getEffectiveBearerToken(optionalMasterReplicationBearerTokenOrNull);
final User currentUser = getSecurityService().getCurrentUser();
if (currentUser != null && currentUser.isEmailValidated() && currentUser.getEmail() != null) {
masterConfigurationBuilder.setCommaSeparatedEmailAddressesToNotifyOfStartup(currentUser.getEmail());
}
masterConfigurationBuilder
.setLandscape(getLandscape())
.setServerName(replicaSetName)
@@ -768,6 +779,10 @@ public class LandscapeServiceImpl implements LandscapeService {
String replicaSetName, final int masterPort, final Release release,
final String bearerTokenUsedByReplicas, final String masterHostname) {
final AppConfigBuilderT replicaConfigurationBuilder = SailingAnalyticsReplicaConfiguration.replicaBuilder();
final User currentUser = getSecurityService().getCurrentUser();
if (currentUser != null && currentUser.isEmailValidated() && currentUser.getEmail() != null) {
replicaConfigurationBuilder.setCommaSeparatedEmailAddressesToNotifyOfStartup(currentUser.getEmail());
}
// no specific memory configuration is made here; replicas are mostly launched on a dedicated host and hence can
// grab as much memory as they can get on that host
replicaConfigurationBuilder
@@ -1412,6 +1427,7 @@ public class LandscapeServiceImpl implements LandscapeService {
optionalPreferredInstanceToDeployTo).getInstanceToDeployTo(replicaSet);
}
logger.info("Stopping master "+replicaSet.getMaster());
sendMailAboutMasterUnavailable(replicaSet);
replicaSet.getMaster().stopAndTerminateIfLast(Landscape.WAIT_FOR_PROCESS_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
final AppConfigBuilderT masterConfigurationBuilder = createMasterConfigurationBuilder(replicaSet.getName(),
optionalMasterReplicationBearerTokenOrNull, optionalMemoryInMegabytesOrNull, optionalMemoryTotalSizeFactorOrNull,
@@ -1444,6 +1460,7 @@ public class LandscapeServiceImpl implements LandscapeService {
logger.info("Adding new master "+newMaster+" to target groups");
replicaSet.getPublicTargetGroup().addTarget(hostToDeployTo);
replicaSet.getMasterTargetGroup().addTarget(hostToDeployTo);
sendMailAboutMasterAvailable(replicaSet);
if (newTemporaryReplica != null) {
newTemporaryReplica.stopAndTerminateIfLast(Landscape.WAIT_FOR_HOST_TIMEOUT, Optional.ofNullable(optionalKeyName), privateKeyEncryptionPassphrase);
}
@@ -1451,6 +1468,38 @@ public class LandscapeServiceImpl implements LandscapeService {
return getLandscape().getApplicationReplicaSet(region, replicaSet.getServerName(), newMaster, replicaSet.getReplicas());
}
private void sendMailAboutMasterAvailable(
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet) throws MailException {
sendMailToReplicaSetOwner(replicaSet, "MasterUnavailableMailSubject", "MasterUnavailableMailBody");
}
private void sendMailAboutMasterUnavailable(
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet) throws MailException {
sendMailToReplicaSetOwner(replicaSet, "MasterAvailableMailSubject", "MasterAvailableMailBody");
}
/**
* @param subjectMessageKey must have a single placeholder argument representing the name of the replica set
* @param bodyMessageKey must have a single placeholder argument representing the name of the replica set
*/
private void sendMailToReplicaSetOwner(
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet,
final String subjectMessageKey, final String bodyMessageKey) throws MailException {
final OwnershipAnnotation serverOwnership = getSecurityService().getOwnership(getReplicaSetQualifiedObjectIdentifier(replicaSet));
final User serverOwner;
final ResourceBundleStringMessagesImpl stringMessages = new ResourceBundleStringMessagesImpl(STRING_MESSAGES_BASE_NAME, getClass().getClassLoader());
if (serverOwnership != null && serverOwnership.getAnnotation() != null && (serverOwner = serverOwnership.getAnnotation().getUserOwner()) != null) {
getSecurityService().sendMail(serverOwner.getName(),
stringMessages.get(serverOwner.getLocaleOrDefault(), subjectMessageKey, replicaSet.getServerName()),
stringMessages.get(serverOwner.getLocaleOrDefault(), bodyMessageKey, replicaSet.getServerName()));
}
}
private QualifiedObjectIdentifier getReplicaSetQualifiedObjectIdentifier(
AwsApplicationReplicaSet<String, SailingAnalyticsMetrics, SailingAnalyticsProcess<String>> replicaSet) {
return SecuredSecurityTypes.SERVER.getQualifiedObjectIdentifier(new TypeRelativeObjectIdentifier(replicaSet.getServerName()));
}
/**
* If a non-{@code null}, non-{@link String#isEmpty() empty} bearer token is provided by the
* {@code optionalBearerTokenOnNull} parameter, it is returned unchanged; otherwise, the bearer token as obtained
@@ -440,7 +440,7 @@ implements ReplicableSecurityService, ClearStateTestSupport {
@Override
public void sendMail(String username, String subject, String body) throws MailException {
final User user = getUserByName(username);
if (user != null) {
if (user != null && user.isEmailValidated()) {
final String toAddress = user.getEmail();
if (toAddress != null) {
MailService mailService = getMailService();
@@ -26,15 +26,15 @@ import com.sap.sse.i18n.impl.NullResourceBundleStringMessages;
* </pre>
*/
public interface ResourceBundleStringMessages {
public static final ResourceBundleStringMessages NULL = new NullResourceBundleStringMessages();
static final ResourceBundleStringMessages NULL = new NullResourceBundleStringMessages();
public String getResourceBaseName();
String getResourceBaseName();
public String get(Locale locale, String messageKey);
String get(Locale locale, String messageKey);
public String get(Locale locale, String messageKey, String... parameters);
String get(Locale locale, String messageKey, String... parameters);
public static final class Util {
static final class Util {
private static final Locale FALLBACK_LOCALE = Locale.ROOT;
public static Control createControl(String encoding) {