Enable redis/sentinel port and sentinel master name configuration 46/7946/2 1.6.0
authorPetri Ovaska <petri.ovaska@nokia.com>
Thu, 10 Mar 2022 07:59:23 +0000 (09:59 +0200)
committerPetri Ovaska <petri.ovaska@nokia.com>
Mon, 14 Mar 2022 12:02:42 +0000 (14:02 +0200)
This change enables configuration of DBAAS_MASTER_NAME,
DBAAS_SERVICE_PORT and DBAAS_SERVICE_SENTINEL_PORT value
configuration for different clusters. Environment variable values
are comma separated lists.

For example if the DBAAS_CLUSTER_ADDR_LIST environment variable has
three cluster addresses then it ispossible to configure each
cluster different values like:

 DBAAS_MASTER_NAME='dbaasmaster-0,dbaasmaster-1,dbaasmaster-2'
 DBAAS_SERVICE_PORT='6379,6380,6381'
 DBAAS_SERVICE_SENTINEL_PORT='26379,26380,26381'

Notice: RIC platform deployments above list type of environment
variables will have a single value (only one Database (DB) service
is supported).

SDL version 1.6.0

Issue-Id: RIC-698

Change-Id: Ib07243da0fd973623dfeb09b82c000d19be11a7d
Signed-off-by: Petri Ovaska <petri.ovaska@nokia.com>
13 files changed:
configure.ac
debian/changelog.in
docs/release-notes.rst
docs/user-guide.rst
include/private/databaseconfiguration.hpp
include/private/databaseconfigurationimpl.hpp
include/private/tst/databaseconfigurationmock.hpp
rpm/sdl.spec.in
src/configurationreader.cpp
src/databaseconfigurationimpl.cpp
src/redis/asyncdatabasediscovery.cpp
tst/configurationreader_test.cpp
tst/databaseconfigurationimpl_test.cpp

index ab652d4..ed19555 100644 (file)
@@ -10,8 +10,8 @@
 # Change the numbers just before release.
 
 m4_define([SDL_MAJOR], [1])
-m4_define([SDL_MINOR], [5])
-m4_define([SDL_MICRO], [1])
+m4_define([SDL_MINOR], [6])
+m4_define([SDL_MICRO], [0])
 
 # SDL ABI version with libtool
 #
@@ -28,7 +28,7 @@ m4_define([SDL_MICRO], [1])
 # Change the numbers just before release.
 
 m4_define([SDL_CURRENT], [5])
