41ac671475ac392f06238b48f3009e5b0f674478
Home.md
| ... | ... | @@ -59,6 +59,7 @@ SAP is at the center of today’s technology revolution, developing innovations |
| 59 | 59 | * Amazon |
| 60 | 60 | * [[Amazon EC2|wiki/info/landscape/amazon-ec2]] |
| 61 | 61 | * [[Upgrading ARCHIVE server|wiki/info/landscape/archive-server-upgrade]] |
| 62 | + * [[Upgrading MongoDB Nodes|wiki/info/landscape/mongo-cluster-upgrade]] |
|
| 62 | 63 | * [[EC2 Backup Strategy|wiki/info/landscape/amazon-ec2-backup-strategy]] |
| 63 | 64 | * [[Creating an EC2 image from scratch|wiki/info/landscape/creating-ec2-image-from-scratch]] |
| 64 | 65 | * [[Upgrading an EC2 image|wiki/info/landscape/upgrading-ec2-image]] |
java/com.sap.sailing.grib/src/com/sap/sailing/grib/impl/GribWindFieldFactoryImpl.java
| ... | ... | @@ -19,6 +19,7 @@ import java.util.logging.Logger; |
| 19 | 19 | |
| 20 | 20 | import com.sap.sailing.grib.GribWindField; |
| 21 | 21 | import com.sap.sailing.grib.GribWindFieldFactory; |
| 22 | +import com.sap.sse.common.Util; |
|
| 22 | 23 | import com.sap.sse.common.util.MappingIterable; |
| 23 | 24 | import com.sap.sse.util.LoggerAppender; |
| 24 | 25 | |
| ... | ... | @@ -188,6 +189,9 @@ public class GribWindFieldFactoryImpl implements GribWindFieldFactory { |
| 188 | 189 | * are no longer needed. |
| 189 | 190 | */ |
| 190 | 191 | private File copyStreamToFile(InputStream s, String filename) throws IOException { |
| 192 | + if (Util.hasLength(filename) && (filename.contains("..") || filename.contains("/") || filename.contains("\\"))) { |
|
| 193 | + throw new IllegalArgumentException("File extension must not contain '..' or a file separator like '/'."); |
|
| 194 | + } |
|
| 191 | 195 | Path tempDir = Files.createTempDirectory("gribcache"); |
| 192 | 196 | Path filePath = tempDir.resolve(filename); |
| 193 | 197 | Files.copy(s, filePath); |
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementPanel.java
| ... | ... | @@ -1618,7 +1618,7 @@ public class LandscapeManagementPanel extends SimplePanel { |
| 1618 | 1618 | new AsyncCallback<Void>() { |
| 1619 | 1619 | @Override |
| 1620 | 1620 | public void onSuccess(Void result) { |
| 1621 | - Notification.notify(stringMessages.unlockedSuccessfully(), NotificationType.SUCCESS); |
|
| 1621 | + Notification.notify(stringMessages.success(), NotificationType.SUCCESS); |
|
| 1622 | 1622 | proxiesTableBusy.setBusy(false); |
| 1623 | 1623 | refreshProxiesTable(); |
| 1624 | 1624 | } |
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java
| ... | ... | @@ -173,7 +173,7 @@ com.sap.sse.gwt.adminconsole.StringMessages { |
| 173 | 173 | String successfullyRotatedHttpdLogsOnInstance(String instance); |
| 174 | 174 | String invalidOperationForThisProxy(); |
| 175 | 175 | String pleaseProvideNonEmptyNameAndAZ(); |
| 176 | - String unlockedSuccessfully(); |
|
| 176 | + String success(); |
|
| 177 | 177 | String availabilityZone(); |
| 178 | 178 | String runOnExisting(); |
| 179 | 179 | String publicIp(); |
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.properties
| ... | ... | @@ -162,7 +162,7 @@ rotateHttpdLogs=Rotate httpd logs |
| 162 | 162 | successfullyRotatedHttpdLogsOnInstance=Successfully rotated the Apache Httpd logs on instance: {0} |
| 163 | 163 | invalidOperationForThisProxy=You can''t perform this operation on this instance |
| 164 | 164 | pleaseProvideNonEmptyNameAndAZ=Please provide a non-empty name (UTF-8) and an AZ. |
| 165 | -success=success |
|
| 165 | +success=Success |
|
| 166 | 166 | availabilityZone=Availability Zone |
| 167 | 167 | runOnExisting=Run on an existing, running instance |
| 168 | 168 | publicIp=Public IP address |
java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/LocalFileStorageServiceImpl.java
| ... | ... | @@ -17,6 +17,7 @@ import org.apache.shiro.authz.UnauthorizedException; |
| 17 | 17 | import org.osgi.framework.BundleContext; |
| 18 | 18 | |
| 19 | 19 | import com.sap.sailing.domain.common.security.SecuredDomainType; |
| 20 | +import com.sap.sse.common.Util; |
|
| 20 | 21 | import com.sap.sse.common.Util.Pair; |
| 21 | 22 | import com.sap.sse.filestorage.FileStorageService; |
| 22 | 23 | import com.sap.sse.filestorage.FileStorageServiceProperty; |
| ... | ... | @@ -41,8 +42,6 @@ import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; |
| 41 | 42 | * @author Jan Broß |
| 42 | 43 | * |
| 43 | 44 | */ |
| 44 | - |
|
| 45 | - |
|
| 46 | 45 | public class LocalFileStorageServiceImpl extends BaseFileStorageServiceImpl implements FileStorageService { |
| 47 | 46 | private static final long serialVersionUID = -8661781258137340835L; |
| 48 | 47 | private static final String testFile = "Bundesliga2014_Regatta6_eventteaser.jpg"; |
| ... | ... | @@ -62,6 +61,9 @@ public class LocalFileStorageServiceImpl extends BaseFileStorageServiceImpl impl |
| 62 | 61 | @Override |
| 63 | 62 | public URI storeFile(InputStream is, String fileExtension, long lengthInBytes) |
| 64 | 63 | throws IOException, UnauthorizedException { |
| 64 | + if (Util.hasLength(fileExtension) && (fileExtension.contains("..") || fileExtension.contains("/") || fileExtension.contains("\\"))) { |
|
| 65 | + throw new IllegalArgumentException("File extension must not contain '..' or a file separator like '/'."); |
|
| 66 | + } |
|
| 65 | 67 | String fileName = getKey(fileExtension); |
| 66 | 68 | String pathToFile = localPath.getValue() + "/" + fileName; |
| 67 | 69 | return getSecurityService().setOwnershipCheckPermissionForObjectCreationAndRevertOnError(SecuredDomainType.FILE_STORAGE, |
java/com.sap.sse.landscape.aws/src/com/sap/sse/landscape/aws/impl/AwsLandscapeImpl.java
| ... | ... | @@ -1029,7 +1029,6 @@ public class AwsLandscapeImpl<ShardingKey> implements AwsLandscape<ShardingKey> |
| 1029 | 1029 | } |
| 1030 | 1030 | final Ec2Client ec2Client = getEc2Client(getRegion(az.getRegion())); |
| 1031 | 1031 | final Builder runInstancesRequestBuilder = RunInstancesRequest.builder() |
| 1032 | - .additionalInfo("Test " + getClass().getName()) |
|
| 1033 | 1032 | .imageId(fromImage.getId().toString()) |
| 1034 | 1033 | .minCount(numberOfHostsToLaunch) |
| 1035 | 1034 | .maxCount(numberOfHostsToLaunch) |
java/com.sap.sse.test/src/com/sap/sse/test/RegexTest.java
| ... | ... | @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; |
| 5 | 5 | import static org.junit.jupiter.api.Assertions.assertNull; |
| 6 | 6 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| 7 | 7 | |
| 8 | +import java.util.Arrays; |
|
| 8 | 9 | import java.util.logging.Logger; |
| 9 | 10 | import java.util.regex.Matcher; |
| 10 | 11 | import java.util.regex.Pattern; |
| ... | ... | @@ -94,4 +95,11 @@ public class RegexTest { |
| 94 | 95 | final Matcher m1 = nationalityPattern.matcher(sb.toString()); |
| 95 | 96 | assertFalse(m1.matches()); |
| 96 | 97 | } |
| 98 | + |
|
| 99 | + @Test |
|
| 100 | + public void testExpeditionHeaderSplitting() { |
|
| 101 | + final String line = "a , b ,, c"; |
|
| 102 | + final String[] splitResult = line.split("\\s*,\\s*"); |
|
| 103 | + assertEquals(Arrays.asList("a", "b", "", "c"), Arrays.asList(splitResult)); |
|
| 104 | + } |
|
| 97 | 105 | } |
wiki/info/landscape/mongo-cluster-upgrade.md
| ... | ... | @@ -0,0 +1,91 @@ |
| 1 | +# MongoDB Cluster Upgrades |
|
| 2 | + |
|
| 3 | +In our production environment on AWS, we currently (2026-02-10) run three MongoDB replica sets: |
|
| 4 | + |
|
| 5 | +- ``live``: holds all databases for live operations and consists of three nodes: two i3.large instances with fast NVMe storage used for the ``/var/lib/mongo`` partition, and a hidden instance with an EBS volume that is backed up on a daily basis |
|
| 6 | +- ``archive``: holds the ``winddb`` database used for the ARCHIVE server |
|
| 7 | +- ``slow``: used for backing up databases when removing them from the ``live`` replica set, e.g., when shutting down an application replica set after an event |
|
| 8 | + |
|
| 9 | +The ``archive`` and ``slow`` replica sets usually have only a single instance running on ``dbserver.internal.sapsailing.com``, and this is also where the hidden replica of the ``live`` replica set runs. The other two ``live`` nodes have internal DNS names set for them: ``mongo[01].internal.sapsailing.com``. |
|
| 10 | + |
|
| 11 | +Upgrades may affect the packages installed on the nodes, or may affect the major version of MongoDB being run. Both upgrade procedures are described in the following two sections. |
|
| 12 | + |
|
| 13 | +## Upgrade Using Package Manager |
|
| 14 | + |
|
| 15 | +With Amazon Linux 2023, ``dnf`` is the package manager used. When logging on to an instance, a message like |
|
| 16 | + |
|
| 17 | +``` |
|
| 18 | +A newer release of "Amazon Linux" is available. |
|
| 19 | + Version 2023.10.20260202: |
|
| 20 | +Run "/usr/bin/dnf check-release-update" for full release and version update info |
|
| 21 | +``` |
|
| 22 | + |
|
| 23 | +may be shown. In this case, run |
|
| 24 | + |
|
| 25 | +``` |
|
| 26 | +dnf --releasever=latest upgrade |
|
| 27 | +``` |
|
| 28 | + |
|
| 29 | +and watch closely what the package manager suggests. As soon as you see a kernel update about to install, displayed in red color (if your terminal supports colored output), a reboot will be required after completing the installation. This can also be checked using the following command: |
|
| 30 | + |
|
| 31 | +``` |
|
| 32 | +needs-restarting -r |
|
| 33 | +``` |
|
| 34 | + |
|
| 35 | +It will output a message like |
|
| 36 | + |
|
| 37 | +``` |
|
| 38 | +No core libraries or services have been updated since boot-up. |
|
| 39 | +Reboot should not be necessary. |
|
| 40 | +``` |
|
| 41 | + |
|
| 42 | +and exits with code ``0`` if no reboot is required; otherwise, it will exit with ``1`` and display a corresponding message. |
|
| 43 | + |
|
| 44 | +To avoid interrupting user-facing services, rebooting the MongoDB nodes shall follow a certain procedure: |
|
| 45 | + |
|
| 46 | +- Ensure that no ARCHIVE candidate is currently launching; such a candidate would read from the ``archive`` replica set, so that rebooting the ``dbserver.internal.sapsailing.com`` node would interrupt this loading process. If an ARCHIVE candidate is launching, wait for the launch to finish. |
|
| 47 | +- Ensure that no application replica set is currently being shut down with backing up its database. This backup would fail if the ``dbserver.internal.sapsailing.com`` node were restarted as it hosts the ``slow`` replica set used for the backup. |
|
| 48 | +- ssh into ``ec2-user@dbserver.internal.sapsailing.com`` |
|
| 49 | +- There, run ``sudo dnf --releasever=latest upgrade`` and confirm with "yes" |
|
| 50 | +- Assuming an update was installed that now requires a reboot, run ``sudo reboot`` |
|
| 51 | +- Wait until the instance is back up and running, you can ssh into it again, and ``pgrep mongod`` shows the three process IDs of the three running ``mongod`` processes |
|
| 52 | +- ssh into ``ec2-user@mongo0.internal.sapsailing.com`` |
|
| 53 | +- run ``mongosh`` to see if ``mongo0`` is currently primary or secondary in the ``live`` replica set |
|
| 54 | +- if you see "secondary", you're all set; if you see "primary", enter ``rs.stepDown()`` and see how the prompt changes from "primary" to "secondary" |
|
| 55 | +- use ``quit()`` to exit the ``mongosh`` shell |
|
| 56 | +- run ``sudo dnf --releasever=latest upgrade`` and confirm with "yes" |
|
| 57 | +- if a reboot is required, run ``sudo reboot`` |
|
| 58 | +- wait for the instance and its ``mongod`` process to become available again; you may probe, e.g., by ssh-ing into the instance and checking with ``mongosh`` |
|
| 59 | +- repeat the process described for ``mongo0`` for ``mongo1.internal.sapsailing.com`` |
|
| 60 | + |
|
| 61 | +Hint: You can choose the order between ``mongo0`` and ``mongo1`` as you wish. If you start with the "secondary" instance, you will save one ``rs.stepDown()`` command. |
|
| 62 | + |
|
| 63 | +## MongoDB Major Version Upgrade |
|
| 64 | + |
|
| 65 | +Upgrading a MongoDB replica set that has more than one node can work without client noticing any interruption of service. This is in particular important for our ``live`` replica set used by all running application replica sets other than ``ARCHIVE``. For the single-node replica sets ``archive`` and ``slow`` it again comes down to timing an upgrade such that no ``ARCHIVE`` candidate launch is ongoing, and that no application replica set is currently being shut down with its database getting backed up to the ``slow`` replica set. |
|
| 66 | + |
|
| 67 | +The [MongoDB online documentation](https://www.mongodb.com/docs/manual/release-notes/8.0-upgrade-replica-set/#std-label-8.0-upgrade-replica-set) contains a useful description of the steps necessary. The key to understanding those steps is that MongoDB replica sets can distinguish between the actual version of ``mongod`` that is running, and the "protocol version" the nodes use to talk to each other in a replica set. Newer ``mongod`` versions can always still work with the "protocol version" of the previous major release. For example, ``mongod`` in version 8 can still work with protocol version "7.0". |
|
| 68 | + |
|
| 69 | +Therefore, upgrading a replica set with multiple nodes will work along these steps: |
|
| 70 | + |
|
| 71 | +- Ensure all ``mongod`` processes in the replica set run the same (old) version |
|
| 72 | +- Ensure all ``mongod`` processes use the protocol version that matches their own ``mongod`` version |
|
| 73 | +- Upgrade the binaries and restart the ``mongod`` processes with the new version for all nodes, properly having the primary step down before restarting its process |
|
| 74 | +- Set the new protocol version for the replica set |
|
| 75 | + |
|
| 76 | +The sequence in which to work with the different nodes and processes resembles that for reboots after upgrades with the package manager. Here are the steps in detail: |
|
| 77 | + |
|
| 78 | +- Ensure that no ARCHIVE candidate is currently launching; such a candidate would read from the ``archive`` replica set, so that rebooting the ``dbserver.internal.sapsailing.com`` node would interrupt this loading process. If an ARCHIVE candidate is launching, wait for the launch to finish. |
|
| 79 | +- Ensure that no application replica set is currently being shut down with backing up its database. This backup would fail if the ``dbserver.internal.sapsailing.com`` node were restarted as it hosts the ``slow`` replica set used for the backup. |
|
| 80 | +- ssh into ``ec2-user@dbserver.internal.sapsailing.com`` |
|
| 81 | +- Ensure all ``mongod`` processes on the host run the same (old) version, using ``mongosh`` for all three replica sets (``live``, ``archive``, ``slow``) |
|
| 82 | +- In ``mongosh``, display the protocol version using ``db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )``. Should you find a deviation, set the protocol version using ``db.adminCommand( { setFeatureCompatibilityVersion: "7.0" , confirm: true } )`` (of course with the "7.0" replaced by whichever protocol version you have to set this to). |
|
| 83 | +- In ``/etc/yum.repos.d/`` find the ``mongodb-org.{major.minor}.repo`` file that controls where the MongoDB packages are currently obtained from. Rename the current ``mongodb-org.{major.minor}.repo`` by appending, e.g., ``.bak`` to its name and create a new ``.repo`` file for the MongoDB version you'd like to upgrade to. Then run ``dnf --releasever=latest upgrade``. This should automatically restart the ``mongod`` processes now upgraded to the new release. |
|
| 84 | +- ssh into ``ec2-user@mongo0.internal.sapsailing.com`` |
|
| 85 | +- check ``mongod`` and protocol version using ``mongosh``; adjust protocol version if necessary (see above) |
|
| 86 | +- if on the "primary", use ``rs.stepDown()`` to make it a "secondary" |
|
| 87 | +- run the binaries upgrade as explained for ``dbserver.internal.sapsailing.com`` above, adjusting the ``.repo`` file under ``/etc/yum.repos.d``, followed by ``dnf --releasever=latest upgrade`` |
|
| 88 | +- repeat the last four steps for ``mongo1.internal.sapsailing.com`` |
|
| 89 | +- use ``mongosh`` to connect to the primaries of all three replica sets (``live``, ``archive``, ``slow``) and on each one issue the command ``db.adminCommand( { setFeatureCompatibilityVersion: "8.0", confirm: true }`` with the "8.0" replaced by the protocol version you want to upgrade to, so usually the major/minor version of the binaries to which you have upgraded. |
|
| 90 | + |
|
| 91 | +Done :-) |
|
| ... | ... | \ No newline at end of file |