-m4_define([SDL_REVISION], [13])
+m4_define([SDL_REVISION], [14])
 m4_define([SDL_AGE], [0])
 
 AC_INIT([shareddatalayer], [SDL_MAJOR.SDL_MINOR.SDL_MICRO], [], [], [https://gerrit.o-ran-sc.org/r/admin/repos/ric-plt/sdl])
index b29304a..ab5177e 100644 (file)
@@ -1,3 +1,9 @@
+sdl (1.6.0-1) UNRELEASED; urgency=low
+
+  * Enable redis/sentinel port and sentinel master name configuration
+
+ -- Petri Ovaska <petri.ovaska@nokia.com>  Thu, 10 Mar 2022 09:59:23 +0300
+
 sdl (1.5.1-1) UNRELEASED; urgency=low
 
   * Add set, get and listKeys -sdltool CLI commands
index c4913ac..5ac92c0 100644 (file)
@@ -1,5 +1,5 @@
 ..
-..  Copyright (c) 2019 Nokia.
+..  Copyright (c) 2019-2022 Nokia.
 ..
 ..  Licensed under the Creative Commons Attribution 4.0 International
 ..  Public License (the "License"); you may not use this file except
@@ -29,6 +29,10 @@ This document provides the release notes of the sdl library.
 Version history
 ---------------
 
+[1.6.0] - 2022-03-10
+
+* Enable redis/sentinel port and sentinel master name configuration
+
 [1.5.1] - 2021-09-17
 
 * Add set, get and listKeys -sdltool CLI commands
index 57e8bc0..a1a2246 100644 (file)
@@ -1,6 +1,6 @@
 ..
 ..  Copyright (c) 2019 AT&T Intellectual Property.
-..  Copyright (c) 2019 Nokia.
+..  Copyright (c) 2019-2022 Nokia.
 ..
 ..  Licensed under the Creative Commons Attribution 4.0 International
 ..  Public License (the "License"); you may not use this file except
@@ -239,12 +239,25 @@ configure database backend:
 * DBAAS_SERVICE_SENTINEL_PORT
 * DBAAS_MASTER_NAME
 * DBAAS_NODE_COUNT
+* DBAAS_CLUSTER_ADDR_LIST
 
 After DBaaS service is installed, environment variables are exposed to
 application containers. SDL library will automatically use these environment
 variables. If DBaaS service is not used, above environment variables needs to
 be set manually so that SDL backend can connect to correct database.
 
+When multiple Database (DB) service is used Nokia SEP deployments can have
+comma separated list of DB ports, sentinel master group names and DB service
+addresses:
+
+ DBAAS_CLUSTER_ADDR_LIST=<comma separated list of DB services>
+ DBAAS_MASTER_NAME=<comma separated list of DB sentinel master names>
+ DBAAS_SERVICE_PORT=<comma separated list of DB service ports>
+ DBAAS_SERVICE_SENTINEL_PORT=<comma separated list of Redis Sentinel ports>
+
+In RIC platform deployments above list type of environment variables will have
+a single value, because only one Database (DB) service is supported in RIC.
+
 **Examples**
 
 An example how environment variables can be set in bash shell, when standalone
@@ -265,6 +278,16 @@ HA deployment is used::
    export DBAAS_SERVICE_SENTINEL_PORT=23550
    export DBAAS_NODE_COUNT=3
 
+An example how environment variables can be set in bash shell, when Redis
+HA deployment with two DB service is used::
+
+   export DBAAS_CLUSTER_ADDR_LIST=dbaas-0,dbaas-1
+   export DBAAS_MASTER_NAME=my-dbaasmaster-0,my-dbaasmaster-1
+   export DBAAS_SERVICE_HOST=dbaas-0
+   export DBAAS_SERVICE_PORT=6379,6380
+   export DBAAS_SERVICE_SENTINEL_PORT=26379,26380
+   export DBAAS_NODE_COUNT=3
+
 .. raw:: pdf
 
    PageBreak
index e8e5b8d..b43aeee 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -34,6 +34,8 @@ namespace shareddatalayer
     public:
         class InvalidDbType;
         using Addresses = std::vector<HostAndPort>;
+        using SentinelPorts = std::vector<uint16_t>;
+        using SentinelMasterNames = std::vector<std::string>;
         enum class DbType
         {
             UNKNOWN = 0,
@@ -47,15 +49,14 @@ namespace shareddatalayer
         virtual ~DatabaseConfiguration() = default;
         virtual void checkAndApplyDbType(const std::string& type) = 0;
         virtual void checkAndApplyServerAddress(const std::string& address) = 0;
-        virtual void checkAndApplySentinelAddress(const std::string& address) = 0;
-        virtual void checkAndApplySentinelMasterName(const std::string& name) = 0;
+        virtual void checkAndApplySentinelPorts(const std::string& sentinelPortsEnvStr) = 0;
+        virtual void checkAndApplySentinelMasterNames(const std::string& sentinelMasterNamesEnvStr) = 0;
         virtual DatabaseConfiguration::DbType getDbType() const = 0;
         virtual DatabaseConfiguration::Addresses getServerAddresses() const = 0;
         virtual DatabaseConfiguration::Addresses getServerAddresses(const boost::optional<std::size_t>& addressIndex) const = 0;
         virtual DatabaseConfiguration::Addresses getDefaultServerAddresses() const = 0;
-        virtual boost::optional<HostAndPort> getSentinelAddress() const = 0; // Optional return value, because empty HostAndPort can't be created.
         virtual boost::optional<HostAndPort> getSentinelAddress(const boost::optional<std::size_t>& addressIndex) const = 0;
-        virtual std::string getSentinelMasterName() const = 0;
+        virtual std::string getSentinelMasterName(const boost::optional<std::size_t>& addressIndex) const = 0;
         virtual bool isEmpty() const = 0;
 
         DatabaseConfiguration(DatabaseConfiguration&&) = delete;
index 955b292..4044758 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -37,9 +37,9 @@ namespace shareddatalayer
 
         void checkAndApplyServerAddress(const std::string& address) override;
 
-        void checkAndApplySentinelAddress(const std::string& address) override;
+        void checkAndApplySentinelPorts(const std::string& sentinelPortsEnvStr) override;
 
-        void checkAndApplySentinelMasterName(const std::string& name) override;
+        void checkAndApplySentinelMasterNames(const std::string& sentinelMasterNamesEnvStr) override;
 
         DatabaseConfiguration::DbType getDbType() const override;
 
@@ -49,19 +49,17 @@ namespace shareddatalayer
 
         DatabaseConfiguration::Addresses getDefaultServerAddresses() const override;
 
-        boost::optional<HostAndPort> getSentinelAddress() const override;
-
         boost::optional<HostAndPort> getSentinelAddress(const boost::optional<std::size_t>& addressIndex) const override;
 
-        std::string getSentinelMasterName() const override;
+        std::string getSentinelMasterName(const boost::optional<std::size_t>& addressIndex) const override;
 
         bool isEmpty() const override;
 
     private:
         DbType dbType;
         Addresses serverAddresses;
-        boost::optional<HostAndPort> sentinelAddress;
-        std::string sentinelMasterName;
+        SentinelPorts sentinelPorts;
+        SentinelMasterNames sentinelMasterNames;
     };
 }
 
index 8f8d30e..eb3084a 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -33,16 +33,15 @@ namespace shareddatalayer
         public:
             MOCK_METHOD1(checkAndApplyDbType, void(const std::string& type));
             MOCK_METHOD1(checkAndApplyServerAddress, void(const std::string& address));
-            MOCK_METHOD1(checkAndApplySentinelAddress, void(const std::string& address));
-            MOCK_METHOD1(checkAndApplySentinelMasterName, void(const std::string& name));
+            MOCK_METHOD1(checkAndApplySentinelPorts, void(const std::string& sentinelPortsEnvStr));
+            MOCK_METHOD1(checkAndApplySentinelMasterNames, void(const std::string& sentinelMasterNamesEnvStr));
             MOCK_CONST_METHOD0(getDbType, DatabaseConfiguration::DbType());
             MOCK_CONST_METHOD0(getServerAddresses, DatabaseConfiguration::Addresses());
             MOCK_CONST_METHOD1(getServerAddresses, DatabaseConfiguration::Addresses(const boost::optional<std::size_t>& addressIndex));
             MOCK_CONST_METHOD0(getDefaultServerAddresses, DatabaseConfiguration::Addresses());
             MOCK_CONST_METHOD0(isEmpty, bool());
-            MOCK_CONST_METHOD0(getSentinelAddress, boost::optional<HostAndPort>());
             MOCK_CONST_METHOD1(getSentinelAddress, boost::optional<HostAndPort>(const boost::optional<std::size_t>& addressIndex));
-            MOCK_CONST_METHOD0(getSentinelMasterName, std::string());
+            MOCK_CONST_METHOD1(getSentinelMasterName, std::string(const boost::optional<std::size_t>& addressIndex));
         };
     }
 }
index 4d5da0d..753e0e2 100755 (executable)
@@ -1,5 +1,5 @@
 Name:     sdl
-Version:  1.5.1
+Version:  1.6.0
 Release:  1%{?dist}
 Summary:  C++ API library for Shared Data Layer clients
 
@@ -50,6 +50,9 @@ rm -f %{buildroot}%{_libdir}/lib*.*a
 %{_includedir}/sdl
 
 %changelog
+* Thu Mar 10 2022 Petri Ovaska <petri.ovaska@nokia.com> - 1.6.0-1
+- Enable redis/sentinel port and sentinel master name configuration
+
 * Fri Sep 17 2021 Petri Ovaska <petri.ovaska@nokia.com> - 1.5.1-1
 - Add set, get and listKeys -sdltool CLI commands
 
index 1870a87..2cd707b 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
 #include "private/namespaceconfigurations.hpp"
 #include "private/namespacevalidator.hpp"
 #include "private/system.hpp"
+#include <boost/algorithm/string.hpp>
 
 using namespace shareddatalayer;
 
@@ -196,17 +197,25 @@ namespace
             parseNsConfiguration(namespaceConfigurations, namespaceConfigurationMapItem.first, namespaceConfigurationMapItem.second.first, namespaceConfigurationMapItem.second.second);
     }
 
+    const std::string DEFAULT_REDIS_PORT("6379");
+
     void appendDBPortToAddrList(std::string& addresses, const std::string& port)
     {
         size_t base(0);
+        std::vector<std::string> portList;
+        boost::split(portList, port, boost::is_any_of(","));
+
+        std::size_t idx(0);
+        auto redisPort((portList.size() > 0 && idx < portList.size()) ? portList.at(idx) : DEFAULT_REDIS_PORT);
         auto pos = addresses.find(',', base);
         while (std::string::npos != pos)
         {
-            addresses.insert(pos, ":" + port);
-            base = pos + 2 + port.size();
+            addresses.insert(pos, ":" + redisPort);
+            base = pos + 2 + redisPort.size();
             pos = addresses.find(',', base);
+            idx++;
         }
-        addresses.append(":" + port);
+        addresses.append(":" + redisPort);
     }
 }
 
@@ -357,8 +366,8 @@ void ConfigurationReader::readDatabaseConfiguration(DatabaseConfiguration& datab
             if (DatabaseConfiguration::DbType::REDIS_SENTINEL == dbType ||
                 DatabaseConfiguration::DbType::SDL_SENTINEL_CLUSTER == dbType)
             {
-                databaseConfiguration.checkAndApplySentinelAddress(dbHostEnvVariableValue + ":" + sentinelPortEnvVariableValue);
-                databaseConfiguration.checkAndApplySentinelMasterName(sentinelMasterNameEnvVariableValue);
+                databaseConfiguration.checkAndApplySentinelPorts(sentinelPortEnvVariableValue);
+                databaseConfiguration.checkAndApplySentinelMasterNames(sentinelMasterNameEnvVariableValue);
             }
         }
         else
index 4ee548f..ac691ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -22,6 +22,8 @@
 #include "private/databaseconfigurationimpl.hpp"
 #include <arpa/inet.h>
 #include <boost/crc.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/algorithm/string.hpp>
 
 using namespace shareddatalayer;
 
@@ -35,6 +37,7 @@ namespace
 
     const uint16_t DEFAULT_PORT(6379U);
     const uint16_t DEFAULT_SENTINEL_PORT(26379U);
+    const std::string DEFAULT_SENTINEL_MASTER_GROUP_NAME("dbaasmaster");
 }
 
 DatabaseConfigurationImpl::DatabaseConfigurationImpl():
@@ -95,30 +98,40 @@ DatabaseConfiguration::Addresses DatabaseConfigurationImpl::getDefaultServerAddr
     return { HostAndPort(getDefaultHost(), htons(DEFAULT_PORT)) };
 }
 
-void DatabaseConfigurationImpl::checkAndApplySentinelAddress(const std::string& address)
+void DatabaseConfigurationImpl::checkAndApplySentinelPorts(const std::string& portsEnvStr)
 {
-    sentinelAddress = HostAndPort(address, htons(DEFAULT_SENTINEL_PORT));
-}
+    std::vector<std::string> ports;
+    boost::split(ports, portsEnvStr, boost::is_any_of(","));
 
-boost::optional<HostAndPort> DatabaseConfigurationImpl::getSentinelAddress() const
-{
-    return sentinelAddress;
+    for (auto port : ports)
+    {
+        try {
+            sentinelPorts.push_back(htons(boost::lexical_cast<uint16_t>(port)));
+        }
+        catch (boost::bad_lexical_cast const &) {
+            continue;
+        }
+    }
 }
 
 boost::optional<HostAndPort> DatabaseConfigurationImpl::getSentinelAddress(const boost::optional<std::size_t>& addressIndex) const
 {
-    if (addressIndex)
-        return { HostAndPort(serverAddresses.at(*addressIndex).getHost(), sentinelAddress->getPort()) };
+    std::size_t index(addressIndex ? *addressIndex : 0);
+    uint16_t port((sentinelPorts.size() > 0 && index < sentinelPorts.size()) ? sentinelPorts.at(index) : htons(DEFAULT_SENTINEL_PORT));
+
+    if (!(serverAddresses.size() > 0))
+        return {};
 
-    return getSentinelAddress();
+    return { HostAndPort(serverAddresses.at(index).getHost(), port) };
 }
 
-void DatabaseConfigurationImpl::checkAndApplySentinelMasterName(const std::string& name)
+void DatabaseConfigurationImpl::checkAndApplySentinelMasterNames(const std::string& sentinelMasterNamesEnvStr)
 {
-    sentinelMasterName = name;
+    boost::split(sentinelMasterNames, sentinelMasterNamesEnvStr, boost::is_any_of(","));
 }
 
-std::string DatabaseConfigurationImpl::getSentinelMasterName() const
+std::string DatabaseConfigurationImpl::getSentinelMasterName(const boost::optional<std::size_t>& addressIndex) const
 {
-    return sentinelMasterName;
+    std::size_t index(addressIndex ? *addressIndex : 0);
+    return ((sentinelMasterNames.size() > 0 && index < sentinelMasterNames.size()) ? sentinelMasterNames.at(index) : DEFAULT_SENTINEL_MASTER_GROUP_NAME);
 }
index 526757e..b57955e 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -62,11 +62,13 @@ std::shared_ptr<AsyncDatabaseDiscovery> AsyncDatabaseDiscovery::create(std::shar
             staticDbType == DatabaseConfiguration::DbType::SDL_SENTINEL_CLUSTER)
         {
             auto sentinelAddress(staticDatabaseConfiguration.getSentinelAddress(addressIndex));
+            auto sentinelMasterName(staticDatabaseConfiguration.getSentinelMasterName(addressIndex));
+
             if (sentinelAddress)
                 return std::make_shared<AsyncSentinelDatabaseDiscovery>(engine,
                                                                         logger,
                                                                         *sentinelAddress,
-                                                                        staticDatabaseConfiguration.getSentinelMasterName());
+                                                                        sentinelMasterName);
             else
                 SHAREDDATALAYER_ABORT("Sentinel address not configured.");
         }
index 55db2fc..d9f4f6d 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -73,14 +73,14 @@ namespace
             EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(address));
         }
 
-        void expectSentinelAddressConfigurationCheckAndApply(const std::string& address)
+        void expectCheckAndApplySentinelPorts(const std::string& portsEnvStr)
         {
-            EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelAddress(address));
+            EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelPorts(portsEnvStr));
         }
 
         void expectSentinelMasterNameConfigurationCheckAndApply(const std::string& address)
         {
-            EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelMasterName(address));
+            EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelMasterNames(address));
         }
 
         void expectDatabaseConfigurationIsEmpty_returnFalse()
@@ -883,7 +883,7 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithS
     expectDbTypeConfigurationCheckAndApply("redis-sentinel");
     expectDBServerAddressConfigurationCheckAndApply("sentinelAddress.local:1111");
     expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::REDIS_SENTINEL);
-    expectSentinelAddressConfigurationCheckAndApply("sentinelAddress.local:2222");
+    expectCheckAndApplySentinelPorts(sentinelPortEnvVariableValue);
     expectSentinelMasterNameConfigurationCheckAndApply(sentinelMasterNameEnvVariableValue);
     initializeReaderWithoutDirectories();
     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
@@ -895,9 +895,9 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithS
     dbHostEnvVariableValue = "address-0.local";
     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
     expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
-    sentinelPortEnvVariableValue = "2222";
+    sentinelPortEnvVariableValue = "2222,2223,2224";
     expectGetEnvironmentString(sentinelPortEnvVariableValue.c_str());
-    sentinelMasterNameEnvVariableValue = "mymaster";
+    sentinelMasterNameEnvVariableValue = "mymaster-0,mymaster-1,mymaster-2";
     expectGetEnvironmentString(sentinelMasterNameEnvVariableValue.c_str());
     dbClusterAddrListEnvVariableValue = "address-0.local,address-1.local,address-2.local";
     expectGetEnvironmentString(dbClusterAddrListEnvVariableValue.c_str());
@@ -907,7 +907,7 @@ TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithS
     expectDBServerAddressConfigurationCheckAndApply("address-1.local");
     expectDBServerAddressConfigurationCheckAndApply("address-2.local");
     expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::SDL_SENTINEL_CLUSTER);
-    expectSentinelAddressConfigurationCheckAndApply("address-0.local:2222");
+    expectCheckAndApplySentinelPorts(sentinelPortEnvVariableValue);
     expectSentinelMasterNameConfigurationCheckAndApply(sentinelMasterNameEnvVariableValue);
     initializeReaderWithoutDirectories();
     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
index 008d564..df6dd0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2018-2019 Nokia.
+   Copyright (c) 2018-2022 Nokia.
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
@@ -153,31 +153,66 @@ TEST_F(DatabaseConfigurationImplTest, DefaultSentinelAddressIsNone)
 
 TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelAddress)
 {
-    databaseConfigurationImpl->checkAndApplySentinelAddress("dummydatabaseaddress.local:1234");
-    auto address = databaseConfigurationImpl->getSentinelAddress(boost::none);
+    databaseConfigurationImpl->checkAndApplyServerAddress("dummydatabaseaddress.local:1234");
+    databaseConfigurationImpl->checkAndApplySentinelPorts("51234");
+    const auto serverAddresses(databaseConfigurationImpl->getServerAddresses());
+    const auto address = databaseConfigurationImpl->getSentinelAddress(boost::none);
     EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(boost::none));
     EXPECT_EQ("dummydatabaseaddress.local", address->getHost());
-    EXPECT_EQ(1234, ntohs(address->getPort()));
+    EXPECT_EQ(51234, ntohs(address->getPort()));
+    EXPECT_EQ(1U, serverAddresses.size());
+    EXPECT_EQ("dummydatabaseaddress.local", serverAddresses.at(0).getHost());
+    EXPECT_EQ(1234U, ntohs(serverAddresses.at(0).getPort()));
+}
+
+TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelAddressDefaultSentinelPort)
+{
+    databaseConfigurationImpl->checkAndApplyServerAddress("dummydatabaseaddress.local:1234");
+    databaseConfigurationImpl->checkAndApplySentinelPorts("");
+    const auto serverAddresses(databaseConfigurationImpl->getServerAddresses());
+    const auto address = databaseConfigurationImpl->getSentinelAddress(boost::none);
+    EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(boost::none));
+    EXPECT_EQ("dummydatabaseaddress.local", address->getHost());
+    EXPECT_EQ(26379, ntohs(address->getPort()));
+    EXPECT_EQ(1U, serverAddresses.size());
+    EXPECT_EQ("dummydatabaseaddress.local", serverAddresses.at(0).getHost());
+    EXPECT_EQ(1234U, ntohs(serverAddresses.at(0).getPort()));
 }
 
 TEST_F(DatabaseConfigurationImplTest, DefaultSentinelMasterNameIsEmpty)
 {
-    EXPECT_EQ("", databaseConfigurationImpl->getSentinelMasterName());
+    EXPECT_EQ("dbaasmaster", databaseConfigurationImpl->getSentinelMasterName(boost::none));
 }
 
 TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelMasterName)
 {
-    databaseConfigurationImpl->checkAndApplySentinelMasterName("mymaster");
-    EXPECT_EQ("mymaster", databaseConfigurationImpl->getSentinelMasterName());
+    databaseConfigurationImpl->checkAndApplySentinelMasterNames("mymaster");
+    EXPECT_EQ("mymaster", databaseConfigurationImpl->getSentinelMasterName(boost::none));
+}
+
+TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnSentinelMasterNames)
+{
+    databaseConfigurationImpl->checkAndApplySentinelMasterNames("mymaster-0,mymaster-1,mymaster-2");
+    EXPECT_EQ("mymaster-0", databaseConfigurationImpl->getSentinelMasterName(0));
+    EXPECT_EQ("mymaster-1", databaseConfigurationImpl->getSentinelMasterName(1));
+    EXPECT_EQ("mymaster-2", databaseConfigurationImpl->getSentinelMasterName(2));
 }
 
-TEST_F(DatabaseConfigurationImplTest, CanReturnSDLSentinelClusterAddress)
+TEST_F(DatabaseConfigurationImplTest, CanApplyAndReturnDefaultSentinelMasterNamesWhenNotAllMasterNamesAreSet)
+{
+    databaseConfigurationImpl->checkAndApplySentinelMasterNames("mymaster-0");
+    EXPECT_EQ("mymaster-0", databaseConfigurationImpl->getSentinelMasterName(0));
+    EXPECT_EQ("dbaasmaster", databaseConfigurationImpl->getSentinelMasterName(1));
+    EXPECT_EQ("dbaasmaster", databaseConfigurationImpl->getSentinelMasterName(2));
+}
+
+TEST_F(DatabaseConfigurationImplTest, CanReturnSDLSentinelClusterAddresses)
 {
     databaseConfigurationImpl->checkAndApplyDbType("sdl-sentinel-cluster");
     databaseConfigurationImpl->checkAndApplyServerAddress("cluster-0.local");
     databaseConfigurationImpl->checkAndApplyServerAddress("cluster-1.local");
     databaseConfigurationImpl->checkAndApplyServerAddress("cluster-2.local");
-    databaseConfigurationImpl->checkAndApplySentinelAddress("cluster-0.local:54321");
+    databaseConfigurationImpl->checkAndApplySentinelPorts("54321,54322,54323");
     auto address0 = databaseConfigurationImpl->getSentinelAddress(0);
     auto address1 = databaseConfigurationImpl->getSentinelAddress(1);
     auto address2 = databaseConfigurationImpl->getSentinelAddress(2);
@@ -188,14 +223,36 @@ TEST_F(DatabaseConfigurationImplTest, CanReturnSDLSentinelClusterAddress)
     EXPECT_EQ("cluster-1.local", address1->getHost());
     EXPECT_EQ("cluster-2.local", address2->getHost());
     EXPECT_EQ(54321, ntohs(address0->getPort()));
+    EXPECT_EQ(54322, ntohs(address1->getPort()));
+    EXPECT_EQ(54323, ntohs(address2->getPort()));
 }
 
-TEST_F(DatabaseConfigurationImplTest, CanReturnDefaultPortForSDLClusterAddress)
+TEST_F(DatabaseConfigurationImplTest, CanReturnSDLSentinelPorts)
 {
+    databaseConfigurationImpl->checkAndApplyDbType("sdl-sentinel-cluster");
     databaseConfigurationImpl->checkAndApplyServerAddress("cluster-0.local");
-    databaseConfigurationImpl->checkAndApplySentinelAddress("cluster-0.local");
+    databaseConfigurationImpl->checkAndApplyServerAddress("cluster-1.local");
+    databaseConfigurationImpl->checkAndApplyServerAddress("cluster-2.local");
+    databaseConfigurationImpl->checkAndApplySentinelPorts("54321");
     auto address0 = databaseConfigurationImpl->getSentinelAddress(0);
+    auto address1 = databaseConfigurationImpl->getSentinelAddress(1);
+    auto address2 = databaseConfigurationImpl->getSentinelAddress(2);
     EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(0));
+    EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(1));
+    EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(2));
     EXPECT_EQ("cluster-0.local", address0->getHost());
-    EXPECT_EQ(26379, ntohs(address0->getPort()));
+    EXPECT_EQ("cluster-1.local", address1->getHost());
+    EXPECT_EQ("cluster-2.local", address2->getHost());
+    EXPECT_EQ(54321, ntohs(address0->getPort()));
+    EXPECT_EQ(26379, ntohs(address1->getPort()));
+    EXPECT_EQ(26379, ntohs(address2->getPort()));
+}
+
+TEST_F(DatabaseConfigurationImplTest, CanReturnDefaultSentinelPortForSDLClusterAddress)
+{
+    databaseConfigurationImpl->checkAndApplyServerAddress("cluster-0.local");
+    auto address = databaseConfigurationImpl->getSentinelAddress(boost::none);
+    EXPECT_NE(boost::none, databaseConfigurationImpl->getSentinelAddress(boost::none));
+    EXPECT_EQ("cluster-0.local", address->getHost());
+    EXPECT_EQ(26379, ntohs(address->getPort()));
 }