diff --git a/catalogue/CMakeLists.txt b/catalogue/CMakeLists.txt index b46717c56fa40107568986b89929423588cee423..dffdef2ef4d3f2b3527988b6c9634a094fa0f836 100644 --- a/catalogue/CMakeLists.txt +++ b/catalogue/CMakeLists.txt @@ -58,6 +58,7 @@ set (CATALOGUE_LIB_SRC_FILES UserSpecifiedAnEmptyStringLogicalLibraryName.cpp UserSpecifiedAnEmptyStringMediaType.cpp UserSpecifiedAnEmptyStringStorageClassName.cpp + UserSpecifiedAnEmptyStringSupply.cpp UserSpecifiedAnEmptyStringTapePoolName.cpp UserSpecifiedAnEmptyStringUsername.cpp UserSpecifiedAnEmptyStringVendor.cpp diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp index 3a0a928252cbf654d5f4cab2b777a6973f79e3ab..695eabebfe6c97884d521901eaa82f2ee46c7c1b 100644 --- a/catalogue/Catalogue.hpp +++ b/catalogue/Catalogue.hpp @@ -58,6 +58,7 @@ #include "common/exception/UserError.hpp" #include "common/log/LogContext.hpp" #include "common/log/Logger.hpp" +#include "common/optional.hpp" #include <list> #include <map> @@ -237,13 +238,14 @@ public: virtual void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &name, const uint64_t nbCopies) = 0; virtual void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &name, const std::string &comment) = 0; - virtual void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::string &comment) = 0; + virtual void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const cta::optional<std::string> &supply, const std::string &comment) = 0; virtual void deleteTapePool(const std::string &name) = 0; virtual std::list<TapePool> getTapePools() const = 0; virtual void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) = 0; virtual void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbPartialTapes) = 0; virtual void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; virtual void setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool encryptionValue) = 0; + virtual void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) = 0; virtual void createArchiveRoute( const common::dataStructures::SecurityIdentity &admin, @@ -271,10 +273,11 @@ public: virtual void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) = 0; virtual void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) = 0; - virtual void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; + virtual void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool isDisabled, const std::string &comment) = 0; virtual void deleteLogicalLibrary(const std::string &name) = 0; virtual std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const = 0; virtual void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; + virtual void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) = 0; /** * Creates a tape which is assumed to have logical block protection (LBP) diff --git a/catalogue/CatalogueRetryWrapper.hpp b/catalogue/CatalogueRetryWrapper.hpp index 9e01f127fefd7d9851fedea3f495087342d5f19b..b9155d69c4b2ddb531286f31a60550cd144fb03b 100644 --- a/catalogue/CatalogueRetryWrapper.hpp +++ b/catalogue/CatalogueRetryWrapper.hpp @@ -137,8 +137,8 @@ public: return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyStorageClassComment(admin, instanceName, name, comment);}, m_maxTriesToConnect); } - void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::string &comment) override { - return retryOnLostConnection(m_log, [&]{return m_catalogue->createTapePool(admin, name, vo, nbPartialTapes, encryptionValue, comment);}, m_maxTriesToConnect); + void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const cta::optional<std::string> &supply, const std::string &comment) override { + return retryOnLostConnection(m_log, [&]{return m_catalogue->createTapePool(admin, name, vo, nbPartialTapes, encryptionValue, supply, comment);}, m_maxTriesToConnect); } void deleteTapePool(const std::string &name) override { @@ -165,6 +165,10 @@ public: return retryOnLostConnection(m_log, [&]{return m_catalogue->setTapePoolEncryption(admin, name, encryptionValue);}, m_maxTriesToConnect); } + void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) override { + return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapePoolSupply(admin, name, supply);}, m_maxTriesToConnect); + } + void createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &diskInstanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) override { return retryOnLostConnection(m_log, [&]{return m_catalogue->createArchiveRoute(admin, diskInstanceName, storageClassName, copyNb, tapePoolName, comment);}, m_maxTriesToConnect); } @@ -185,8 +189,8 @@ public: return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyArchiveRouteComment(admin, instanceName, storageClassName, copyNb, comment);}, m_maxTriesToConnect); } - void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override { - return retryOnLostConnection(m_log, [&]{return m_catalogue->createLogicalLibrary(admin, name, comment);}, m_maxTriesToConnect); + void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool isDisabled, const std::string &comment) override { + return retryOnLostConnection(m_log, [&]{return m_catalogue->createLogicalLibrary(admin, name, isDisabled, comment);}, m_maxTriesToConnect); } void deleteLogicalLibrary(const std::string &name) override { @@ -201,6 +205,10 @@ public: return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyLogicalLibraryComment(admin, name, comment);}, m_maxTriesToConnect); } + void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) override { + return retryOnLostConnection(m_log, [&]{return m_catalogue->setLogicalLibraryDisabled(admin, name, disabledValue);}, m_maxTriesToConnect); + } + void createTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType, const std::string &vendor, const std::string &logicalLibraryName, const std::string &tapePoolName, const uint64_t capacityInBytes, const bool disabled, const bool full, const std::string &comment) override { return retryOnLostConnection(m_log, [&]{return m_catalogue->createTape(admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabled, full, comment);}, m_maxTriesToConnect); } diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp index 5223ea81934496221e67381ebf9f4367b90f58c6..97000ca464a268a50cb3f91811cc32ff7de48fae 100644 --- a/catalogue/CatalogueTest.cpp +++ b/catalogue/CatalogueTest.cpp @@ -28,6 +28,7 @@ #include "catalogue/UserSpecifiedAnEmptyStringLogicalLibraryName.hpp" #include "catalogue/UserSpecifiedAnEmptyStringMediaType.hpp" #include "catalogue/UserSpecifiedAnEmptyStringStorageClassName.hpp" +#include "catalogue/UserSpecifiedAnEmptyStringSupply.hpp" #include "catalogue/UserSpecifiedAnEmptyStringTapePoolName.hpp" #include "catalogue/UserSpecifiedAnEmptyStringUsername.hpp" #include "catalogue/UserSpecifiedAnEmptyStringVendor.hpp" @@ -798,8 +799,9 @@ TEST_P(cta_catalogue_CatalogueTest, createTapePool) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); ASSERT_TRUE(m_catalogue->tapePoolExists(tapePoolName)); @@ -812,6 +814,52 @@ TEST_P(cta_catalogue_CatalogueTest, createTapePool) { ASSERT_EQ(vo, pool.vo); ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(supply.value(), pool.supply.value()); + ASSERT_EQ(supply, pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = + pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_CatalogueTest, createTapePool_null_supply) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = "tape_pool"; + + ASSERT_FALSE(m_catalogue->tapePoolExists(tapePoolName)); + + const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply; + const std::string comment = "Create tape pool"; + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); + + ASSERT_TRUE(m_catalogue->tapePoolExists(tapePoolName)); + + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_FALSE((bool)pool.supply); ASSERT_EQ(0, pool.nbTapes); ASSERT_EQ(0, pool.capacityBytes); ASSERT_EQ(0, pool.dataBytes); @@ -834,9 +882,10 @@ TEST_P(cta_catalogue_CatalogueTest, createTapePool_same_twice) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); - ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment), + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); + ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment), exception::UserError); } @@ -849,8 +898,9 @@ TEST_P(cta_catalogue_CatalogueTest, deleteTapePool) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); const auto pools = m_catalogue->getTapePools(); @@ -891,17 +941,21 @@ TEST_P(cta_catalogue_CatalogueTest, deleteTapePool_notEmpty) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -973,8 +1027,9 @@ TEST_P(cta_catalogue_CatalogueTest, createTapePool_emptyStringTapePoolName) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment), + ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment), catalogue::UserSpecifiedAnEmptyStringTapePoolName); } @@ -990,8 +1045,9 @@ TEST_P(cta_catalogue_CatalogueTest, createTapePool_emptyStringVO) { const std::string vo = ""; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment), + ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment), catalogue::UserSpecifiedAnEmptyStringVo); } @@ -1007,8 +1063,9 @@ TEST_P(cta_catalogue_CatalogueTest, createTapePool_emptyStringComment) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = ""; - ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment), + ASSERT_THROW(m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment), catalogue::UserSpecifiedAnEmptyStringComment); } @@ -1028,8 +1085,9 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolVo) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); { const auto pools = m_catalogue->getTapePools(); @@ -1100,8 +1158,9 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolVo_emptyStringVo) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); { const auto pools = m_catalogue->getTapePools(); @@ -1141,8 +1200,9 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolNbPartialTapes) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); { const auto pools = m_catalogue->getTapePools(); @@ -1224,8 +1284,9 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolComment) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); { const auto pools = m_catalogue->getTapePools(); @@ -1296,8 +1357,9 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolComment_emptyStringComment) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); { const auto pools = m_catalogue->getTapePools(); @@ -1347,8 +1409,9 @@ TEST_P(cta_catalogue_CatalogueTest, setTapePoolEncryption) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string comment = "Create tape pool"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, comment); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); { const auto pools = m_catalogue->getTapePools(); @@ -1409,6 +1472,139 @@ TEST_P(cta_catalogue_CatalogueTest, setTapePoolEncryption_nonExistentTapePool) { ASSERT_THROW(m_catalogue->setTapePoolEncryption(m_admin, tapePoolName, isEncrypted), exception::UserError); } +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolSupply) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = "tape_pool"; + const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); + + { + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)supply); + ASSERT_EQ(supply.value(), pool.supply.value()); + ASSERT_EQ(supply, pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedSupply("Modified supply"); + m_catalogue->modifyTapePoolSupply(m_admin, tapePoolName, modifiedSupply); + + { + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)supply); + ASSERT_EQ(modifiedSupply, pool.supply.value()); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolSupply_emptyStringTapePoolName) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = ""; + const std::string modifiedSupply = "Modified supply"; + ASSERT_THROW(m_catalogue->modifyTapePoolSupply(m_admin, tapePoolName, modifiedSupply), + catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolSupply_emptyStringSupply) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = "tape_pool"; + const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); + + { + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)supply); + ASSERT_EQ(supply.value(), pool.supply.value()); + ASSERT_EQ(supply, pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedSupply = ""; + ASSERT_THROW(m_catalogue->modifyTapePoolSupply(m_admin, tapePoolName, modifiedSupply), + catalogue::UserSpecifiedAnEmptyStringSupply); +} + +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolSupply_nonExistentTapePool) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = "tape_pool"; + const std::string supply = "value for the supply pool mechanism"; + ASSERT_THROW(m_catalogue->modifyTapePoolSupply(m_admin, tapePoolName, supply), exception::UserError); +} + TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute) { using namespace cta; @@ -1427,7 +1623,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1470,7 +1667,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_emptyStringDiskInstanceNa const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const std::string diskInstanceName = ""; const uint32_t copyNb = 1; @@ -1497,7 +1695,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_emptyStringStorageClassNa const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const std::string storageClassName = ""; const uint32_t copyNb = 1; @@ -1524,7 +1723,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_zeroCopyNb) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 0; const std::string comment = "Create archive route"; @@ -1571,7 +1771,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_emptyStringComment) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = ""; @@ -1593,7 +1794,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_non_existent_storage_clas const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1650,7 +1852,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_same_name_different_disk_ const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1702,7 +1905,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_same_twice) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1729,7 +1933,8 @@ TEST_P(cta_catalogue_CatalogueTest, deleteArchiveRoute) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1782,7 +1987,8 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_deleteStorageClass) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1828,10 +2034,12 @@ TEST_P(cta_catalogue_CatalogueTest, modifyArchiveRouteTapePoolName) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const std::string anotherTapePoolName = "another_tape_pool"; - m_catalogue->createTapePool(m_admin, anotherTapePoolName, vo, nbPartialTapes, isEncrypted, "Create another tape pool"); + m_catalogue->createTapePool(m_admin, anotherTapePoolName, vo, nbPartialTapes, isEncrypted, supply, + "Create another tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1896,7 +2104,8 @@ TEST_P(cta_catalogue_CatalogueTest, modifyArchiveRouteTapePoolName_nonExistentAr const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; ASSERT_THROW(m_catalogue->modifyArchiveRouteTapePoolName(m_admin, storageClass.diskInstance, storageClass.name, @@ -1921,7 +2130,8 @@ TEST_P(cta_catalogue_CatalogueTest, modifyArchiveRouteComment) { const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Create archive route"; @@ -1988,7 +2198,8 @@ TEST_P(cta_catalogue_CatalogueTest, modifyArchiveRouteComment_nonExistentArchive const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string comment = "Comment"; @@ -2003,7 +2214,8 @@ TEST_P(cta_catalogue_CatalogueTest, createLogicalLibrary) { const std::string logicalLibraryName = "logical_library"; const std::string comment = "Create logical library"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, comment); + const bool logicalLibraryIsDisabled= false; + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); const std::list<common::dataStructures::LogicalLibrary> libs = m_catalogue->getLogicalLibraries(); @@ -2012,6 +2224,65 @@ TEST_P(cta_catalogue_CatalogueTest, createLogicalLibrary) { const common::dataStructures::LogicalLibrary lib = libs.front(); ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_CatalogueTest, createLogicalLibrary_disabled_true) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled(true); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); + + const std::list<common::dataStructures::LogicalLibrary> libs = + m_catalogue->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_TRUE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_CatalogueTest, createLogicalLibrary_disabled_false) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled(false); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); + + const std::list<common::dataStructures::LogicalLibrary> libs = + m_catalogue->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); ASSERT_EQ(comment, lib.comment); const common::dataStructures::EntryLog creationLog = lib.creationLog; @@ -2028,8 +2299,109 @@ TEST_P(cta_catalogue_CatalogueTest, createLogicalLibrary_same_twice) { const std::string logicalLibraryName = "logical_library"; const std::string comment = "Create logical library"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, comment); - ASSERT_THROW(m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, comment), exception::UserError); + const bool logicalLibraryIsDisabled= false; + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); + ASSERT_THROW(m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment), exception::UserError); +} + +TEST_P(cta_catalogue_CatalogueTest, setLogicalLibraryDisabled_true) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); + + { + const std::list<common::dataStructures::LogicalLibrary> libs = + m_catalogue->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const bool modifiedLogicalLibraryIsDisabled= true; + m_catalogue->setLogicalLibraryDisabled(m_admin, logicalLibraryName, modifiedLogicalLibraryIsDisabled); + + { + const std::list<common::dataStructures::LogicalLibrary> libs = + m_catalogue->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(modifiedLogicalLibraryIsDisabled, lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_CatalogueTest, setLogicalLibraryDisabled_false) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); + + { + const std::list<common::dataStructures::LogicalLibrary> libs = + m_catalogue->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const bool modifiedLogicalLibraryIsDisabled= false; + m_catalogue->setLogicalLibraryDisabled(m_admin, logicalLibraryName, modifiedLogicalLibraryIsDisabled); + + { + const std::list<common::dataStructures::LogicalLibrary> libs = + m_catalogue->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(modifiedLogicalLibraryIsDisabled, lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } } TEST_P(cta_catalogue_CatalogueTest, deleteLogicalLibrary) { @@ -2039,7 +2411,8 @@ TEST_P(cta_catalogue_CatalogueTest, deleteLogicalLibrary) { const std::string logicalLibraryName = "logical_library"; const std::string comment = "Create logical library"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, comment); + const bool logicalLibraryIsDisabled= false; + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); const std::list<common::dataStructures::LogicalLibrary> libs = m_catalogue->getLogicalLibraries(); @@ -2076,7 +2449,8 @@ TEST_P(cta_catalogue_CatalogueTest, modifyLogicalLibraryComment) { const std::string logicalLibraryName = "logical_library"; const std::string comment = "Create logical library"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, comment); + const bool logicalLibraryIsDisabled= false; + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, comment); { const std::list<common::dataStructures::LogicalLibrary> libs = m_catalogue->getLogicalLibraries(); @@ -2147,17 +2521,20 @@ TEST_P(cta_catalogue_CatalogueTest, createTape) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2228,17 +2605,20 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringVid) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2270,12 +2650,15 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringMediaType) { const std::string logicalLibraryName = "logical_library_name"; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2307,12 +2690,15 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringVendor) { const std::string logicalLibraryName = "logical_library_name"; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2344,12 +2730,15 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringLogicalLibraryName) { const std::string logicalLibraryName = ""; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2379,6 +2768,7 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringTapePoolName) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = ""; const std::string vo = "vo"; const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; @@ -2386,8 +2776,7 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringTapePoolName) { const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); ASSERT_THROW(m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment), catalogue::UserSpecifiedAnEmptyStringTapePoolName); @@ -2405,17 +2794,20 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_zeroCapacity) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = 0; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2445,17 +2837,20 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_emptyStringComment) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = ""; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2484,12 +2879,15 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_non_existent_logical_library) { const std::string logicalLibraryName = "logical_library_name"; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); ASSERT_THROW(m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment), exception::UserError); } @@ -2503,14 +2901,14 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_non_existent_tape_pool) { const std::string vendor = "vendor"; const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); ASSERT_THROW(m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment), exception::UserError); } @@ -2524,17 +2922,21 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_9_exabytes_capacity) { const std::string vendor = "vendor"; const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); // The maximum size of an SQLite integer is a signed 64-bit integer const uint64_t capacityInBytes = 9L * 1000 * 1000 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2600,17 +3002,20 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_same_twice) { const std::string vendor = "vendor"; const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2664,18 +3069,22 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_many_tapes) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibrary = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t) 10 * 1000 * 1000 * 1000 * 1000; const bool disabled = true; const bool full = false; const std::string comment = "Create tape"; ASSERT_TRUE(m_catalogue->getLogicalLibraries().empty()); - m_catalogue->createLogicalLibrary(m_admin, logicalLibrary, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibrary, logicalLibraryIsDisabled, "Create logical library"); ASSERT_TRUE(m_catalogue->getTapePools().empty()); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -2928,15 +3337,19 @@ TEST_P(cta_catalogue_CatalogueTest, createTape_1_tape_with_write_log_1_tape_with const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); @@ -3091,16 +3504,19 @@ TEST_P(cta_catalogue_CatalogueTest, deleteTape) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3153,16 +3569,19 @@ TEST_P(cta_catalogue_CatalogueTest, deleteNonEmptyTape) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, - "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3272,16 +3691,20 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeMediaType) { const std::string anotherMediaType = "another_media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3350,16 +3773,20 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeVendor) { const std::string vendor = "vendor"; const std::string anotherVendor = "another_vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3428,18 +3855,23 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLogicalLibraryName) { const std::string mediaType = "mediaType"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string anotherLogicalLibraryName = "another_logical_library_name"; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createLogicalLibrary(m_admin, anotherLogicalLibraryName, "Create another logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, anotherLogicalLibraryName, logicalLibraryIsDisabled, + "Create another logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3506,8 +3938,9 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeLogicalLibraryName_nonExistentTape const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); ASSERT_THROW(m_catalogue->modifyTapeLogicalLibraryName(m_admin, vid, logicalLibraryName), exception::UserError); } @@ -3521,18 +3954,22 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeTapePoolName) { const std::string mediaType = "mediaType"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const std::string anotherTapePoolName = "another_tape_pool_name"; const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); - m_catalogue->createTapePool(m_admin, anotherTapePoolName, vo, 2, true, "Create another tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->createTapePool(m_admin, anotherTapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create another tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3600,11 +4037,15 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeTapePoolName_nonExistentTape) { const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); ASSERT_THROW(m_catalogue->modifyTapeTapePoolName(m_admin, vid, tapePoolName), exception::UserError); } @@ -3618,16 +4059,20 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeCapacityInBytes) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3709,16 +4154,20 @@ TEST_P(cta_catalogue_CatalogueTest, modifyTapeEncryptionKey) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3801,16 +4250,20 @@ TEST_P(cta_catalogue_CatalogueTest, tapeLabelled) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3893,16 +4346,20 @@ TEST_P(cta_catalogue_CatalogueTest, tapeMountedForArchive) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -3985,16 +4442,20 @@ TEST_P(cta_catalogue_CatalogueTest, tapeMountedForRetrieve) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -4077,16 +4538,20 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeFull) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -4166,16 +4631,20 @@ TEST_P(cta_catalogue_CatalogueTest, noSpaceLeftOnTape) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -4255,16 +4724,20 @@ TEST_P(cta_catalogue_CatalogueTest, setTapeDisabled) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -4344,15 +4817,19 @@ TEST_P(cta_catalogue_CatalogueTest, getTapesForWriting) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->tapeLabelled(vid, "tape_drive"); @@ -4381,15 +4858,19 @@ TEST_P(cta_catalogue_CatalogueTest, DISABLED_getTapesForWriting_no_labelled_tape const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -5753,7 +6234,8 @@ TEST_P(cta_catalogue_CatalogueTest, checkAndGetNextArchiveFileId_no_mount_rules) const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -5838,7 +6320,8 @@ TEST_P(cta_catalogue_CatalogueTest, checkAndGetNextArchiveFileId_requester_mount const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -5928,7 +6411,8 @@ TEST_P(cta_catalogue_CatalogueTest, checkAndGetNextArchiveFileId_requester_group const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -6037,7 +6521,8 @@ TEST_P(cta_catalogue_CatalogueTest, checkAndGetNextArchiveFileId_requester_mount const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -6186,7 +6671,8 @@ TEST_P(cta_catalogue_CatalogueTest, getArchiveFileQueueCriteria_requester_mount_ const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -6268,7 +6754,8 @@ TEST_P(cta_catalogue_CatalogueTest, getArchiveFileQueueCriteria_requester_group_ const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -6369,7 +6856,8 @@ TEST_P(cta_catalogue_CatalogueTest, getArchiveFileQueueCriteria_requester_mount_ const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; const bool isEncrypted = true; - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, "Create tape pool"); + const cta::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Create archive route"; @@ -6412,15 +6900,19 @@ TEST_P(cta_catalogue_CatalogueTest, prepareToRetrieveFileUsingArchiveFileId) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; const bool fullValue = false; const std::string createTapeComment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -6670,15 +7162,19 @@ TEST_P(cta_catalogue_CatalogueTest, prepareToRetrieveFileUsingArchiveFileId_disa const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; const bool fullValue = false; const std::string createTapeComment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -7145,17 +7641,21 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_many_archive_files) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName1 = "tape_pool_name_1"; const std::string tapePoolName2 = "tape_pool_name_2"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName1, vo, 1, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName1, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -7172,7 +7672,7 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_many_archive_files) { ASSERT_EQ(0, pool.nbPhysicalFiles); } - m_catalogue->createTapePool(m_admin, tapePoolName2, vo, 1, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName2, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(2, pools.size()); @@ -8130,17 +8630,21 @@ TEST_P(cta_catalogue_CatalogueTest, DISABLED_concurrent_filesWrittenToTape_many_ const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName1 = "tape_pool_name_1"; const std::string tapePoolName2 = "tape_pool_name_2"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName1, vo, 1, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName1, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(1, pools.size()); @@ -8157,7 +8661,7 @@ TEST_P(cta_catalogue_CatalogueTest, DISABLED_concurrent_filesWrittenToTape_many_ ASSERT_EQ(0, pool.nbPhysicalFiles); } - m_catalogue->createTapePool(m_admin, tapePoolName2, vo, 1, true, "Create tape pool"); + m_catalogue->createTapePool(m_admin, tapePoolName2, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); { const auto pools = m_catalogue->getTapePools(); ASSERT_EQ(2, pools.size()); @@ -8951,15 +9455,19 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_1_archive_file_2_tape_cop const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -9180,15 +9688,19 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_1_archive_file_2_tape_cop const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -9405,15 +9917,19 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_1_archive_file_2_tape_cop const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -9604,15 +10120,19 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_1_archive_file_2_tape_cop const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -9786,15 +10306,19 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_1_archive_file_2_tape_cop const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -9968,15 +10492,19 @@ TEST_P(cta_catalogue_CatalogueTest, filesWrittenToTape_1_archive_file_2_tape_cop const std::string mediaType = "mediaType"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -10150,15 +10678,19 @@ TEST_P(cta_catalogue_CatalogueTest, deleteArchiveFile) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -10467,15 +10999,19 @@ TEST_P(cta_catalogue_CatalogueTest, deleteArchiveFile_by_archive_file_id_of_anot const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -10812,15 +11348,18 @@ TEST_P(cta_catalogue_CatalogueTest, getAllTapes_many_tapes) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); const uint32_t nbTapes = 10; @@ -10865,15 +11404,19 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_full_lastFSeq_0_no_tape_files) { const std::string vendor = "vendor"; const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -10946,15 +11489,19 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_not_full_lastFSeq_0_no_tape_file const std::string vendor = "vendor"; const std::string vid = "vid"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string comment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, comment); @@ -11002,15 +11549,19 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_full_lastFSeq_1_no_tape_files) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string createTapeComment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); @@ -11225,15 +11776,19 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_full_lastFSeq_1_one_tape_file) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string createTapeComment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); @@ -11385,15 +11940,19 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_full_lastFSeq_1_one_tape_file_su const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string createTapeComment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); m_catalogue->createTape(m_admin, vid2, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, @@ -11604,15 +12163,19 @@ TEST_P(cta_catalogue_CatalogueTest, exist_non_superseded_files_after_fseq) { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled= false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string createTapeComment = "Create tape"; - m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(m_admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(m_admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(m_admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); diff --git a/catalogue/DropSchemaCmd.cpp b/catalogue/DropSchemaCmd.cpp index 607e254eeef3446704026e3edc30b813c5c8fa0f..a73dd2f84110d16f701dc55b8ed5b36c41bc601d 100644 --- a/catalogue/DropSchemaCmd.cpp +++ b/catalogue/DropSchemaCmd.cpp @@ -184,7 +184,9 @@ void DropSchemaCmd::dropMysqlCatalogueSchema(rdbms::Conn &conn) { "CHECK_TAPE_BEFORE_INSERT", "CHECK_TAPE_BEFORE_UPDATE", "TAPE_FILE_COPY_NB_GT_ZERO_BEFORE_INSERT", - "TAPE_FILE_COPY_NB_GT_ZERO_BEFORE_UPDATE" + "TAPE_FILE_COPY_NB_GT_ZERO_BEFORE_UPDATE", + "CHECK_LOGICAL_LIBRARY_BEFORE_INSERT", + "CHECK_LOGICAL_LIBRARY_BEFORE_UPDATE" }; for (auto triggerToDrop: triggersToDrop) { conn.executeNonQuery(std::string("DROP TRIGGER IF EXISTS ") + triggerToDrop); diff --git a/catalogue/DummyCatalogue.hpp b/catalogue/DummyCatalogue.hpp index 506f2678be937730c3d379057fe412f230c7ed52..a67b479e1710340e5726459b69beefbe4aebda3f 100644 --- a/catalogue/DummyCatalogue.hpp +++ b/catalogue/DummyCatalogue.hpp @@ -36,13 +36,13 @@ public: void createAdminUser(const common::dataStructures::SecurityIdentity& admin, const std::string& username, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void createArchiveRoute(const common::dataStructures::SecurityIdentity& admin, const std::string& diskInstanceName, const std::string& storageClassName, const uint32_t copyNb, const std::string& tapePoolName, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } - void createLogicalLibrary(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } + void createLogicalLibrary(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const bool isDisabled, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void createMountPolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t archivePriority, const uint64_t minArchiveRequestAge, const uint64_t retrievePriority, const uint64_t minRetrieveRequestAge, const uint64_t maxDrivesAllowed, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void createRequesterGroupMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstanceName, const std::string& requesterGroupName, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void createRequesterMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstance, const std::string& requesterName, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void createStorageClass(const common::dataStructures::SecurityIdentity& admin, const common::dataStructures::StorageClass& storageClass) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void createTape(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string &mediaType, const std::string &vendor, const std::string& logicalLibraryName, const std::string& tapePoolName, const uint64_t capacityInBytes, const bool disabled, const bool full, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } - void createTapePool(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string & vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } + void createTapePool(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string & vo, const uint64_t nbPartialTapes, const bool encryptionValue, const cta::optional<std::string> &supply, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void deleteAdminUser(const std::string& username) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void deleteArchiveFile(const std::string& instanceName, const uint64_t archiveFileId, log::LogContext &lc) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void deleteArchiveRoute(const std::string& diskInstanceName, const std::string& storageClassName, const uint32_t copyNb) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } @@ -76,6 +76,7 @@ public: void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& storageClassName, const uint32_t copyNb, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& storageClassName, const uint32_t copyNb, const std::string& tapePoolName) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } + void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t minArchiveRequestAge) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t archivePriority) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } @@ -97,6 +98,7 @@ public: void modifyTapePoolComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbPartialTapes) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } + void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& supply) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& tapePoolName) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void noSpaceLeftOnTape(const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void ping() override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp index 0db0322496b58c634e1c2eae803d846cca660378..4ad7b64be62195aac45f256293e23f88be420e48 100644 --- a/catalogue/RdbmsCatalogue.cpp +++ b/catalogue/RdbmsCatalogue.cpp @@ -29,6 +29,7 @@ #include "catalogue/UserSpecifiedAnEmptyStringLogicalLibraryName.hpp" #include "catalogue/UserSpecifiedAnEmptyStringMediaType.hpp" #include "catalogue/UserSpecifiedAnEmptyStringStorageClassName.hpp" +#include "catalogue/UserSpecifiedAnEmptyStringSupply.hpp" #include "catalogue/UserSpecifiedAnEmptyStringTapePoolName.hpp" #include "catalogue/UserSpecifiedAnEmptyStringUsername.hpp" #include "catalogue/UserSpecifiedAnEmptyStringVendor.hpp" @@ -568,6 +569,7 @@ void RdbmsCatalogue::createTapePool( const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const cta::optional<std::string> &supply, const std::string &comment) { try { if(name.empty()) { @@ -595,6 +597,7 @@ void RdbmsCatalogue::createTapePool( "VO," "NB_PARTIAL_TAPES," "IS_ENCRYPTED," + "SUPPLY," "USER_COMMENT," @@ -610,6 +613,7 @@ void RdbmsCatalogue::createTapePool( ":VO," ":NB_PARTIAL_TAPES," ":IS_ENCRYPTED," + ":SUPPLY," ":USER_COMMENT," @@ -626,6 +630,7 @@ void RdbmsCatalogue::createTapePool( stmt.bindString(":VO", vo); stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes); stmt.bindBool(":IS_ENCRYPTED", encryptionValue); + stmt.bindOptionalString(":SUPPLY", supply); stmt.bindString(":USER_COMMENT", comment); @@ -893,6 +898,7 @@ std::list<TapePool> RdbmsCatalogue::getTapePools() const { "COALESCE(TAPE_POOL.VO, 'NONE') AS VO," // TBD Remove COALESCE "TAPE_POOL.NB_PARTIAL_TAPES AS NB_PARTIAL_TAPES," "TAPE_POOL.IS_ENCRYPTED AS IS_ENCRYPTED," + "TAPE_POOL.SUPPLY AS SUPPLY," "COALESCE(COUNT(TAPE.VID), 0) AS NB_TAPES," "COALESCE(SUM(TAPE.CAPACITY_IN_BYTES), 0) AS CAPACITY_IN_BYTES," @@ -917,6 +923,7 @@ std::list<TapePool> RdbmsCatalogue::getTapePools() const { "TAPE_POOL.VO," "TAPE_POOL.NB_PARTIAL_TAPES," "TAPE_POOL.IS_ENCRYPTED," + "TAPE_POOL.SUPPLY," "TAPE_POOL.USER_COMMENT," "TAPE_POOL.CREATION_LOG_USER_NAME," "TAPE_POOL.CREATION_LOG_HOST_NAME," @@ -937,6 +944,7 @@ std::list<TapePool> RdbmsCatalogue::getTapePools() const { pool.vo = rset.columnString("VO"); pool.nbPartialTapes = rset.columnUint64("NB_PARTIAL_TAPES"); pool.encryption = rset.columnBool("IS_ENCRYPTED"); + pool.supply = rset.columnOptionalString("SUPPLY"); pool.nbTapes = rset.columnUint64("NB_TAPES"); pool.capacityBytes = rset.columnUint64("CAPACITY_IN_BYTES"); pool.dataBytes = rset.columnUint64("DATA_IN_BYTES"); @@ -1124,6 +1132,51 @@ void RdbmsCatalogue::setTapePoolEncryption(const common::dataStructures::Securit } } +//------------------------------------------------------------------------------ +// modifyTapePoolSupply +//------------------------------------------------------------------------------ +void RdbmsCatalogue::modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &supply) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" + " string"); + } + + if(supply.empty()) { + throw UserSpecifiedAnEmptyStringSupply("Cannot modify tape pool because the new supply value is an empty" + " string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "SUPPLY = :SUPPLY," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto conn = m_connPool.getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":SUPPLY", supply); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // createArchiveRoute //------------------------------------------------------------------------------ @@ -1438,6 +1491,7 @@ void RdbmsCatalogue::modifyArchiveRouteComment(const common::dataStructures::Sec void RdbmsCatalogue::createLogicalLibrary( const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool isDisabled, const std::string &comment) { try { auto conn = m_connPool.getConn(); @@ -1449,6 +1503,7 @@ void RdbmsCatalogue::createLogicalLibrary( const char *const sql = "INSERT INTO LOGICAL_LIBRARY(" "LOGICAL_LIBRARY_NAME," + "IS_DISABLED," "USER_COMMENT," @@ -1461,6 +1516,7 @@ void RdbmsCatalogue::createLogicalLibrary( "LAST_UPDATE_TIME)" "VALUES(" ":LOGICAL_LIBRARY_NAME," + ":IS_DISABLED," ":USER_COMMENT," @@ -1474,6 +1530,7 @@ void RdbmsCatalogue::createLogicalLibrary( auto stmt = conn.createStmt(sql); stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.bindBool(":IS_DISABLED", isDisabled); stmt.bindString(":USER_COMMENT", comment); @@ -1549,6 +1606,7 @@ std::list<common::dataStructures::LogicalLibrary> RdbmsCatalogue::getLogicalLibr const char *const sql = "SELECT " "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," + "IS_DISABLED AS IS_DISABLED," "USER_COMMENT AS USER_COMMENT," @@ -1570,6 +1628,7 @@ std::list<common::dataStructures::LogicalLibrary> RdbmsCatalogue::getLogicalLibr common::dataStructures::LogicalLibrary lib; lib.name = rset.columnString("LOGICAL_LIBRARY_NAME"); + lib.isDisabled = rset.columnBool("IS_DISABLED"); lib.comment = rset.columnString("USER_COMMENT"); lib.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); lib.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); @@ -1625,6 +1684,41 @@ void RdbmsCatalogue::modifyLogicalLibraryComment(const common::dataStructures::S } } +//------------------------------------------------------------------------------ +// setLogicalLibraryDisabled +//------------------------------------------------------------------------------ +void RdbmsCatalogue::setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool disabledValue) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE LOGICAL_LIBRARY SET " + "IS_DISABLED = :IS_DISABLED," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + auto conn = m_connPool.getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindBool(":IS_DISABLED", disabledValue); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // createTape //------------------------------------------------------------------------------ @@ -4152,7 +4246,8 @@ std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getFilesForRepack "TAPE_FILE.VID = TAPE.VID " "WHERE " "TAPE_FILE.VID = :VID AND " - "TAPE_FILE.FSEQ >= :START_FSEQ " + "TAPE_FILE.FSEQ >= :START_FSEQ AND " + "TAPE_FILE.SUPERSEDED_BY_VID IS NULL " "ORDER BY FSEQ"; auto conn = m_connPool.getConn(); diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp index 44deff7e839b7bea95974ca93fc7c0f9c9b042c3..766dca01f7390bd4176adcd2e7535998b8a3431b 100644 --- a/catalogue/RdbmsCatalogue.hpp +++ b/catalogue/RdbmsCatalogue.hpp @@ -233,13 +233,14 @@ public: void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &name, const uint64_t nbCopies) override; void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &name, const std::string &comment) override; - void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::string &comment) override; + void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const cta::optional<std::string> &supply, const std::string &comment) override; void deleteTapePool(const std::string &name) override; std::list<TapePool> getTapePools() const override; void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override; void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbPartialTapes) override; void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; void setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool encryptionValue) override; + void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) override; void createArchiveRoute( const common::dataStructures::SecurityIdentity &admin, @@ -268,10 +269,11 @@ public: void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) override; void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) override; - void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; + void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool isDisabled, const std::string &comment) override; void deleteLogicalLibrary(const std::string &name) override; std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const override; void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; + virtual void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) override; /** * Creates a tape. diff --git a/catalogue/TapePool.hpp b/catalogue/TapePool.hpp index 7ca30f058e493943f219c121a38d07c4f6449f80..5de6f27e89aa695668ed74772266eb97ff9ae15a 100644 --- a/catalogue/TapePool.hpp +++ b/catalogue/TapePool.hpp @@ -23,6 +23,7 @@ #include <string> #include "common/dataStructures/EntryLog.hpp" +#include "common/optional.hpp" namespace cta { namespace catalogue { @@ -99,6 +100,11 @@ struct TapePool { */ uint64_t nbPhysicalFiles; + /** + * Optional value used by the tape pool supply mechanism. + */ + cta::optional<std::string> supply; + /** * The creation log. */ diff --git a/catalogue/UserSpecifiedAnEmptyStringSupply.cpp b/catalogue/UserSpecifiedAnEmptyStringSupply.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dee220acbdda2094afaba2686ae51321d11264c1 --- /dev/null +++ b/catalogue/UserSpecifiedAnEmptyStringSupply.cpp @@ -0,0 +1,39 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "catalogue/UserSpecifiedAnEmptyStringSupply.hpp" + +namespace cta { +namespace catalogue { + + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +UserSpecifiedAnEmptyStringSupply::UserSpecifiedAnEmptyStringSupply(const std::string &context, + const bool embedBacktrace): cta::exception::UserError(context, embedBacktrace) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +UserSpecifiedAnEmptyStringSupply::~UserSpecifiedAnEmptyStringSupply() { +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/UserSpecifiedAnEmptyStringSupply.hpp b/catalogue/UserSpecifiedAnEmptyStringSupply.hpp new file mode 100644 index 0000000000000000000000000000000000000000..12803e2c96497cf8af9e850831a3f0aefe8f1796 --- /dev/null +++ b/catalogue/UserSpecifiedAnEmptyStringSupply.hpp @@ -0,0 +1,48 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "common/exception/UserError.hpp" + +namespace cta { +namespace catalogue { + +/** + * User specified an empty string for a supply value when this is not permitted. + */ +class UserSpecifiedAnEmptyStringSupply: public exception::UserError { +public: + /** + * Constructor. + * + * @param context optional context string added to the message + * at initialisation time. + * @param embedBacktrace whether to embed a backtrace of where the + * exception was throw in the message + */ + UserSpecifiedAnEmptyStringSupply(const std::string &context = "", const bool embedBacktrace = true); + + /** + * Destructor. + */ + ~UserSpecifiedAnEmptyStringSupply() override; +}; // class UserSpecifiedAnEmptyStringSupply + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/common_catalogue_schema.sql b/catalogue/common_catalogue_schema.sql index 26468f8986bfa91a51928f06264fabe68e04ce31..e37a2d5022b9a3b87d071002acff2f1171485b29 100644 --- a/catalogue/common_catalogue_schema.sql +++ b/catalogue/common_catalogue_schema.sql @@ -33,6 +33,7 @@ CREATE TABLE TAPE_POOL( VO VARCHAR(100) CONSTRAINT TAPE_POOL_VO_NN NOT NULL, NB_PARTIAL_TAPES NUMERIC(20, 0) CONSTRAINT TAPE_POOL_NPT_NN NOT NULL, IS_ENCRYPTED CHAR(1) CONSTRAINT TAPE_POOL_IE_NN NOT NULL, + SUPPLY VARCHAR(100), USER_COMMENT VARCHAR(1000) CONSTRAINT TAPE_POOL_UC_NN NOT NULL, CREATION_LOG_USER_NAME VARCHAR(100) CONSTRAINT TAPE_POOL_CLUN_NN NOT NULL, CREATION_LOG_HOST_NAME VARCHAR(100) CONSTRAINT TAPE_POOL_CLHN_NN NOT NULL, @@ -62,6 +63,7 @@ CREATE TABLE ARCHIVE_ROUTE( ); CREATE TABLE LOGICAL_LIBRARY( LOGICAL_LIBRARY_NAME VARCHAR(100) CONSTRAINT LOGICAL_LIBRARY_LLL_NN NOT NULL, + IS_DISABLED CHAR(1) DEFAULT '0' CONSTRAINT LOGICAL_LIBRARY_ID_NN NOT NULL, USER_COMMENT VARCHAR(1000) CONSTRAINT LOGICAL_LIBRARY_UC_NN NOT NULL, CREATION_LOG_USER_NAME VARCHAR(100) CONSTRAINT LOGICAL_LIBRARY_CLUN_NN NOT NULL, CREATION_LOG_HOST_NAME VARCHAR(100) CONSTRAINT LOGICAL_LIBRARY_CLHN_NN NOT NULL, @@ -69,7 +71,8 @@ CREATE TABLE LOGICAL_LIBRARY( LAST_UPDATE_USER_NAME VARCHAR(100) CONSTRAINT LOGICAL_LIBRARY_LUUN_NN NOT NULL, LAST_UPDATE_HOST_NAME VARCHAR(100) CONSTRAINT LOGICAL_LIBRARY_LUHN_NN NOT NULL, LAST_UPDATE_TIME NUMERIC(20, 0) CONSTRAINT LOGICAL_LIBRARY_LUT_NN NOT NULL, - CONSTRAINT LOGICAL_LIBRARY_PK PRIMARY KEY(LOGICAL_LIBRARY_NAME) + CONSTRAINT LOGICAL_LIBRARY_PK PRIMARY KEY(LOGICAL_LIBRARY_NAME), + CONSTRAINT LOGICAL_LIBRARY_ID_BOOL_CK CHECK(IS_DISABLED IN ('0', '1')) ); CREATE TABLE TAPE( VID VARCHAR(100) CONSTRAINT TAPE_V_UN NOT NULL, @@ -89,8 +92,8 @@ CREATE TABLE TAPE( LAST_READ_TIME NUMERIC(20, 0), LAST_WRITE_DRIVE VARCHAR(100), LAST_WRITE_TIME NUMERIC(20, 0), - READ_MOUNT_COUNT NUMERIC(20, 0) DEFAULT 0, - WRITE_MOUNT_COUNT NUMERIC(20, 0) DEFAULT 0, + READ_MOUNT_COUNT NUMERIC(20, 0) DEFAULT 0 CONSTRAINT TAPE_RMC_NN NOT NULL, + WRITE_MOUNT_COUNT NUMERIC(20, 0) DEFAULT 0 CONSTRAINT TAPE_WMC_NN NOT NULL, USER_COMMENT VARCHAR(1000) CONSTRAINT TAPE_UC_UN NOT NULL, CREATION_LOG_USER_NAME VARCHAR(100) CONSTRAINT TAPE_CLUN_UN NOT NULL, CREATION_LOG_HOST_NAME VARCHAR(100) CONSTRAINT TAPE_CLHN_UN NOT NULL, @@ -180,7 +183,7 @@ CREATE TABLE TAPE_FILE( CREATION_TIME NUMERIC(20, 0) CONSTRAINT TAPE_FILE_CT_NN NOT NULL, ARCHIVE_FILE_ID NUMERIC(20, 0) CONSTRAINT TAPE_FILE_AFI_NN NOT NULL, SUPERSEDED_BY_VID VARCHAR(100), - SUPERSEDED_BY_FSEQ INTEGER, + SUPERSEDED_BY_FSEQ NUMERIC(20, 0), CONSTRAINT TAPE_FILE_PK PRIMARY KEY(VID, FSEQ), CONSTRAINT TAPE_FILE_TAPE_FK FOREIGN KEY(VID) REFERENCES TAPE(VID), @@ -188,7 +191,7 @@ CREATE TABLE TAPE_FILE( REFERENCES ARCHIVE_FILE(ARCHIVE_FILE_ID), CONSTRAINT TAPE_FILE_VID_BLOCK_ID_UN UNIQUE(VID, BLOCK_ID), CONSTRAINT TAPE_FILE_COPY_NB_GT_ZERO CHECK(COPY_NB > 0), - CONSTRAINT TAPE_FILE_SS_VID_FSEQ FOREIGN KEY(SUPERSEDED_BY_VID, SUPERSEDED_BY_FSEQ) + CONSTRAINT TAPE_FILE_SS_VID_FSEQ_FK FOREIGN KEY(SUPERSEDED_BY_VID, SUPERSEDED_BY_FSEQ) REFERENCES TAPE_FILE(VID, FSEQ) ); CREATE INDEX TAPE_FILE_VID_IDX ON TAPE_FILE(VID); diff --git a/catalogue/mysql_catalogue_schema_trigger.sql b/catalogue/mysql_catalogue_schema_trigger.sql index 694c27a8800727de03dd306bee20cd9670a4418f..16ac8b0277bac899c3bf6f0ebf86dec36d43753a 100644 --- a/catalogue/mysql_catalogue_schema_trigger.sql +++ b/catalogue/mysql_catalogue_schema_trigger.sql @@ -78,7 +78,20 @@ CREATE TRIGGER `TAPE_FILE_COPY_NB_GT_ZERO_BEFORE_UPDATE` BEFORE UPDATE ON `TAPE_ END IF; END; +CREATE TRIGGER `CHECK_LOGICAL_LIBRARY_BEFORE_INSERT` BEFORE INSERT ON `LOGICAL_LIBRARY` + FOR EACH ROW + BEGIN + IF new.IS_DISABLED not in ('0','1') THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'LOGICAL_LIBRARY.IS_DISABLED should be 0 or 1'; + END IF; + END; - - - +CREATE TRIGGER `CHECK_LOGICAL_LIBRARY_BEFORE_UPDATE` BEFORE UPDATE ON `LOGICAL_LIBRARY` + FOR EACH ROW + BEGIN + IF new.IS_DISABLED not in ('0','1') THEN + SIGNAL SQLSTATE '45000' + SET MESSAGE_TEXT = 'LOGICAL_LIBRARY.IS_DISABLED should be 0 or 1'; + END IF; + END; diff --git a/cmdline/CtaAdminCmd.cpp b/cmdline/CtaAdminCmd.cpp index 6cd287a263c1006748a2a3b2ba16a67acea95e38..338e2a25083fd2df654a64e461716522ecd139c6 100644 --- a/cmdline/CtaAdminCmd.cpp +++ b/cmdline/CtaAdminCmd.cpp @@ -646,6 +646,7 @@ void CtaAdminCmd::printTpLsHeader() << std::setfill(' ') << std::setw(6) << std::right << "avail" << ' ' << std::setfill(' ') << std::setw(6) << std::right << "use%" << ' ' << std::setfill(' ') << std::setw(8) << std::right << "encrypt" << ' ' + << std::setfill(' ') << std::setw(20) << std::right << "supply" << ' ' << std::setfill(' ') << std::setw(8) << std::right << "c.user" << ' ' << std::setfill(' ') << std::setw(25) << std::right << "c.host" << ' ' << std::setfill(' ') << std::setw(24) << std::right << "c.time" << ' ' @@ -748,6 +749,7 @@ void CtaAdminCmd::print(const cta::admin::TapePoolLsItem &tpls_item) << std::setfill(' ') << std::setw(5) << std::right << avail / 1000000000 << "G " << std::setfill(' ') << std::setw(5) << std::right << std::fixed << std::setprecision(1) << use_percent << "% " << std::setfill(' ') << std::setw(8) << std::right << encrypt_str << ' ' + << std::setfill(' ') << std::setw(20) << std::right << tpls_item.supply() << ' ' << std::setfill(' ') << std::setw(8) << std::right << tpls_item.created().username() << ' ' << std::setfill(' ') << std::setw(25) << std::right << tpls_item.created().host() << ' ' << std::setfill(' ') << std::setw(24) << std::right << timeToString(tpls_item.created().time()) << ' ' diff --git a/cmdline/CtaAdminCmdParse.hpp b/cmdline/CtaAdminCmdParse.hpp index 11ef3897eb5ab19ec0e1bc013885cf8130a080a0..20d4fa207729ca14577dcc7dfce3efdaa320ff03 100644 --- a/cmdline/CtaAdminCmdParse.hpp +++ b/cmdline/CtaAdminCmdParse.hpp @@ -302,6 +302,7 @@ const std::map<std::string, OptionString::Key> strOptions = { { "--owner", OptionString::OWNER }, { "--path", OptionString::PATH }, { "--storageclass", OptionString::STORAGE_CLASS }, + { "--supply", OptionString::SUPPLY }, { "--tapepool", OptionString::TAPE_POOL }, { "--username", OptionString::USERNAME }, { "--vendor", OptionString::VENDOR }, @@ -408,6 +409,7 @@ const Option opt_storageclass { Option::OPT_STR, "--storageclass", const Option opt_storageclass_alias { Option::OPT_STR, "--name", "-n", " <storage_class_name>", "--storageclass" }; const Option opt_summary { Option::OPT_FLAG, "--summary", "-S", "" }; +const Option opt_supply { Option::OPT_STR, "--supply", "-s", " <supply_value>" }; const Option opt_tapepool { Option::OPT_STR, "--tapepool", "-t", " <tapepool_name>" }; const Option opt_tapepool_alias { Option::OPT_STR, "--name", "-n", " <tapepool_name>", "--tapepool" }; @@ -469,8 +471,10 @@ const std::map<cmd_key_t, cmd_val_t> cmdOptions = { {{ AdminCmd::CMD_LISTPENDINGRETRIEVES, AdminCmd::SUBCMD_NONE }, { opt_header.optional(), opt_vid.optional(), opt_extended.optional() }}, /*----------------------------------------------------------------------------------------------------*/ - {{ AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_ADD }, { opt_logicallibrary_alias, opt_comment }}, - {{ AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_CH }, { opt_logicallibrary_alias, opt_comment }}, + {{ AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_ADD }, + { opt_logicallibrary_alias, opt_disabled.optional(), opt_comment }}, + {{ AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_CH }, + { opt_logicallibrary_alias, opt_disabled.optional(), opt_comment.optional() }}, {{ AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_RM }, { opt_logicallibrary_alias }}, {{ AdminCmd::CMD_LOGICALLIBRARY, AdminCmd::SUBCMD_LS }, { opt_header.optional() }}, /*----------------------------------------------------------------------------------------------------*/ @@ -523,9 +527,10 @@ const std::map<cmd_key_t, cmd_val_t> cmdOptions = { { opt_vid, opt_force.optional(), opt_lbp.optional() }}, /*----------------------------------------------------------------------------------------------------*/ {{ AdminCmd::CMD_TAPEPOOL, AdminCmd::SUBCMD_ADD }, - { opt_tapepool_alias, opt_vo, opt_partialtapes, opt_encrypted, opt_comment }}, + { opt_tapepool_alias, opt_vo, opt_partialtapes, opt_encrypted, opt_supply.optional(), opt_comment }}, {{ AdminCmd::CMD_TAPEPOOL, AdminCmd::SUBCMD_CH }, - { opt_tapepool_alias, opt_vo.optional(), opt_partialtapes.optional(), opt_encrypted.optional(), opt_comment.optional() }}, + { opt_tapepool_alias, opt_vo.optional(), opt_partialtapes.optional(), opt_encrypted.optional(), + opt_supply.optional(), opt_comment.optional() }}, {{ AdminCmd::CMD_TAPEPOOL, AdminCmd::SUBCMD_RM }, { opt_tapepool_alias }}, {{ AdminCmd::CMD_TAPEPOOL, AdminCmd::SUBCMD_LS }, { opt_header.optional() }}, }; diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 6e36d11b42b64b812a598fdc56fd5f6118a8a235..cac4940c7d4f676c836f2ce81f6b685080f50330 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -166,6 +166,7 @@ set (COMMON_UNIT_TESTS_LIB_SRC_FILES ConfigurationFileTests.cpp SourcedParameterTests.cpp dataStructures/ArchiveFileTest.cpp + dataStructures/LogicalLibraryTest.cpp dataStructures/StorageClassTest.cpp processCap/SmartCapTest.cpp log/FileLoggerTest.cpp diff --git a/common/dataStructures/LogicalLibrary.cpp b/common/dataStructures/LogicalLibrary.cpp index 1e6efaf6fb4562e3ded9f08eb586aa36987baffc..339ad78da4e2adba8ffd4cf91d1fc1c40de11344 100644 --- a/common/dataStructures/LogicalLibrary.cpp +++ b/common/dataStructures/LogicalLibrary.cpp @@ -27,7 +27,8 @@ namespace dataStructures { //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -LogicalLibrary::LogicalLibrary() {} +LogicalLibrary::LogicalLibrary(): isDisabled(false) { +} //------------------------------------------------------------------------------ // operator== diff --git a/common/dataStructures/LogicalLibrary.hpp b/common/dataStructures/LogicalLibrary.hpp index 8ab20e4334022158a147f47af91c3fff049dc66b..6a70f7c2e8d855829d74f405426e85f6721abc0b 100644 --- a/common/dataStructures/LogicalLibrary.hpp +++ b/common/dataStructures/LogicalLibrary.hpp @@ -35,6 +35,11 @@ namespace dataStructures { */ struct LogicalLibrary { + /** + * Constructor. + * + * Initialises isDisabled to false. + */ LogicalLibrary(); bool operator==(const LogicalLibrary &rhs) const; @@ -42,6 +47,7 @@ struct LogicalLibrary { bool operator!=(const LogicalLibrary &rhs) const; std::string name; + bool isDisabled; EntryLog creationLog; EntryLog lastModificationLog; std::string comment; diff --git a/common/dataStructures/LogicalLibraryTest.cpp b/common/dataStructures/LogicalLibraryTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88117c709096161b481c5efa4d93f206d3cccc00 --- /dev/null +++ b/common/dataStructures/LogicalLibraryTest.cpp @@ -0,0 +1,43 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "common/dataStructures/LogicalLibrary.hpp" + +#include <gtest/gtest.h> +#include <algorithm> + +namespace unitTests { + +class cta_common_dataStructures_LogicalLibraryTest : public ::testing::Test { +protected: + + virtual void SetUp() { + } + + virtual void TearDown() { + } +}; + +TEST_F(cta_common_dataStructures_LogicalLibraryTest, constructor) { + using namespace cta::common::dataStructures; + + LogicalLibrary logicalLibrary; + ASSERT_FALSE(logicalLibrary.isDisabled); +} + +} // namespace unitTests diff --git a/common/exception/Backtrace.cpp b/common/exception/Backtrace.cpp index 6561aabfe5ae4a1dc4ac96ce52d893323c66c1de..bdbf67bcdace96c00f0516404a0b904e703fe661 100644 --- a/common/exception/Backtrace.cpp +++ b/common/exception/Backtrace.cpp @@ -117,7 +117,6 @@ cta::exception::Backtrace::Backtrace(bool fake): m_trace() { void * array[200]; g_lock.lock(); size_t depth = ::backtrace(array, sizeof(array)/sizeof(void*)); - g_lock.unlock(); char ** strings = ::backtrace_symbols(array, depth); if (!strings) @@ -158,6 +157,7 @@ cta::exception::Backtrace::Backtrace(bool fake): m_trace() { } free (strings); } + g_lock.unlock(); } /* Implementation of the singleton lock */ diff --git a/common/utils/UtilsTest.cpp b/common/utils/UtilsTest.cpp index 2f30fc2c37ab2ab1c0f48c9fa479689e3bc8a467..e3f1f0b0c2db0def7395f95a59f1c3907c6f9581 100644 --- a/common/utils/UtilsTest.cpp +++ b/common/utils/UtilsTest.cpp @@ -429,7 +429,7 @@ TEST_F(cta_UtilsTest, toGid_too_big) { ASSERT_THROW(utils::toGid(oss.str()), std::exception); } -TEST_F(cta_UtilsTest, isValidUInt_unsigned_int) { +TEST_F(cta_UtilsTest, isValidUInt) { using namespace cta; ASSERT_TRUE(utils::isValidUInt("12345")); @@ -441,7 +441,7 @@ TEST_F(cta_UtilsTest, isValidUInt_empty_string) { ASSERT_FALSE(utils::isValidUInt("")); } -TEST_F(cta_UtilsTest, isValidUInt_signed_int) { +TEST_F(cta_UtilsTest, isValidUInt_negative) { using namespace cta; ASSERT_FALSE(utils::isValidUInt("-12345")); @@ -453,7 +453,7 @@ TEST_F(cta_UtilsTest, isValidUInt_not_a_number) { ASSERT_FALSE(utils::isValidUInt("one")); } -TEST_F(cta_UtilsTest, toUint64_unsigned_int) { +TEST_F(cta_UtilsTest, toUint64) { using namespace cta; ASSERT_EQ((uint64_t)12345, utils::toUint64("12345")); @@ -484,6 +484,67 @@ TEST_F(cta_UtilsTest, toUint64_not_a_number) { ASSERT_THROW(utils::toUint64("one"), exception::Exception); } +TEST_F(cta_UtilsTest, isValidDecimal) { + using namespace cta; + + ASSERT_TRUE(utils::isValidDecimal("1.234")); +} + +TEST_F(cta_UtilsTest, isValidDecimal_empty_string) { + using namespace cta; + + ASSERT_FALSE(utils::isValidDecimal("")); +} + +TEST_F(cta_UtilsTest, isValidDecimal_negative_double) { + using namespace cta; + + ASSERT_TRUE(utils::isValidDecimal("-1.234")); +} + +TEST_F(cta_UtilsTest, isValidDecimal_not_a_number) { + using namespace cta; + + ASSERT_FALSE(utils::isValidDecimal("one")); +} + +TEST_F(cta_UtilsTest, isValidDecimal_two_decimal_points) { + using namespace cta; + + ASSERT_FALSE(utils::isValidDecimal("1.2.34")); +} + +TEST_F(cta_UtilsTest, toDouble_double) { + using namespace cta; + + ASSERT_EQ((double)1.234, utils::toDouble("1.234")); +} + +TEST_F(cta_UtilsTest, toDouble_negative_double) { + using namespace cta; + + ASSERT_EQ((double)-1.234, utils::toDouble("-1.234")); +} + +TEST_F(cta_UtilsTest, toDouble_too_big) { + using namespace cta; + + // std::numeric_limits<double>::max=1.79769e+308 + ASSERT_THROW(utils::toDouble("1.79770e+308"), exception::Exception); +} + +TEST_F(cta_UtilsTest, toDouble_empty_string) { + using namespace cta; + + ASSERT_THROW(utils::toDouble(""), exception::Exception); +} + +TEST_F(cta_UtilsTest, toDouble_not_a_number) { + using namespace cta; + + ASSERT_THROW(utils::toDouble("one"), exception::Exception); +} + TEST_F(cta_UtilsTest, adler32_empty_buf) { using namespace cta; @@ -683,4 +744,16 @@ TEST_F(cta_UtilsTest, DISABLED_currentTime) { std::cout << getCurrentLocalTime() << std::endl; } +TEST_F(cta_UtilsTest, searchAndReplace) { + using namespace cta::utils; + + std::string str = "one two three four one two three four"; + const std::string search = "two"; + const std::string replacement = "replacement"; + + searchAndReplace(str, search, replacement); + + ASSERT_EQ("one replacement three four one replacement three four", str); +} + } // namespace unitTests diff --git a/common/utils/utils.cpp b/common/utils/utils.cpp index 5a764b31d1f5cb05df255551d9c7a3bc96883d87..ac4d0221b54919fcc6c2965ce87f42318a194d7c 100644 --- a/common/utils/utils.cpp +++ b/common/utils/utils.cpp @@ -626,7 +626,7 @@ uint64_t toUint64(const std::string &str) { try { return std::stoul(str); } catch(std::invalid_argument &) { - throw exception::Exception("Invalid string"); + throw exception::Exception("Invalid uint64"); } catch(std::out_of_range &) { throw exception::Exception("Out of range"); } catch(std::exception &se) { @@ -638,6 +638,61 @@ uint64_t toUint64(const std::string &str) { } } +//------------------------------------------------------------------------------ +// isValidDecimal +//------------------------------------------------------------------------------ +bool isValidDecimal(const std::string &str) { + // An empty string is not a valid decimal + if(str.empty()) { + return false; + } + + uint64_t nbDecimalPoints = 0; + + // For each character in the string + for(std::string::const_iterator itor = str.begin(); itor != str.end(); itor++) { + + const bool isFirstChar = itor == str.begin(); + const bool isMinusChar = '-' == *itor; + const bool isANumericalDigit = '0' <= *itor && *itor <= '9'; + const bool isADecimalPoint = '.' == *itor; + + if(!(isFirstChar && isMinusChar) && !isANumericalDigit && !isADecimalPoint) { + return false; + } + + if(isADecimalPoint) { + nbDecimalPoints++; + } + + if(1 < nbDecimalPoints) { + return false; + } + } + + return true; +} + +//------------------------------------------------------------------------------ +// toDouble +//------------------------------------------------------------------------------ +double toDouble(const std::string &str) { + try { + try { + return std::stod(str); + } catch(std::invalid_argument &) { + throw exception::Exception("Invalid double"); + } catch(std::out_of_range &) { + throw exception::Exception("Out of range"); + } catch(std::exception &se) { + throw exception::Exception(se.what()); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string("Failed to parse ") + str + " as a double: " + + ex.getMessage().str()); + } +} + //------------------------------------------------------------------------------ // toUpper //------------------------------------------------------------------------------ @@ -799,5 +854,23 @@ std::string extractPathFromXrootdPath(const std::string& path){ return std::string(urlInfo.File.c_str()); } +//------------------------------------------------------------------------------ +// searchAndReplace +//------------------------------------------------------------------------------ +void searchAndReplace(std::string &str, const std::string &search, const std::string replacement) { + std::string::size_type pos = 0; + while(std::string::npos != (pos = str.find(search, pos))) { + str.replace(pos, search.length(), replacement); + pos += replacement.length(); + } +} + +//------------------------------------------------------------------------------ +// segfault +//------------------------------------------------------------------------------ +void segfault() { + *((int *)nullptr) = 0; +} + } // namespace utils } // namespace cta diff --git a/common/utils/utils.hpp b/common/utils/utils.hpp index bb6bf0dac4749fe30dd3d3323392212cc3983472..d56e933011cd61dced8dd996b878c369a50cba36 100644 --- a/common/utils/utils.hpp +++ b/common/utils/utils.hpp @@ -280,6 +280,21 @@ namespace utils { */ uint64_t toUint64(const std::string &str); + /** + * Checks if the specified string is a valid decimal. + * + * @param str The string to be checked. + * @returns true if the string is a valid decimal, else false. + */ + bool isValidDecimal(const std::string &str); + + /** + * Parses the specified string representation of a double. + * + * @return The parsed double. + */ + double toDouble(const std::string &str); + /** * Converts the specified string to uppercase. * @@ -379,6 +394,22 @@ namespace utils { */ std::string extractPathFromXrootdPath(const std::string &path); + /** + * Performs a search and replace operation on the specified string. + * + * @param str In/out parameter which is the string to be modified. + * @param search The search string. + * @param replacement The replacement string. + */ + void searchAndReplace(std::string &str, const std::string &search, const std::string replacement); + + /** + * Willful segmentation violation (accessing nullptr) ensuring the process will stop hard. + * This is different from self-killing the process as the signal delivery is not immediate. + * Here, the CPU will interrupt the process with a memory protection error. + */ + void segfault(void); + } // namespace utils } // namespace cta diff --git a/continuousintegration/docker/ctafrontend/cc7/buildtree-stage1-rpms/Dockerfile b/continuousintegration/docker/ctafrontend/cc7/buildtree-stage1-rpms/Dockerfile index fb8fb133bcb84e5ffcc9defa12246fdcb9005d95..302dd30ac76cf1b563e5bb6c400f9473cf718f68 100644 --- a/continuousintegration/docker/ctafrontend/cc7/buildtree-stage1-rpms/Dockerfile +++ b/continuousintegration/docker/ctafrontend/cc7/buildtree-stage1-rpms/Dockerfile @@ -95,6 +95,7 @@ RUN yum-config-manager --enable epel --setopt="epel.priority=4" \ hiredis \ jsoncpp \ libmicrohttpd \ + jq \ && \ yum clean all \ && \ diff --git a/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list b/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list index 8a35ba63050da8b3ebb9656c79c123c45793caf7..ef96601fc643bd62754bc4f2a4cfeadb7f9566e9 100644 --- a/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list +++ b/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list @@ -1,17 +1,17 @@ -0:eos-archive-4.4.45-3.el7.cern.x86_64 -0:eos-cleanup-4.4.45-3.el7.cern.x86_64 -0:eos-client-4.4.45-3.el7.cern.x86_64 -0:eos-debuginfo-4.4.45-3.el7.cern.x86_64 -0:eos-fuse-4.4.45-3.el7.cern.x86_64 -0:eos-fuse-core-4.4.45-3.el7.cern.x86_64 -0:eos-fuse-sysv-4.4.45-3.el7.cern.x86_64 -0:eos-fusex-4.4.45-3.el7.cern.x86_64 -0:eos-fusex-core-4.4.45-3.el7.cern.x86_64 -0:eos-fusex-selinux-4.4.45-3.el7.cern.x86_64 -0:eos-server-4.4.45-3.el7.cern.x86_64 -0:eos-srm-4.4.45-3.el7.cern.x86_64 -0:eos-test-4.4.45-3.el7.cern.x86_64 -0:eos-testkeytab-4.4.45-3.el7.cern.x86_64 +0:eos-archive-4.4.47-1.el7.cern.x86_64 +0:eos-cleanup-4.4.47-1.el7.cern.x86_64 +0:eos-client-4.4.47-1.el7.cern.x86_64 +0:eos-debuginfo-4.4.47-1.el7.cern.x86_64 +0:eos-fuse-4.4.47-1.el7.cern.x86_64 +0:eos-fuse-core-4.4.47-1.el7.cern.x86_64 +0:eos-fuse-sysv-4.4.47-1.el7.cern.x86_64 +0:eos-fusex-4.4.47-1.el7.cern.x86_64 +0:eos-fusex-core-4.4.47-1.el7.cern.x86_64 +0:eos-fusex-selinux-4.4.47-1.el7.cern.x86_64 +0:eos-server-4.4.47-1.el7.cern.x86_64 +0:eos-srm-4.4.47-1.el7.cern.x86_64 +0:eos-test-4.4.47-1.el7.cern.x86_64 +0:eos-testkeytab-4.4.47-1.el7.cern.x86_64 1:python2-xrootd-4.9.1-1.el7.* 1:python3-xrootd-4.9.1-1.el7.* 1:xrootd-4.9.1-1.el7.* diff --git a/continuousintegration/docker/ctafrontend/cc7/opt/run/bin/client.sh b/continuousintegration/docker/ctafrontend/cc7/opt/run/bin/client.sh index 436a27a79e7c6275db061250a9923a4d02d82ff8..05325855de7ff37c0c4bac8d7a044f164fee4e23 100755 --- a/continuousintegration/docker/ctafrontend/cc7/opt/run/bin/client.sh +++ b/continuousintegration/docker/ctafrontend/cc7/opt/run/bin/client.sh @@ -7,10 +7,7 @@ if [ ! -e /etc/buildtreeRunner ]; then yum-config-manager --enable ceph # Install missing RPMs - yum -y install cta-cli cta-debuginfo xrootd-client eos-client - - # Install needed tools for CI testing - yum install -y jq + yum -y install cta-cli cta-debuginfo xrootd-client eos-client jq ## Keep this temporary fix that may be needed if going to protobuf3-3.5.1 for CTA # Install eos-protobuf3 separately as eos is OK with protobuf3 but cannot use it.. diff --git a/continuousintegration/orchestration/delete_instance.sh b/continuousintegration/orchestration/delete_instance.sh index 5e0ca804370cc2546db5d39ba76e8cdad9b58c23..95ce1c489b706aa488c62041c1feb255e9baf81d 100755 --- a/continuousintegration/orchestration/delete_instance.sh +++ b/continuousintegration/orchestration/delete_instance.sh @@ -71,7 +71,7 @@ if [ $collectlogs == 1 ] ; then for podcontainer in "init -c ctainit" "client -c client" "ctacli -c ctacli" "ctaeos -c mgm" "ctafrontend -c ctafrontend" "kdc -c kdc" "tpsrv01 -c taped" "tpsrv01 -c rmcd" "tpsrv02 -c taped" "tpsrv02 -c rmcd"; do kubectl --namespace ${instance} logs ${podcontainer} > ${tmpdir}/$(echo ${podcontainer} | sed -e 's/ -c /-/').log done - kubectl --namespace ${instance} exec ctacli -- tar -C /mnt/logs -zcf - . > ${tmpdir}/varlog.tgz + kubectl --namespace ${instance} exec ctacli -- bash -c "XZ_OPT='-0 -T0' tar -C /mnt/logs -Jcf - ." > ${tmpdir}/varlog.tar.xz if [ ! -z "${CI_PIPELINE_ID}" ]; then # we are in the context of a CI run => save artifacts in the directory structure of the build diff --git a/continuousintegration/orchestration/tests/archive_retrieve.sh b/continuousintegration/orchestration/tests/archive_retrieve.sh index bfb8e1ab7f05da45452dbb349ea318ce1124ca9d..4bca61163ae358fd2f18a0b24765fad5d2f77962 100755 --- a/continuousintegration/orchestration/tests/archive_retrieve.sh +++ b/continuousintegration/orchestration/tests/archive_retrieve.sh @@ -41,9 +41,6 @@ kubectl -n ${NAMESPACE} exec client -- bash /root/simple_client_ar.sh || exit 1 kubectl -n ${NAMESPACE} cp grep_xrdlog_mgm_for_error.sh ctaeos:/root/grep_xrdlog_mgm_for_error.sh kubectl -n ${NAMESPACE} exec ctaeos -- bash /root/grep_xrdlog_mgm_for_error.sh || exit 1 -echo -./simple_repack.sh -n ${NAMESPACE} || exit 1 - NB_FILES=10000 FILE_SIZE_KB=15 diff --git a/continuousintegration/orchestration/tests/client_ar.sh b/continuousintegration/orchestration/tests/client_ar.sh index 5cb4c82bad0a538da7abc79a4f1d7c91b8cc2972..83f1c8618ee9df0cf834e2894b98349f69a60502 100644 --- a/continuousintegration/orchestration/tests/client_ar.sh +++ b/continuousintegration/orchestration/tests/client_ar.sh @@ -292,7 +292,7 @@ RETRIEVED=0 echo "$(date +%s): Waiting for files to be back on disk:" SECONDS_PASSED=0 WAIT_FOR_RETRIEVED_FILE_TIMEOUT=$((40+${NB_FILES}/5)) -while test 0 != ${RETRIEVING}; do +while test 0 -lt ${RETRIEVING}; do echo "$(date +%s): Waiting for files to be retrieved from tape: Seconds passed = ${SECONDS_PASSED}" sleep 3 let SECONDS_PASSED=SECONDS_PASSED+1 diff --git a/continuousintegration/orchestration/tests/repack_systemtest.sh b/continuousintegration/orchestration/tests/repack_systemtest.sh index 8928d3426cbbb5891c62648b23cb7b6912a88840..306ef4cf0028644134257af006d0e0e0c8b0b58f 100755 --- a/continuousintegration/orchestration/tests/repack_systemtest.sh +++ b/continuousintegration/orchestration/tests/repack_systemtest.sh @@ -21,23 +21,12 @@ exit 1 } testRepackBufferURL(){ - echo "Creating the repack buffer URL at root://${EOSINSTANCE}/${REPACK_BUFFER_BASEDIR}" + echo "Testing the repack buffer URL at root://${EOSINSTANCE}/${REPACK_BUFFER_BASEDIR}" eos root://${EOSINSTANCE} ls -d ${REPACK_BUFFER_BASEDIR} || die "Repack bufferURL directory does not exist" echo "Testing the insertion of a test file in the buffer URL" - for ((i=0; i<300; i++)); do - xrdcp /etc/group ${FULL_REPACK_BUFFER_URL}/testFile && break - echo -n "." - sleep 1 - done - echo OK - failed_xrdcp_test=$i - if test $failed_xrdcp_test -eq 0; then - echo "[SUCCESS]: Repack buffer URL OK" | tee -a /var/log/CI_tests - echo "Removing the test file" - eos root://${EOSINSTANCE} rm ${REPACK_BUFFER_BASEDIR}/testFile - else - echo "[ERROR]: Unable to write a file into the provided repack buffer URL." | tee -a /var/log/CI_tests - fi + tempFilePath=$(mktemp /tmp/testFile.XXXX) + tempFileName=${tempFilePath##*/} + xrdcp ${tempFilePath} ${FULL_REPACK_BUFFER_URL}/${tempFileName} || die "Unable to write a file into the repack buffer directory" echo "OK" } @@ -82,19 +71,17 @@ fi # Get kerberos credentials for user1 admin_kinit -klist -s || die "Cannot get kerberos credentials for user ${USER}" - -# Get kerberos credentials for poweruser1 -eospower_kdestroy -eospower_kinit +admin_klist > /dev/null 2>&1 || die "Cannot get kerberos credentials for user ${USER}" -echo "Testing the repackBufferURL provided" FULL_REPACK_BUFFER_URL=root://${EOSINSTANCE}/${REPACK_BUFFER_BASEDIR} testRepackBufferURL echo "Deleting existing repack request for VID ${VID_TO_REPACK}" admin_cta repack rm --vid ${VID_TO_REPACK} +echo "Marking the tape ${VID_TO_REPACK} as full before Repacking it" +admin_cta tape ch --vid ${VID_TO_REPACK} --full true + echo "State of the tape VID ${VID_TO_REPACK} BEFORE repack" admin_cta --json tape ls --vid ${VID_TO_REPACK} | jq . diff --git a/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh b/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh index cbf9adf476fa22399eb234196eeec8a561da1797..fe31c8ce4223115bdbb3523e4775ac1b9acd37c3 100755 --- a/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh +++ b/continuousintegration/orchestration/tests/repack_systemtest_wrapper.sh @@ -30,7 +30,7 @@ fi echo "Preparing namespace for the tests" ./prepare_tests.sh -n ${NAMESPACE} -NB_FILES=1000 +NB_FILES=1 FILE_SIZE_KB=15 kubectl -n ${NAMESPACE} cp client_helper.sh client:/root/client_helper.sh @@ -50,14 +50,46 @@ kubectl -n ${NAMESPACE} exec ctaeos -- eos chmod 1777 ${REPACK_BUFFER_URL} source ./repack_helper.sh kubectl -n ${NAMESPACE} cp repack_systemtest.sh client:/root/repack_systemtest.sh +echo +echo "Launching a round trip repack request" + +VID_TO_REPACK=$(getFirstVidContainingFiles) +if [ "$VID_TO_REPACK" != "null" ] +then +echo + echo "Launching the repack test on VID ${VID_TO_REPACK}" + kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${VID_TO_REPACK} -b ${REPACK_BUFFER_URL} || exit 1 +else + echo "No vid found to repack" + exit 1 +fi + +echo "Reclaiming tape ${VID_TO_REPACK}" +kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape reclaim --vid ${VID_TO_REPACK} + +VID_TO_REPACK=$(getFirstVidContainingFiles) +if [ "$VID_TO_REPACK" != "null" ] +then +echo + echo "Launching the repack test on VID ${VID_TO_REPACK}" + kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${VID_TO_REPACK} -b ${REPACK_BUFFER_URL} || exit 1 +else + echo "No vid found to repack" + exit 1 +fi + +echo "Reclaiming tape ${VID_TO_REPACK}" +kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape reclaim --vid ${VID_TO_REPACK} + +NB_FILES=1152 +kubectl -n ${NAMESPACE} exec client -- bash /root/client_ar.sh -n ${NB_FILES} -s ${FILE_SIZE_KB} -p 100 -d /eos/ctaeos/preprod -v -A || exit 1 + VID_TO_REPACK=$(getFirstVidContainingFiles) if [ "$VID_TO_REPACK" != "null" ] then echo - echo "Marking the tape ${VID_TO_REPACK} as full" - kubectl -n ${NAMESPACE} exec ctacli -- cta-admin ta ch -v ${VID_TO_REPACK} -f true echo "Launching the repack test on VID ${VID_TO_REPACK}" - kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${VID_TO_REPACK} -b ${REPACK_BUFFER_URL} + kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${VID_TO_REPACK} -b ${REPACK_BUFFER_URL} || exit 1 else echo "No vid found to repack" exit 1 diff --git a/continuousintegration/orchestration/tests/simple_repack.sh b/continuousintegration/orchestration/tests/simple_repack.sh index 498170c5d1c367edddb5d63a3c1bae7533d11727..0bf373ae81a7779c9b4ec3bd7f7cef4a245aab45 100755 --- a/continuousintegration/orchestration/tests/simple_repack.sh +++ b/continuousintegration/orchestration/tests/simple_repack.sh @@ -27,66 +27,44 @@ if [ ! -z "${error}" ]; then exit 1 fi +echo +echo "Launching a round trip repack request" +kubectl -n ${NAMESPACE} cp repack_systemtest.sh client:/root/repack_systemtest.sh source ./repack_helper.sh -echo "Execution of simple_repack.sh" - REPACK_BUFFER_URL=/eos/ctaeos/repack -vidToRepack1=$(getFirstVidContainingFiles) -if [ "$vidToRepack1" != "null" ] -then - echo - echo "Creating the repack buffer URL directory (${REPACK_BUFFER_URL})" - kubectl -n ${NAMESPACE} exec ctaeos -- eos mkdir ${REPACK_BUFFER_URL} - kubectl -n ${NAMESPACE} exec ctaeos -- eos chmod 1777 ${REPACK_BUFFER_URL} - - echo "Marking tape $vidToRepack1 as full before repacking" - kubectl -n ${NAMESPACE} exec ctacli -- cta-admin ta ch -v $vidToRepack1 -f true +echo "Creating the repack buffer URL directory (${REPACK_BUFFER_URL})" +kubectl -n ${NAMESPACE} exec ctaeos -- eos mkdir ${REPACK_BUFFER_URL} +kubectl -n ${NAMESPACE} exec ctaeos -- eos chmod 1777 ${REPACK_BUFFER_URL} - kubectl -n ${NAMESPACE} cp repack_systemtest.sh client:/root/repack_systemtest.sh - - echo - echo "Launching the repack test on VID ${vidToRepack1}" - kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${vidToRepack1} -b ${REPACK_BUFFER_URL} - - echo "Reclaiming tape $vidToRepack1" - executeReclaim $vidToRepack1 - echo - writeTapeSummary $vidToRepack1 +VID_TO_REPACK=$(getFirstVidContainingFiles) +if [ "$VID_TO_REPACK" != "null" ] +then +echo + echo "Marking the tape ${VID_TO_REPACK} as full" + kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape ch --vid ${VID_TO_REPACK} -f true + echo "Launching the repack test on VID ${VID_TO_REPACK}" + kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${VID_TO_REPACK} -b ${REPACK_BUFFER_URL} else echo "No vid found to repack" exit 1 fi -vidToRepack2=$(getFirstVidContainingFiles) -if [ "$vidToRepack2" != "null" ] -then - echo - echo "Creating the repack buffer URL directory (${REPACK_BUFFER_URL})" - kubectl -n ${NAMESPACE} exec ctaeos -- eos mkdir ${REPACK_BUFFER_URL} - kubectl -n ${NAMESPACE} exec ctaeos -- eos chmod 1777 ${REPACK_BUFFER_URL} - - echo "Marking tape $vidToRepack2 as full before repacking" - kubectl -n ${NAMESPACE} exec ctacli -- cta-admin ta ch -v $vidToRepack2 -f true - kubectl -n ${NAMESPACE} cp repack_systemtest.sh client:/root/repack_systemtest.sh +echo "Reclaiming tape ${VID_TO_REPACK}" +kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape reclaim --vid ${VID_TO_REPACK} - echo - echo "Launching the repack test on VID ${vidToRepack2}" - kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${vidToRepack2} -b ${REPACK_BUFFER_URL} - - echo "Reclaiming tape $vidToRepack2" - executeReclaim $vidToRepack2 - echo - writeTapeSummary $vidToRepack1 - writeTapeSummary $vidToRepack2 +VID_TO_REPACK=$(getFirstVidContainingFiles) +if [ "$VID_TO_REPACK" != "null" ] +then +echo + echo "Marking the tape ${VID_TO_REPACK} as full" + kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape ch --vid ${VID_TO_REPACK} -f true + echo "Launching the repack test on VID ${VID_TO_REPACK}" + kubectl -n ${NAMESPACE} exec client -- bash /root/repack_systemtest.sh -v ${VID_TO_REPACK} -b ${REPACK_BUFFER_URL} else echo "No vid found to repack" exit 1 fi -echo -echo -echo "Summary of the repack requests" -kubectl -n ${NAMESPACE} exec ctacli -- cta-admin re ls -h - -echo "End of test simple_repack" +echo "Reclaiming tape ${VID_TO_REPACK}" +kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape reclaim --vid ${VID_TO_REPACK} diff --git a/cta.spec.in b/cta.spec.in index 8cd97055a5be7da1274acb616f0a22fad10e18ef..67c7ef15d53eceeb4e9f3638729f82d21028619c 100644 --- a/cta.spec.in +++ b/cta.spec.in @@ -279,9 +279,11 @@ Unit tests and system tests with virtual tape drives %{_libdir}/libctacommonunittests.so* %{_libdir}/libctadbconfigcatalogueunittests.so* %{_libdir}/libctadbconfigconnunittests.so* +%{_libdir}/libctadbconfigstmtunittests.so* %{_libdir}/libctaexceptionunittests.so* %{_libdir}/libctainmemorycatalogueunittests.so* %{_libdir}/libctainmemoryconnunittests.so* +%{_libdir}/libctainmemorystmtunittests.so* %{_libdir}/libctaobjectstoreunittests.so* %{_libdir}/libctardbmsunittests.so* %{_libdir}/libctardbmswrapperunittests.so* @@ -334,19 +336,6 @@ Scripts and utilities to faciliate working with the CTA catalogue %attr(0644,root,root) %doc /usr/share/man/man1/cta-catalogue-schema-drop.1cta.gz %attr(0644,root,root) %doc /usr/share/man/man1/cta-database-poll.1cta.gz -%package -n cta-mediachangerutils -Summary: Utilities to faciliate working with mediachangers -Group: Application/CTA -Requires: cta-lib = %{version}-%{release} -%description -n cta-mediachangerutils -CERN Tape Archive: -Utilities to faciliate working with the mediachangers -%files -n cta-mediachangerutils -%attr(0755,root,root) %{_bindir}/cta-mediachanger-dismount -%attr(0755,root,root) %{_bindir}/cta-mediachanger-mount -%attr(0644,root,root) %doc /usr/share/man/man1/cta-mediachanger-dismount.1cta.gz -%attr(0644,root,root) %doc /usr/share/man/man1/cta-mediachanger-mount.1cta.gz - %package -n cta-rmcd Summary: Tools to faciliate working with rmcd and smc in cta Group: Application/CTA diff --git a/mediachanger/CMakeLists.txt b/mediachanger/CMakeLists.txt index 2f8e3afe0ea7d89c811d7458d7bf9d32298e072d..a0fe0aaacface7bbdea083f1296342d15afecf6c 100644 --- a/mediachanger/CMakeLists.txt +++ b/mediachanger/CMakeLists.txt @@ -105,8 +105,6 @@ set_property (TARGET cta-mediachanger-mount APPEND PROPERTY INSTALL_RPATH ${PROT target_link_libraries (cta-mediachanger-mount ctacommon ctamediachanger) -install (TARGETS cta-mediachanger-mount DESTINATION /usr/bin) -install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-mediachanger-mount.1cta DESTINATION /usr/share/man/man1) set (MEDIA_CHANGER_DISMOUNT_SRC_FILES DismountCmd.cpp @@ -121,5 +119,3 @@ set_property (TARGET cta-mediachanger-dismount APPEND PROPERTY INSTALL_RPATH ${P target_link_libraries (cta-mediachanger-dismount ctacommon ctamediachanger) -install (TARGETS cta-mediachanger-dismount DESTINATION /usr/bin) -install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-mediachanger-dismount.1cta DESTINATION /usr/share/man/man1) diff --git a/objectstore/Agent.cpp b/objectstore/Agent.cpp index cb68dcb0e394af4c6c9f077ed30fc6bb82f10bce..89cbe6154614afa3925aec59a431a8241b071c7d 100644 --- a/objectstore/Agent.cpp +++ b/objectstore/Agent.cpp @@ -42,7 +42,7 @@ cta::objectstore::Agent::Agent(const std::string & name, Backend & os): void cta::objectstore::Agent::initialize() { ObjectOps<serializers::Agent, serializers::Agent_t>::initialize(); m_payload.set_heartbeat(0); - m_payload.set_timeout_us(60*1000*1000); + m_payload.set_timeout_us(120*1000*1000); m_payload.set_description(""); m_payload.set_being_garbage_collected(false); m_payloadInterpreted = true; diff --git a/objectstore/AgentHeartbeatThread.cpp b/objectstore/AgentHeartbeatThread.cpp index f09bc3aead502651906bd9023f288ef98b53e085..358be90625aa4a20635bf6dd5e657d95345eeeb7 100644 --- a/objectstore/AgentHeartbeatThread.cpp +++ b/objectstore/AgentHeartbeatThread.cpp @@ -19,6 +19,7 @@ #include "AgentHeartbeatThread.hpp" #include "common/log/LogContext.hpp" #include "common/Timer.hpp" +#include "common/utils/utils.hpp" #include <sys/types.h> #include <signal.h> #include <unistd.h> @@ -45,13 +46,12 @@ void AgentHeartbeatThread::run() { utils::Timer t; m_agentReference.bumpHeatbeat(m_backend); auto updateTime = t.secs(); - auto updateTimeLimit = std::chrono::duration<double, std::ratio<1, 1>>(m_heartRate).count(); - if (updateTime > updateTimeLimit) { + if (updateTime > std::chrono::duration_cast<std::chrono::seconds>(m_heartbeatDeadline).count()) { log::ScopedParamContainer params(lc); - params.add("HeartbeatUpdateTimeLimit", updateTimeLimit) + params.add("HeartbeatDeadline", std::chrono::duration_cast<std::chrono::seconds>(m_heartbeatDeadline).count()) .add("HeartbeatUpdateTime", updateTime); lc.log(log::CRIT, "In AgentHeartbeatThread::run(): Could not update heartbeat in time. Exiting (segfault)."); - ::kill(::getpid(), SIGSEGV); + cta::utils::segfault(); ::exit(EXIT_FAILURE); } } @@ -62,7 +62,7 @@ void AgentHeartbeatThread::run() { params.add("Message", ex.getMessageValue()); lc.log(log::CRIT, "In AgentHeartbeatThread::run(): exception while bumping heartbeat. Backtrace follows. Exiting (segfault)."); lc.logBacktrace(log::ERR, ex.backtrace()); - ::kill(::getpid(), SIGSEGV); + cta::utils::segfault(); ::exit(EXIT_FAILURE); } } diff --git a/objectstore/AgentHeartbeatThread.hpp b/objectstore/AgentHeartbeatThread.hpp index addbd5e98f8056fdf7ea1fa2b337b358c4b02f88..6c94483f6e6923b0fdaa4a505cd0247c7c0765b1 100644 --- a/objectstore/AgentHeartbeatThread.hpp +++ b/objectstore/AgentHeartbeatThread.hpp @@ -64,8 +64,11 @@ private: std::promise<void> m_exit; /// The heartbeat update rate. - std::chrono::seconds const m_heartRate = std::chrono::seconds(60); + std::chrono::seconds const m_heartRate = std::chrono::seconds(30); + /// The heartbeat update deadline. + std::chrono::seconds const m_heartbeatDeadline = std::chrono::seconds(60); + /// The logging context log::Logger & m_logger; }; diff --git a/objectstore/AgentReference.cpp b/objectstore/AgentReference.cpp index d46e65e9180eb81436487485f743b6394677076b..df92d50a0bc249cd05f76fc24522b1de5c0b84bc 100644 --- a/objectstore/AgentReference.cpp +++ b/objectstore/AgentReference.cpp @@ -20,6 +20,7 @@ #include "AgentReference.hpp" #include "Agent.hpp" #include "common/exception/Errnum.hpp" +#include "common/utils/utils.hpp" #include <sstream> #include <unistd.h> @@ -163,7 +164,7 @@ void AgentReference::queueAndExecuteAction(std::shared_ptr<Action> action, objec log::ScopedParamContainer params(lc); params.add("agentObject", ag.getAddressIfSet()); lc.log(log::CRIT, "In AgentReference::queueAndExecuteAction(): agent object being garbage collected. Exiting (segfault)."); - ::kill(::getpid(), SIGSEGV); + cta::utils::segfault(); ::exit(EXIT_FAILURE); } double agentFetchTime = t.secs(utils::Timer::resetCounter); diff --git a/objectstore/BackendPopulator.cpp b/objectstore/BackendPopulator.cpp index ea4dd0eac3b2ef1558a9153aa86fe16b03247420..3a7f71a1af683f77cd2ca404b42be1b19901d246 100644 --- a/objectstore/BackendPopulator.cpp +++ b/objectstore/BackendPopulator.cpp @@ -19,6 +19,7 @@ #include "objectstore/BackendVFS.hpp" #include "objectstore/RootEntry.hpp" #include "objectstore/BackendPopulator.hpp" +#include "common/utils/utils.hpp" namespace cta { namespace objectstore { @@ -77,13 +78,13 @@ BackendPopulator::~BackendPopulator() throw() { m_lc.log(log::CRIT, "In BackendPopulator::~BackendPopulator(): error deleting agent (cta::exception::Exception). Backtrace follows."); m_lc.logBacktrace(log::ERR, ex.backtrace()); // We have an exception (we should not), let's core dump. - *((int*)nullptr)=0; + cta::utils::segfault(); } catch (std::exception & ex) { cta::log::ScopedParamContainer params(m_lc); params.add("exceptionWhat", ex.what()); m_lc.log(log::CRIT, "In BackendPopulator::~BackendPopulator(): error deleting agent (std::exception)."); // We have an exception (we should not), let's core dump. - *((int*)nullptr)=0; + cta::utils::segfault(); } } diff --git a/objectstore/BackendRados.cpp b/objectstore/BackendRados.cpp index dd4d39fb16e217459296bece36b1c9b28b73f614..2a8abfb75c0f25ec7d3c59e726dc068625c8c0a3 100644 --- a/objectstore/BackendRados.cpp +++ b/objectstore/BackendRados.cpp @@ -21,6 +21,7 @@ #include "common/Timer.hpp" #include "common/threading/MutexLocker.hpp" #include "common/log/LogContext.hpp" +#include "common/utils/utils.hpp" #include <rados/librados.hpp> #include <sys/syscall.h> #include <errno.h> @@ -453,7 +454,7 @@ BackendRados::LockWatcher::~LockWatcher() { }, "In BackendRados::LockWatcher::~LockWatcher(): failed m_context.aio_unwatch()"); } catch (cta::exception::Exception & ex) { // If we get an exception in a destructor, we are going to exit anyway, so better halt the process early. - *((int *) nullptr) = 0; + cta::utils::segfault(); } completion->release(); rtl.logIfNeeded("In BackendRados::LockWatcher::~LockWatcher(): m_context.aio_unwatch() call", name); diff --git a/objectstore/Helpers.cpp b/objectstore/Helpers.cpp index f0b770566cc81be48bc279c586133a3455d558f6..6eff98a143208124434afcc62528a40515e80633 100644 --- a/objectstore/Helpers.cpp +++ b/objectstore/Helpers.cpp @@ -669,7 +669,7 @@ void Helpers::registerRepackRequestToIndex(const std::string& vid, const std::st // First, try to get the address of of the repack index lockfree. try { repackIndexAddress = re.getRepackIndexAddress(); - } catch (RootEntry::NotAllocated &){ + } catch (cta::exception::Exception &){ ScopedExclusiveLock rel(re); re.fetch(); repackIndexAddress = re.addOrGetRepackIndexAndCommit(agentReference); @@ -692,7 +692,7 @@ void Helpers::removeRepackRequestToIndex(const std::string& vid, Backend& backen // First, try to get the address of of the repack index lockfree. try { repackIndexAddress = re.getRepackIndexAddress(); - } catch (RootEntry::NotAllocated &){ + } catch (cta::exception::Exception &){ // No repack index, nothing to do. return; } diff --git a/objectstore/RepackRequest.cpp b/objectstore/RepackRequest.cpp index bfbe311b1b17803aa25d9dc883b5c010234d5d0a..0a0bb02505c8e06d831ad49b49f3379e75fd3668 100644 --- a/objectstore/RepackRequest.cpp +++ b/objectstore/RepackRequest.cpp @@ -75,6 +75,7 @@ void RepackRequest::initialize() { m_payload.set_failedtoarchivebytes(0); m_payload.set_lastexpandedfseq(0); m_payload.set_is_expand_finished(false); + m_payload.set_is_expand_started(false); // This object is good to go (to storage) m_payloadInterpreted = true; } @@ -162,6 +163,47 @@ void RepackRequest::setExpandFinished(const bool expandFinished){ m_payload.set_is_expand_finished(expandFinished); } +void RepackRequest::setExpandStarted(const bool expandStarted){ + checkPayloadWritable(); + m_payload.set_is_expand_started(expandStarted); +} + +void RepackRequest::setTotalStats(const cta::SchedulerDatabase::RepackRequest::TotalStatsFiles& totalStatsFiles){ + setTotalFileToRetrieve(totalStatsFiles.totalFilesToRetrieve); + setTotalFileToArchive(totalStatsFiles.totalFilesToArchive); + setTotalBytesToArchive(totalStatsFiles.totalBytesToArchive); + setTotalBytesToRetrieve(totalStatsFiles.totalBytesToRetrieve); +} + +void RepackRequest::setStatus(){ + checkPayloadWritable(); + checkPayloadReadable(); + + if(m_payload.is_expand_started()){ + //The expansion of the Repack Request have started + if(m_payload.is_expand_finished()){ + if( (m_payload.retrievedfiles() + m_payload.failedtoretrievefiles() >= m_payload.totalfilestoretrieve()) && (m_payload.archivedfiles() + m_payload.failedtoarchivefiles() >= m_payload.totalfilestoarchive()) ){ + //We reached the end + if (m_payload.failedtoretrievefiles() || m_payload.failedtoarchivefiles()) { + //At least one retrieve or archive has failed + setStatus(common::dataStructures::RepackInfo::Status::Failed); + } else { + //No Failure, we are status Complete + setStatus(common::dataStructures::RepackInfo::Status::Complete); + } + return; + } + } + //Expand is finished or not, if we have retrieved files, we are in Running, + //else we are in starting + if(m_payload.retrievedfiles()){ + setStatus(common::dataStructures::RepackInfo::Status::Running); + } else { + setStatus(common::dataStructures::RepackInfo::Status::Starting); + } + } +} + //------------------------------------------------------------------------------ // RepackRequest::getExpandFinished() //------------------------------------------------------------------------------ @@ -276,8 +318,17 @@ void RepackRequest::setTotalFileToArchive(const uint64_t nbFilesToArchive){ void RepackRequest::setTotalBytesToArchive(const uint64_t nbBytesToArchive) { checkPayloadWritable(); m_payload.set_totalbytestoarchive(nbBytesToArchive); -} + } +cta::SchedulerDatabase::RepackRequest::TotalStatsFiles RepackRequest::getTotalStatsFile() { + checkPayloadReadable(); + cta::SchedulerDatabase::RepackRequest::TotalStatsFiles ret; + ret.totalBytesToRetrieve = m_payload.totalbytestoretrieve(); + ret.totalBytesToArchive = m_payload.totalbytestoarchive(); + ret.totalFilesToRetrieve = m_payload.totalfilestoretrieve(); + ret.totalFilesToArchive = m_payload.totalfilestoarchive(); + return ret; +} //------------------------------------------------------------------------------ // RepackRequest::reportRetriveSuccesses() @@ -302,6 +353,7 @@ void RepackRequest::reportRetriveSuccesses(SubrequestStatistics::List& retrieveS } } if (didUpdate) { + setStatus(); m_payload.mutable_subrequests()->Clear(); for (auto & p: pointerMap) p.second.serialize(*m_payload.mutable_subrequests()->Add()); } @@ -330,6 +382,7 @@ void RepackRequest::reportRetriveFailures(SubrequestStatistics::List& retrieveFa } } if (didUpdate) { + setStatus(); m_payload.mutable_subrequests()->Clear(); for (auto & p: pointerMap) p.second.serialize(*m_payload.mutable_subrequests()->Add()); } @@ -360,14 +413,7 @@ serializers::RepackRequestStatus RepackRequest::reportArchiveSuccesses(Subreques } } if (didUpdate) { - // Check whether we reached the end. - if (m_payload.archivedfiles() + m_payload.failedtoarchivefiles() >= m_payload.totalfilestoarchive()) { - if (m_payload.failedtoarchivefiles()) { - m_payload.set_status(serializers::RepackRequestStatus::RRS_Failed); - } else { - m_payload.set_status(serializers::RepackRequestStatus::RRS_Complete); - } - } + setStatus(); m_payload.mutable_subrequests()->Clear(); for (auto & p: pointerMap) p.second.serialize(*m_payload.mutable_subrequests()->Add()); } @@ -399,8 +445,7 @@ serializers::RepackRequestStatus RepackRequest::reportArchiveFailures(Subrequest } if (didUpdate) { // Check whether we reached the end. - if (m_payload.archivedfiles() + m_payload.failedtoarchivefiles() >= m_payload.totalfilestoarchive()) - m_payload.set_status(serializers::RepackRequestStatus::RRS_Failed); + setStatus(); m_payload.mutable_subrequests()->Clear(); for (auto & p: pointerMap) p.second.serialize(*m_payload.mutable_subrequests()->Add()); } diff --git a/objectstore/RepackRequest.hpp b/objectstore/RepackRequest.hpp index bc8de1d2b69e6f6fb56da5a0fc3443a0c127b51b..29b1d618aed8fc04ec7c88f5341134d9f348585f 100644 --- a/objectstore/RepackRequest.hpp +++ b/objectstore/RepackRequest.hpp @@ -23,6 +23,7 @@ #include "common/dataStructures/RepackInfo.hpp" #include "common/log/TimingList.hpp" #include "common/Timer.hpp" +#include "scheduler/SchedulerDatabase.hpp" namespace cta { namespace objectstore { @@ -44,6 +45,14 @@ public: void setBufferURL(const std::string & bufferURL); void setExpandFinished(const bool expandFinished); bool isExpandFinished(); + void setExpandStarted(const bool expandStarted); + void setTotalStats(const cta::SchedulerDatabase::RepackRequest::TotalStatsFiles& totalStatsFiles); + cta::SchedulerDatabase::RepackRequest::TotalStatsFiles getTotalStatsFile(); + /** + * Automatically set the new status of the Repack Request + * regarding multiple parameters + */ + void setStatus(); // Sub request management struct SubrequestInfo { std::string address; diff --git a/objectstore/RootEntry.cpp b/objectstore/RootEntry.cpp index 6f67ce58394dae3bc42c47ea070fae9ebdf0aa69..91869db204155dddaf1ab0f633c9b00954bf14f4 100644 --- a/objectstore/RootEntry.cpp +++ b/objectstore/RootEntry.cpp @@ -740,7 +740,7 @@ std::string RootEntry::getRepackIndexAddress() { m_payload.repackindexpointer().address().size()) { return m_payload.repackindexpointer().address(); } - throw NotAllocated("In RootEntry::getRepackIndexAddress: repack tape register not yet allocated"); + throw cta::exception::Exception("In RootEntry::getRepackIndexAddress: repack tape register not yet allocated"); } std::string RootEntry::addOrGetRepackIndexAndCommit(AgentReference& agentRef) { @@ -748,7 +748,7 @@ std::string RootEntry::addOrGetRepackIndexAndCommit(AgentReference& agentRef) { // Check if the repack tape register exists try { return getRepackIndexAddress(); - } catch (NotAllocated &) { + } catch (cta::exception::Exception &) { // TODO: this insertion method is much simpler than the ones used for other objects. // It implies the only dangling pointer situation we can get is the one where // the object does not exist. diff --git a/objectstore/cta.proto b/objectstore/cta.proto index fa14344739c77ce52e1b445369b9f735877345bc..9b8fefea134df0aab64d37438079363802422000 100644 --- a/objectstore/cta.proto +++ b/objectstore/cta.proto @@ -545,6 +545,7 @@ message RepackRequest { //is not finished. This boolean is used to indicate wether //the expansion of the RepackRequest is done or not required bool is_expand_finished = 11561; + required bool is_expand_started = 11562; repeated RepackSubRequestPointer subrequests = 11570; } diff --git a/operations/tape/tape-config-generate b/operations/tape/tape-config-generate new file mode 100755 index 0000000000000000000000000000000000000000..fcb5ff47998e6fe76b3e73c591a1ccab2e28fe0b --- /dev/null +++ b/operations/tape/tape-config-generate @@ -0,0 +1,193 @@ +#!/usr/bin/perl -w +####################################################################### +# +# This script will generate /etc/cta/TPCONFIG file with the data from +# TOMS (Tape Operations Management System) URL: +# +# https://apex.cern.ch/pls/htmldb_castorns/f?p=toms_prod:250:163672298908022::NO::P250_TAPESERVER:HOSTNAME +# +# Vladimir Bahyl - 05/2019 +# +####################################################################### + +use strict; +use XML::DOM; +use Sys::Hostname; +use LWP::UserAgent; +use LC::Check qw(file); + +#use Data::Dumper; + +my $today = localtime; + +my %TPCONFIG = (); +my $hostname = ''; + +my $tpconfigfile = '/etc/castor/TPCONFIG'; +my $tpconfig = "####################################################################### +# +# CTA Tape Server Configuration file +# +# This tape server is not configured. +# +####################################################################### +# +# Generated on $today by $0 +"; + +my $changes = 0; + +($hostname = hostname()) =~ s/\.cern\.ch$//io; + +my $configUrl = 'https://apex.cern.ch/pls/htmldb_castorns/f?p=toms_prod:250:163672298908022::NO::P250_TAPESERVER:HOSTNAME'; +die ("$0: missing configuration URL") unless ($configUrl); +$configUrl =~ s/HOSTNAME/$hostname/o; + +# +# Fetch the data +# +print("$0: Fetching the data over HTTP from the Oracle APEX database ... please be patient ...\n"); +%TPCONFIG = &GetData($configUrl); + +# +# Prepare the TPCONFIG file +# +my $i = 0; +while (%TPCONFIG and defined($TPCONFIG{$i}{'tapeserver'}) and (lc($TPCONFIG{$i}{'tapeserver'}) eq lc($hostname))) { + $tpconfig = "####################################################################### +# +# CTA Tape Server Configuration file +# +# unit device system control +# name group device method + +" if ($i == 0); + + $tpconfig .= "$TPCONFIG{$i}{'tapedrive'} $TPCONFIG{$i}{'devicegroup'} $TPCONFIG{$i}{'unixdevice'} $TPCONFIG{$i}{'controlmethod'} + +# Tape Drive Comment: $TPCONFIG{$i}{'tapedrivecomment'} +# Tape Service Comment: $TPCONFIG{$i}{'tapeservicecomment'} +# Modified by: $TPCONFIG{$i}{'modifuser'} +# Modify date: $TPCONFIG{$i}{'modifdate'} + +"; + $i++; +} + +$tpconfig .= "# +####################################################################### +# +# Generated on $today by $0 +" if (%TPCONFIG and (lc($TPCONFIG{0}{'tapeserver'}) eq lc($hostname))); + +# Change the TPCONFIG location if comment mentions CTA +$tpconfigfile = '/etc/cta/TPCONFIG' if (%TPCONFIG and (defined $TPCONFIG{0}{'tapeservicecomment'}) and ($TPCONFIG{0}{'tapeservicecomment'} =~ /CTA/oi)); + +# +# Configure TPCONFIG and SSI files +# +$changes += &UpdateFile($tpconfigfile, $tpconfig); + +LC::Check::link('/etc/TPCONFIG', $tpconfigfile, + backup => '.old', + nocheck => 1, + force => 1 +); + +########################################################################## +sub GetData { +########################################################################## + my ($url) = @_; + + my %TPCONFIG = (); + + my $xmlParser = new XML::DOM::Parser; + + # Download the XML formated configuration data + # Use cookies because of APEX (otherwise, nothing will be downloaded; redirection will not work) + my $UserAgent = LWP::UserAgent->new; + $UserAgent->cookie_jar({ file => undef }); + my $xml = $UserAgent->get($url); + + if (defined ($xml->content)) { + if ($xml->content =~/TAPESERVER/oi) { + my $xmlDoc = $xmlParser->parse($xml->content); + + # pcitpdp39 ~ > lynx -source "http://oraweb.cern.ch/pls/cdbsqldev/web.show_tpconfig?p_tapeserver=tpsrv027&p_output=xml" + # <?xml version = '1.0'?> + # <TPCONFIGSEARCHLIST> <TAPESERVER NAME="tpsrv027" TAPEDRIVE="994B53A6" DEVICEGROUP="994BR5" UNIXDEVICE="/dev/nst0" DENSITY="200G" COMPRESSION="Y" INITSTATUS="DOWN" CONTROLMETHOD="acs0,3,10,6" MODEL="9940" ROBOTHOST="sunstk62" /> </TPCONFIGSEARCHLIST> + + for my $i (0 .. ($xmlDoc->getElementsByTagName("TAPESERVER")->getLength())-1) { + $TPCONFIG{$i}{'tapeserver'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("NAME"); + $TPCONFIG{$i}{'tapedrive'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("TAPEDRIVE"); + $TPCONFIG{$i}{'devicegroup'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("DEVICEGROUP"); + $TPCONFIG{$i}{'unixdevice'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("UNIXDEVICE"); + $TPCONFIG{$i}{'initstatus'} = lc($xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("INITSTATUS")); + $TPCONFIG{$i}{'controlmethod'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("CONTROLMETHOD"); + $TPCONFIG{$i}{'modifdate'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("MODIFDATE"); + $TPCONFIG{$i}{'modifuser'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("MODIFUSER"); + $TPCONFIG{$i}{'tapedrivecomment'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("TAPEDRIVECOMMENT"); + $TPCONFIG{$i}{'tapeservicecomment'} = $xmlDoc->getElementsByTagName("TAPESERVER")->item($i)->getAttribute("TAPESERVICECOMMENT"); + + warn("$0: database entry nr. ".($i+1)." missing tape server hostname\n") unless ($TPCONFIG{$i}{'tapeserver'}); + warn("$0: database entry nr. ".($i+1)." missing tape drive name\n") unless ($TPCONFIG{$i}{'tapedrive'}); + warn("$0: database entry nr. ".($i+1)." missing device group name\n") unless ($TPCONFIG{$i}{'devicegroup'}); + warn("$0: database entry nr. ".($i+1)." missing unix device\n") unless ($TPCONFIG{$i}{'unixdevice'}); + warn("$0: database entry nr. ".($i+1)." missing init status\n") unless ($TPCONFIG{$i}{'initstatus'}); + warn("$0: database entry nr. ".($i+1)." missing control method\n") unless ($TPCONFIG{$i}{'controlmethod'}); + warn("$0: database entry nr. ".($i+1)." missing the modification date\n") unless ($TPCONFIG{$i}{'modifdate'}); + warn("$0: database entry nr. ".($i+1)." missing user name\n") unless ($TPCONFIG{$i}{'modifuser'}); + print("$0: database entry nr. ".($i+1)." no tape service comment\n") unless ($TPCONFIG{$i}{'tapeservicecomment'}); + print("$0: database entry nr. ".($i+1)." no tape drive comment\n") unless ($TPCONFIG{$i}{'tapedrivecomment'}); + } + + $xmlDoc->dispose; + } else { + warn("$0: URL $url is not returning any usable data for $hostname. This tape server will not be configured. Please check whether there is a tape drive assigned to this tape server.\n"); + } + } else { + warn("$0: URL $url doesn't seem to work. There could be a problem with the Web server or the Oracle APEX database server.\n"); + } + + return %TPCONFIG; +} + +########################################################################## +sub UpdateFile { +########################################################################## + my ($filename, $newcontent) = @_; + + my $changes = 0; + + if ((-f $filename) and (-r $filename) and (-s $filename)) { + # Check the content of the file and correct it if there are some differences + $changes += LC::Check::file($filename, + source => $filename, + owner => 0, + group => 0, + mode => 0644, + backup => '.old', + code => sub { + my($oldcontent) = @_; + return() unless $oldcontent; + + (my $oldfile = $oldcontent) =~ s/^#.*$//gim; # remove lines with comments + $oldfile =~ s/^\s*$//gim; # remove empty lines + + (my $newfile = $newcontent) =~ s/^#.*$//gim; # remove lines with comments + $newfile =~ s/^\s*$//gim; # remove empty lines + + $oldcontent = $newcontent unless ($oldfile eq $newfile); + + return($oldcontent); + } + ); + } else { + # The file is missing, create a new one + $changes += LC::File::file_contents($filename, $newcontent); + print "$0: created new $filename\n"; + } + die ("$0: error modifying $filename\n") unless (defined($changes)); + + return $changes; +} diff --git a/operations/tape/tape-devices-namer b/operations/tape/tape-devices-namer new file mode 100755 index 0000000000000000000000000000000000000000..708bea830bd59e1d3f8d4002363092e72fb6d892 --- /dev/null +++ b/operations/tape/tape-devices-namer @@ -0,0 +1,227 @@ +#!/usr/bin/python + +""" +This script creates links to tape and medium changer devices. +The association between tape and smc device is made based on +the serial numbers stored in the TOMS DB. +""" + +import re +import os +import sys +import socket +import pprint +import urllib2 +import optparse +import cookielib +import subprocess +pp = pprint.PrettyPrinter(width=200) + +#------------------------------------------------------------ +def mklink(dev, sn, drivename, type): + if not options.noaction and drivename is not None: + link = '/dev/' + type + '_' + drivename + subprocess.Popen(['/bin/ln', '-f', '-s', dev, link]).wait() + print 'Created link', link + else: + print 'Cannot create link to ' + dev + print 'Drivename for serial number ' + sn + ' not found' + +#------------------------------------------------------------ +def fix_mismatch(mm_tape_dev, toms_drives, hostname): + #this fucntions assumes that there is only one mismatch, + #i.e. only one tape device with S/N not found in TOMS + #and only one drives in TOSM with S/N not found in the server. + l = [] + cj = cookielib.CookieJar() + opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) + for d in toms_drives: + if d['match'] == 0: + #assigning drivename to the mismatched tape device + mm_tape_dev['drivename'] = d['drivename'] + #fixing the S/N in TOMS + tomsurl = 'http://castortapeweb.cern.ch/cgi-bin/serial-nr-update.cgi?tapedrive=' + d['drivename'] + '&tapeserver=' + hostname + '&serialnumber=' + mm_tape_dev['sn'] + if options.debug: print 'Opening', tomsurl + try: + urlfh = opener.open(tomsurl) + except: + print 'Cannot open ' + tomsurl + + +#------------------------------------------------------------ +#main +#------------------------------------------------------------ + +# options --------------------------------------------------- +usage = "usage: %prog [options]" +parser = optparse.OptionParser(usage) +parser.add_option("-d", "--debug", action="store_true", dest="debug", help="print debug messages") +parser.add_option("--noaction", action="store_true", dest="noaction", help="do nothing") +(options, args) = parser.parse_args() + +tape_devices = [] +smc_devices = [] + +# find tape and smc devices +if options.debug: print 'Searching tape devices' +try: + p = subprocess.Popen(['/usr/bin/lsscsi', '-g'], stdout=subprocess.PIPE) + p.wait() +except: + print 'Cannot run lsscsi. Exit.' + sys.exit(0) + +for line in p.stdout: + fields = line.split() + scsi_address = fields[0][1:-1] + type = fields[1] + scsi_generic = fields.pop() + scsi_tape = fields.pop() + if type == 'tape': + tape_devices.append({'scsi_address' : scsi_address, 'scsi_generic' : scsi_generic, 'scsi_tape' : scsi_tape, 'sn' : None, 'drivename' : None}) + if type == 'mediumx': + smc_devices.append({'scsi_address' : scsi_address, 'scsi_generic' : scsi_generic, 'scsi_tape' : scsi_tape, 'sn' : None, 'drivename' : None}) + +ntpdev=len(tape_devices) + +if options.debug: + print 'tape_devices:' + pp.pprint(tape_devices) + print 'smc_devices:' + pp.pprint(smc_devices) + +# associate tape and smc devices +if options.debug: print 'Coupling tape and smc devices (if any)' +pairs = [] +for tapedev in tape_devices: + for smcdev in smc_devices: + if tapedev['scsi_address'][:-2] == smcdev['scsi_address'][:-2]: + pairs.append([tapedev, smcdev]) +if options.debug: + print 'pairs:' + pp.pprint(pairs) + +if len(tape_devices)>len(smc_devices) and len(smc_devices)>0: + print 'Number of control paths lower that number of drives' + sys.exit(0) + + +# find the serial number of the tape device +# sg_inq will not work if the /dev/sgX device is not reachable +# sg_inq will not work if the /dev/nstY device is being used +# run sg_inq against the nst dev so that if it is already being used we exit +if options.debug: print 'Reading serial numbers from tape devices' + +for tapedev in tape_devices: + tapedn = '/dev/nst'+tapedev['scsi_tape'][-1] + p = subprocess.Popen(['/usr/bin/sg_inq', tapedn], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if p.wait() != 0: + print 'Cannot run sg_inq on ' + tapedn + '. Exit' + sys.exit(0) + else: + for line in p.stdout: + #reg = re.search('(?<=Unit serial number: )(\d+)', line) + if re.search('Unit serial number', line): + l = line.split(':') + tapedev['sn'] = l[1][1:-1] + + if tapedev['sn'] is None: + print 'Could not extract the serial number from the output of sg_inq ' + tapedn + sys.exit(0) + +if options.debug: + print 'tape_devices:' + pp.pprint(tape_devices) + + +# search the drive names in toms by serial number +toms_drives = [] +if options.debug: print 'Looking into TOMS for drive names' +hostname = socket.gethostname().split('.')[0] +tomsurl = 'https://apex.cern.ch/pls/htmldb_castorns/f?p=toms_prod:250:::NO::P250_TAPESERVER:' + hostname +if options.debug: print 'Opening', tomsurl + +cj = cookielib.CookieJar() +opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) + +try: + urlfh = opener.open(tomsurl) +except: + print 'Cannot open ' + tomsurl + sys.exit(0) + +for line in urlfh: + + if options.debug: print line + + if not re.search('TAPESERVER', line): continue + + drivename, serialnumber = '', '' + + l = line.split() + for item in l: + g = item.split('=') + if g[0] == 'CURRENTSERIALNR': serialnumber = g[1][1:-1] + if g[0] == 'TAPEDRIVE': drivename = g[1][1:-1] + + if drivename == '': + print 'drive name for host ' + hostname + ' not found in TOMS' + sys.exit(0) + + if serialnumber == '': + print 'Serial number for drive', drivename, 'not found in TOMS' + #here we don't exit, in case of a signle mismatch we update the s/n + + toms_drives.append({'drivename' : drivename, 'sn': serialnumber, 'match' : 0}) + + for tapedev in tape_devices: + if tapedev['sn'] == serialnumber: + tapedev['drivename'] = drivename + for d in toms_drives: + if d['drivename'] == drivename: d['match'] = 1 + +if options.debug: + print 'tape_devices:' + pp.pprint(tape_devices) + print 'toms_drives:' + pp.pprint(toms_drives) + + +#Check how many S/N are missing. +#1. If there is only one assume that the drive has been replaced and update the S/N in TOMS. +#2. If there are more than one the script does nothing (new or changed drives/devices +# will not be configured (link not created). + +devs_mm_sn = 0 +mm_tape_dev = None +for t in tape_devices: + if t['drivename'] is None: + devs_mm_sn += 1 + mm_tape_dev = t + +if devs_mm_sn == 1: + print 'One S/N mismatch. Going to fix S/N in TOMS' + fix_mismatch(mm_tape_dev, toms_drives, hostname) +elif devs_mm_sn == 0: + if options.debug: print 'No S/N mismatches' +else: + if options.debug: print 'Too many S/N mismatches' + + +# created links +if pairs == []: + # this is a SUN tape server + for tapedev in tape_devices: + tapedn = '/dev/nst'+tapedev['scsi_tape'][-1] + mklink(tapedn, tapedev['sn'], tapedev['drivename'], 'tape') +else: + #this is a IBM tape server + for pair in pairs: + tapedev = pair[0] + tapedn = '/dev/nst'+tapedev['scsi_tape'][-1] + mklink(tapedn, tapedev['sn'], tapedev['drivename'], 'tape') + smcdev = pair[1] + mklink(smcdev['scsi_generic'], tapedev['sn'], tapedev['drivename'], 'smc') + + + diff --git a/rdbms/CMakeLists.txt b/rdbms/CMakeLists.txt index 8ff00d676c4fefcf472fb174c61b633ff7725c20..c6e926561262358a0dc6080292cd491f74d97f8e 100644 --- a/rdbms/CMakeLists.txt +++ b/rdbms/CMakeLists.txt @@ -43,7 +43,6 @@ install (TARGETS ctardbms DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) set(RDBMS_UNIT_TESTS_LIB_SRC_FILES ConnPoolTest.cpp - ConnTest.cpp LoginTest.cpp RdbmsTest.cpp StmtPoolTest.cpp) @@ -72,6 +71,20 @@ target_link_libraries (ctainmemoryconnunittests install (TARGETS ctainmemoryconnunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) +set(IN_MEMORY_STMT_UNIT_TESTS_LIB_SRC_FILES + StmtTest.cpp + InMemoryVersionOfStmtTest.cpp) + +add_library (ctainmemorystmtunittests SHARED + ${IN_MEMORY_STMT_UNIT_TESTS_LIB_SRC_FILES}) +set_property(TARGET ctainmemorystmtunittests PROPERTY SOVERSION "${CTA_SOVERSION}") +set_property(TARGET ctainmemorystmtunittests PROPERTY VERSION "${CTA_LIBVERSION}") + +target_link_libraries (ctainmemorystmtunittests + ctardbms) + +install (TARGETS ctainmemorystmtunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) + set (DBCONFIG_CONN_UNIT_TESTS_LIB_SRC_FILES ConnTest.cpp DbConfigVersionOfConnTest.cpp) @@ -85,3 +98,17 @@ target_link_libraries (ctadbconfigconnunittests ctardbms) install (TARGETS ctadbconfigconnunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) + +set (DBCONFIG_STMT_UNIT_TESTS_LIB_SRC_FILES + StmtTest.cpp + DbConfigVersionOfStmtTest.cpp) + +add_library (ctadbconfigstmtunittests SHARED + ${DBCONFIG_STMT_UNIT_TESTS_LIB_SRC_FILES}) +set_property(TARGET ctadbconfigstmtunittests PROPERTY SOVERSION "${CTA_SOVERSION}") +set_property(TARGET ctadbconfigstmtunittests PROPERTY VERSION "${CTA_LIBVERSION}") + +target_link_libraries (ctadbconfigstmtunittests + ctardbms) + +install (TARGETS ctadbconfigstmtunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) diff --git a/rdbms/DbConfigVersionOfStmtTest.cpp b/rdbms/DbConfigVersionOfStmtTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f274f726d11a9796ccbb72e650b6230f628ffc36 --- /dev/null +++ b/rdbms/DbConfigVersionOfStmtTest.cpp @@ -0,0 +1,56 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "rdbms/StmtTest.hpp" +#include "tests/RdbmsUnitTestsCmdLineArgs.hpp" + +namespace { + +/** + * Creates Login objects from a database configuration file passed on the + * command-line to the unit-tests program. + */ +class DbConfigFileVersionOfStmtTestLoginFactory: public cta::rdbms::LoginFactory { +public: + + /** + * Destructor. + */ + virtual ~DbConfigFileVersionOfStmtTestLoginFactory() { + } + + /** + * Returns a newly created Login object. + * + * @return A newly created Login object. + */ + virtual cta::rdbms::Login create() { + return cta::rdbms::Login::parseFile(g_cmdLineArgs.dbConfigPath); + } +}; // class OracleLoginFactory + +DbConfigFileVersionOfStmtTestLoginFactory g_dbConfigFileVersionOfStmtTestLoginFactory; + +} // anonymous namespace + +namespace unitTests { + +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_rdbms_StmtTest, + ::testing::Values(dynamic_cast<cta::rdbms::LoginFactory*>(&g_dbConfigFileVersionOfStmtTestLoginFactory))); + +} // namespace unitTests diff --git a/rdbms/InMemoryVersionOfStmtTest.cpp b/rdbms/InMemoryVersionOfStmtTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46f119449e9c21beb6bbc21e3b9e2f46d45b5791 --- /dev/null +++ b/rdbms/InMemoryVersionOfStmtTest.cpp @@ -0,0 +1,54 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "rdbms/StmtTest.hpp" + +namespace unitTests { + +namespace { + +/** + * Creates Login objects for in-memory catalogue databases. + */ +class RdbmsInMemoryLoginFactory: public cta::rdbms::LoginFactory { +public: + + /** + * Destructor. + */ + virtual ~RdbmsInMemoryLoginFactory() { + } + + /** + * Returns a newly created Login object. + * + * @return A newly created Login object. + */ + virtual cta::rdbms::Login create() { + return cta::rdbms::Login(cta::rdbms::Login::DBTYPE_IN_MEMORY, "", "", "", "", 0); + } +}; // class RdbmsInMemoryLoginFactory + +RdbmsInMemoryLoginFactory g_inMemoryLoginFactory; + +} // anonymous namespace + +INSTANTIATE_TEST_CASE_P(InMemory, cta_rdbms_StmtTest, + ::testing::Values(dynamic_cast<cta::rdbms::LoginFactory*>(&g_inMemoryLoginFactory))); + +} // namespace unitTests diff --git a/rdbms/Rset.cpp b/rdbms/Rset.cpp index 065afe071ad04a65ac5b393d8f2aa1b8e373e5e5..f811cb387357b10371aed2aac73cb8b8163d51f9 100644 --- a/rdbms/Rset.cpp +++ b/rdbms/Rset.cpp @@ -192,5 +192,36 @@ optional<uint64_t> Rset::columnOptionalUint64(const std::string &colName) const return m_impl->columnOptionalUint64(colName); } +//------------------------------------------------------------------------------ +// columnDouble +//------------------------------------------------------------------------------ +double Rset::columnDouble(const std::string &colName) const { + try { + if(nullptr == m_impl) { + throw exception::Exception("This result set is invalid"); + } + + const optional<double> col = columnOptionalDouble(colName); + if(col) { + return col.value(); + } else { + throw NullDbValue(std::string("Database column ") + colName + " contains a null value"); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// columnOptionalDouble +//------------------------------------------------------------------------------ +optional<double> Rset::columnOptionalDouble(const std::string &colName) const { + if(nullptr == m_impl) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + "This result set is invalid"); + } + return m_impl->columnOptionalDouble(colName); +} + } // namespace rdbms } // namespace cta diff --git a/rdbms/Rset.hpp b/rdbms/Rset.hpp index 12818d2747f22cb2ddda43321046c081d0ef096c..cbf17fd856d4fee550a1e1b335f648170beb1707 100644 --- a/rdbms/Rset.hpp +++ b/rdbms/Rset.hpp @@ -166,6 +166,27 @@ public: */ optional<bool> columnOptionalBool(const std::string &colName) const; + /** + * Returns the value of the specified column as a double. + * + * This method will throw an exception if the value of the specified column + * is nullptr. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + double columnDouble(const std::string &colName) const; + + /** + * Returns the value of the specified column as a double. + * + * This method will return a null column value as an optional with no value. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + optional<double> columnOptionalDouble(const std::string &colName) const; + private: /** diff --git a/rdbms/Stmt.cpp b/rdbms/Stmt.cpp index aa99fe1c5d247a1ceddc69cb46720fe15cade972..0069bbf3b0343c03a1ce3e34335ca0db818031c0 100644 --- a/rdbms/Stmt.cpp +++ b/rdbms/Stmt.cpp @@ -128,6 +128,28 @@ void Stmt::bindOptionalUint64(const std::string ¶mName, const optional<uint6 } } +//----------------------------------------------------------------------------- +// bindDouble +//----------------------------------------------------------------------------- +void Stmt::bindDouble(const std::string ¶mName, const double paramValue) { + if(nullptr != m_stmt) { + return m_stmt->bindDouble(paramName, paramValue); + } else { + throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement"); + } +} + +//----------------------------------------------------------------------------- +// bindOptionalDouble +//----------------------------------------------------------------------------- +void Stmt::bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) { + if(nullptr != m_stmt) { + return m_stmt->bindOptionalDouble(paramName, paramValue); + } else { + throw exception::Exception(std::string(__FUNCTION__) + " failed: Stmt does not contain a cached statement"); + } +} + //----------------------------------------------------------------------------- // bindBool //----------------------------------------------------------------------------- diff --git a/rdbms/Stmt.hpp b/rdbms/Stmt.hpp index cc4f406781e32a0f5156f0e058ee9c10c3f00855..5a3e7a6076b9192fbc17d68967437500723a816b 100644 --- a/rdbms/Stmt.hpp +++ b/rdbms/Stmt.hpp @@ -119,6 +119,22 @@ public: */ void bindOptionalUint64(const std::string ¶mName, const optional<uint64_t> ¶mValue); + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindDouble(const std::string ¶mName, const double paramValue); + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue); + /** * Binds an SQL parameter. * diff --git a/rdbms/StmtTest.cpp b/rdbms/StmtTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a09095fdfe2f42b17dd1da6f85bb9d823362ace --- /dev/null +++ b/rdbms/StmtTest.cpp @@ -0,0 +1,390 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "common/exception/Exception.hpp" +#include "common/make_unique.hpp" +#include "common/utils/utils.hpp" +#include "rdbms/ConnPool.hpp" +#include "rdbms/StmtTest.hpp" + +#include <gtest/gtest.h> + +namespace unitTests { + +//------------------------------------------------------------------------------ +// Setup +//------------------------------------------------------------------------------ +void cta_rdbms_StmtTest::SetUp() { + using namespace cta::rdbms; + + if(!m_connPool) { + m_login = GetParam()->create(); + const uint64_t maxNbConns = 1; + m_connPool = cta::make_unique<ConnPool>(m_login, maxNbConns); + } + + m_conn = m_connPool->getConn(); + ASSERT_EQ(AutocommitMode::AUTOCOMMIT_ON, m_conn.getAutocommitMode()); + + try { + m_conn.executeNonQuery("DROP TABLE STMT_TEST"); + } catch(...) { + // Do nothing + } + + const std::string createTableSql = getCreateStmtTestTableSql(); + m_conn.executeNonQuery(createTableSql); +} + +//------------------------------------------------------------------------------ +// getCreateStmtTestTableSql +//------------------------------------------------------------------------------ +std::string cta_rdbms_StmtTest::getCreateStmtTestTableSql() { + using namespace cta; + using namespace cta::rdbms; + + try { + std::string sql = + "CREATE TABLE STMT_TEST(" + "DOUBLE_COL FLOAT," + "UINT64_COL NUMERIC(20, 0)," + "STRING_COL VARCHAR(100)," + "BOOL_COL CHAR(1)" + ")"; + + switch(m_login.dbType) { + case Login::DBTYPE_IN_MEMORY: + break; + case Login::DBTYPE_ORACLE: + utils::searchAndReplace(sql, "VARCHAR", "VARCHAR2"); + break; + case Login::DBTYPE_SQLITE: + break; + case Login::DBTYPE_MYSQL: + break; + case Login::DBTYPE_POSTGRESQL: + break; + case Login::DBTYPE_NONE: + { + throw exception::Exception("Cannot create SQL for database type DBTYPE_NONE"); + } + default: + { + std::ostringstream msg; + msg << "Unknown database type: intVal=" << m_login.dbType; + throw exception::Exception(msg.str()); + } + } + + return sql; + } catch(exception::Exception &ex) { + std::ostringstream msg; + msg << __FUNCTION__ << " failed: " << ex.getMessage().str(); + ex.getMessage().str(msg.str()); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// TearDown +//------------------------------------------------------------------------------ +void cta_rdbms_StmtTest::TearDown() { + using namespace cta::rdbms; + try { + m_conn.executeNonQuery("DROP TABLE STMT_TEST"); + } catch(...) { + // Do nothing + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindDouble) { + using namespace cta::rdbms; + + const double insertValue = 1.234; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "DOUBLE_COL) " + "VALUES(" + ":DOUBLE_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindDouble(":DOUBLE_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "DOUBLE_COL AS DOUBLE_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalDouble("DOUBLE_COL"); + + ASSERT_TRUE((bool)selectValue); + + const double diff = insertValue - selectValue.value(); + ASSERT_TRUE(0.000001 > diff); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64) { + using namespace cta::rdbms; + + const uint64_t insertValue = 1234; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "UINT64_COL) " + "VALUES(" + ":UINT64_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindDouble(":UINT64_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "UINT64_COL AS UINT64_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalDouble("UINT64_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64_2_pow_54_minus_2) { + using namespace cta::rdbms; + + // The MySql support in CTA cannot store an unsigned integer greater than + // 2^54-2 + const uint64_t insertValue = 18014398509481982; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "UINT64_COL) " + "VALUES(" + ":UINT64_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindUint64(":UINT64_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "UINT64_COL AS UINT64_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalUint64("UINT64_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindUint64_2_pow_64_minus_1_not_mysql) { + using namespace cta::rdbms; + + if(m_login.dbType == Login::DBTYPE_MYSQL) { + return; + } + + // The MySql support in CTA cannot store an unsigned integer greater than + // 2^54-2 + const uint64_t insertValue = 18446744073709551615U; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "UINT64_COL) " + "VALUES(" + ":UINT64_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindUint64(":UINT64_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "UINT64_COL AS UINT64_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalUint64("UINT64_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindString) { + using namespace cta::rdbms; + + const std::string insertValue = "value"; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "STRING_COL) " + "VALUES(" + ":STRING_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindString(":STRING_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "STRING_COL AS STRING_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalString("STRING_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_true) { + using namespace cta::rdbms; + + const bool insertValue = true; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "BOOL_COL) " + "VALUES(" + ":BOOL_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindBool(":BOOL_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "BOOL_COL AS BOOL_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalBool("BOOL_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +TEST_P(cta_rdbms_StmtTest, insert_with_bindBool_false) { + using namespace cta::rdbms; + + const bool insertValue = false; + + // Insert a row into the test table + { + const char *const sql = + "INSERT INTO STMT_TEST(" + "BOOL_COL) " + "VALUES(" + ":BOOL_COL)"; + auto stmt = m_conn.createStmt(sql); + stmt.bindBool(":BOOL_COL", insertValue); + stmt.executeNonQuery(); + } + + // Select the row back from the table + { + const char *const sql = + "SELECT " + "BOOL_COL AS BOOL_COL " + "FROM " + "STMT_TEST"; + auto stmt = m_conn.createStmt(sql); + auto rset = stmt.executeQuery(); + ASSERT_TRUE(rset.next()); + + const auto selectValue = rset.columnOptionalBool("BOOL_COL"); + + ASSERT_TRUE((bool)selectValue); + + ASSERT_EQ(insertValue,selectValue.value()); + + ASSERT_FALSE(rset.next()); + } +} + +} // namespace unitTests diff --git a/rdbms/StmtTest.hpp b/rdbms/StmtTest.hpp new file mode 100644 index 0000000000000000000000000000000000000000..46dba5489fc34e4ea26d086c97f21742fa8e467b --- /dev/null +++ b/rdbms/StmtTest.hpp @@ -0,0 +1,61 @@ +/* + * The CERN Tape Archive (CTA) project + * Copyright (C) 2015 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "rdbms/LoginFactory.hpp" +#include "rdbms/Conn.hpp" + +#include <gtest/gtest.h> +#include <memory> + +namespace unitTests { + +class cta_rdbms_StmtTest : public ::testing::TestWithParam<cta::rdbms::LoginFactory*> { +protected: + /** + * The database login. + */ + cta::rdbms::Login m_login; + + /** + * The database connection pool. + */ + std::unique_ptr<cta::rdbms::ConnPool> m_connPool; + + /** + * The database connection. + */ + cta::rdbms::Conn m_conn; + + virtual void SetUp(); + + /** + * Returns the SQL to create the STMT_TEST table taking into account any + * differences between the various types of database backend. + * + * @return The SQL to create the STMT_TEST table taking into account any + * differences between the various types of database backend. + */ + std::string getCreateStmtTestTableSql(); + + virtual void TearDown(); + +}; // cta_rdbms_StmtTest + +} // namespace unitTests diff --git a/rdbms/wrapper/Mysql.hpp b/rdbms/wrapper/Mysql.hpp index 327dbba8d1b359bc8a95f36d4592f04cd9778b9d..e47b0606881a49fd0042a4da6cca6168aaa6c721 100644 --- a/rdbms/wrapper/Mysql.hpp +++ b/rdbms/wrapper/Mysql.hpp @@ -99,6 +99,7 @@ class Mysql { enum buffer_types { placeholder_uint64, placeholder_string, + placeholder_double, }; virtual std::string show() = 0; @@ -113,6 +114,7 @@ class Mysql { // following is to access data virtual uint64_t get_uint64() = 0; virtual std::string get_string() = 0; + virtual double get_double() = 0; // helper virtual bool reset() = 0; }; @@ -155,6 +157,10 @@ class Mysql { return std::to_string(val); } + double get_double() { + return val; + } + bool reset() { return false; } @@ -210,6 +216,12 @@ class Mysql { return std::string(val, val+*get_length()); } + // note: allow users try to convert from string to int, + // but users need to catch the exception. + double get_double() { + return std::stod(val); + } + bool reset() { memset(val, 0, buf_sz); @@ -218,6 +230,54 @@ class Mysql { }; + struct Placeholder_Double: Placeholder { + double val; + + Placeholder_Double() + : Placeholder(), val(0) { + + } + + std::string show() override { + std::stringstream ss; + ss << "['" << idx << "' '" << is_null << "' '" << length << "' '" << val << "' '" << get_buffer_length() << "']"; + return ss.str(); + } + + buffer_types get_buffer_type() override { + return placeholder_double; + } + + void* get_buffer() override { + return &val; + } + + unsigned long get_buffer_length() override { + return sizeof(double); + } + + bool get_is_unsigned() override { + return true; + } + + uint64_t get_uint64() override { + return val; + } + + std::string get_string() override { + return std::to_string(val); + } + + double get_double() override { + return val; + } + + bool reset() { + return false; + } + + }; + struct FieldsInfo { FieldsInfo(MYSQL_RES* result_metadata); diff --git a/rdbms/wrapper/MysqlRset.cpp b/rdbms/wrapper/MysqlRset.cpp index a302ceb853ef5325211f1b592a887bd9d57c197a..66a3f649e96d92fff386d2b610a623cc20d22b64 100644 --- a/rdbms/wrapper/MysqlRset.cpp +++ b/rdbms/wrapper/MysqlRset.cpp @@ -134,6 +134,25 @@ optional<uint64_t> MysqlRset::columnOptionalUint64(const std::string &colName) c return optional<uint64_t>(holder->get_uint64()); } +//------------------------------------------------------------------------------ +// columnOptionalDouble +//------------------------------------------------------------------------------ +optional<double> MysqlRset::columnOptionalDouble(const std::string &colName) const { + if (not m_fields.exists(colName)) { + throw exception::Exception(std::string(__FUNCTION__) + " column does not exist: " + colName); + return nullopt; + } + + Mysql::Placeholder* holder = m_stmt.columnHolder(colName); // m_holders[idx]; + + // the value can be null + if (holder->get_is_null() and *holder->get_is_null()) { + return nullopt; + } + + return optional<double>(holder->get_double()); +} + } // namespace wrapper } // namespace rdbms } // namespace cta diff --git a/rdbms/wrapper/MysqlRset.hpp b/rdbms/wrapper/MysqlRset.hpp index 27a77879da5d7341756f1afb995ab4874b9558ce..ff263a397c9d59fde25476e5f8bcf778752a532c 100644 --- a/rdbms/wrapper/MysqlRset.hpp +++ b/rdbms/wrapper/MysqlRset.hpp @@ -96,6 +96,16 @@ public: */ optional<uint64_t> columnOptionalUint64(const std::string &colName) const override; + /** + * Returns the value of the specified column as a double. + * + * This method will return a null column value as an optional with no value. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + optional<double> columnOptionalDouble(const std::string &colName) const override; + private: /** diff --git a/rdbms/wrapper/MysqlStmt.cpp b/rdbms/wrapper/MysqlStmt.cpp index 8a3811424425462242980a20ce1c82cd0610b6b6..6d22de3bc87deb981ca45705b33976fb2fb0c0a0 100644 --- a/rdbms/wrapper/MysqlStmt.cpp +++ b/rdbms/wrapper/MysqlStmt.cpp @@ -189,14 +189,59 @@ void MysqlStmt::bindOptionalUint64(const std::string ¶mName, const optional< const unsigned int paramIdx = getParamIdx(paramName); // starts from 1. const unsigned int idx = paramIdx - 1; - Mysql::Placeholder_Uint64* holder = dynamic_cast<Mysql::Placeholder_Uint64*>(m_placeholder[idx]); + Mysql::Placeholder_Double* holder = dynamic_cast<Mysql::Placeholder_Double*>(m_placeholder[idx]); // if already exists, try to reuse if (!holder and m_placeholder[idx]) { throw exception::Exception(std::string(__FUNCTION__) + " can't cast from Placeholder to Placeholder_Uint64. " ); } if (!holder) { - holder = new Mysql::Placeholder_Uint64(); + holder = new Mysql::Placeholder_Double(); + holder->idx = idx; + holder->length = sizeof(uint64_t); + } + + if (paramValue) { + holder->val = paramValue.value(); + } else { + holder->is_null = true; + } + // delete m_placeholder[idx]; // remove the previous placeholder + + m_placeholder[idx] = holder; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// bindDouble +//------------------------------------------------------------------------------ +void MysqlStmt::bindDouble(const std::string ¶mName, const double paramValue) { + try { + bindOptionalDouble(paramName, paramValue); + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// bindOptionalDouble +//------------------------------------------------------------------------------ +void MysqlStmt::bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) { + try { + const unsigned int paramIdx = getParamIdx(paramName); // starts from 1. + const unsigned int idx = paramIdx - 1; + + Mysql::Placeholder_Double* holder = dynamic_cast<Mysql::Placeholder_Double*>(m_placeholder[idx]); + // if already exists, try to reuse + if (!holder and m_placeholder[idx]) { + throw exception::Exception(std::string(__FUNCTION__) + " can't cast from Placeholder to Placeholder_Double. " ); + } + + if (!holder) { + holder = new Mysql::Placeholder_Double(); holder->idx = idx; holder->length = sizeof(uint64_t); } @@ -393,6 +438,9 @@ bool MysqlStmt::do_bind() { case Mysql::Placeholder::placeholder_string: bind[idx].buffer_type = MYSQL_TYPE_STRING; break; + case Mysql::Placeholder::placeholder_double: + bind[idx].buffer_type = MYSQL_TYPE_DOUBLE; + break; default: throw exception::Exception(std::string(__FUNCTION__) + " Unknown buffer type in placeholder " + std::to_string(holder->get_buffer_type())); break; @@ -473,6 +521,14 @@ bool MysqlStmt::do_bind_results() { bind[i].buffer_type = MYSQL_TYPE_STRING; } break; + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + { + Mysql::Placeholder_Double* holder_ = new Mysql::Placeholder_Double(); + holder = holder_; + bind[i].buffer_type = MYSQL_TYPE_DOUBLE; + } + break; default: throw exception::Exception(std::string(__FUNCTION__) + " unsupport buffer type: " + std::to_string(buffer_type)); break; diff --git a/rdbms/wrapper/MysqlStmt.hpp b/rdbms/wrapper/MysqlStmt.hpp index 96bca5374b42d6f5bf1c7472e0170acb16f7e7d1..5f36b0f19c8637d24cb9825ff81d12f02c6d50df 100644 --- a/rdbms/wrapper/MysqlStmt.hpp +++ b/rdbms/wrapper/MysqlStmt.hpp @@ -100,6 +100,22 @@ public: */ void bindOptionalUint64(const std::string ¶mName, const optional<uint64_t> ¶mValue) override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindDouble(const std::string ¶mName, const double paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) override; + /** * Binds an SQL parameter of type string. * diff --git a/rdbms/wrapper/OcciRset.cpp b/rdbms/wrapper/OcciRset.cpp index 43553fdd9aea7372e9b9a1cd224d31c5b6cb94b9..e1e16e158c5f858e8d73a5ed05c6ce425bd18ef8 100644 --- a/rdbms/wrapper/OcciRset.cpp +++ b/rdbms/wrapper/OcciRset.cpp @@ -172,6 +172,28 @@ optional<uint64_t> OcciRset::columnOptionalUint64(const std::string &colName) co } } +//------------------------------------------------------------------------------ +// columnOptionalDouble +//------------------------------------------------------------------------------ +optional<double> OcciRset::columnOptionalDouble(const std::string &colName) const { + try { + threading::Mutex locker(m_mutex); + + const int colIdx = m_colNameToIdx.getIdx(colName); + if(m_rset->isNull(colIdx)) { + return nullopt; + } else { + return m_rset->getDouble(colIdx); + } + } catch(exception::Exception &ne) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " + + ne.getMessage().str()); + } catch(std::exception &se) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + m_stmt.getSql() + ": " + + se.what()); + } +} + } // namespace wrapper } // namespace rdbms } // namespace cta diff --git a/rdbms/wrapper/OcciRset.hpp b/rdbms/wrapper/OcciRset.hpp index 4750b9cee2d9a915ecd9cd4a1f25336eedcb56a1..27fc061f8c0a90a48018361343b9c05f64eeae5c 100644 --- a/rdbms/wrapper/OcciRset.hpp +++ b/rdbms/wrapper/OcciRset.hpp @@ -100,6 +100,16 @@ public: */ optional<uint64_t> columnOptionalUint64(const std::string &colName) const override; + /** + * Returns the value of the specified column as a double. + * + * This method will return a null column value as an optional with no value. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + optional<double> columnOptionalDouble(const std::string &colName) const override; + private: /** diff --git a/rdbms/wrapper/OcciStmt.cpp b/rdbms/wrapper/OcciStmt.cpp index 4cb0d3b2d6a48bca3156e231e859fb021140f01a..ced47e61d31e3a53de3bb3f05be326622e22e135 100644 --- a/rdbms/wrapper/OcciStmt.cpp +++ b/rdbms/wrapper/OcciStmt.cpp @@ -115,6 +115,38 @@ void OcciStmt::bindOptionalUint64(const std::string ¶mName, const optional<u } } +//------------------------------------------------------------------------------ +// bindDouble +//------------------------------------------------------------------------------ +void OcciStmt::bindDouble(const std::string ¶mName, const double paramValue) { + try { + bindOptionalDouble(paramName, paramValue); + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// bindOptionalDouble +//------------------------------------------------------------------------------ +void OcciStmt::bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) { + try { + const unsigned paramIdx = getParamIdx(paramName); + if(paramValue) { + // Bind integer as a string in order to support 64-bit integers + m_stmt->setDouble(paramIdx, paramValue.value()); + } else { + m_stmt->setNull(paramIdx, oracle::occi::OCCIDOUBLE); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + } catch(std::exception &se) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + se.what()); + } +} + //------------------------------------------------------------------------------ // bind //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/OcciStmt.hpp b/rdbms/wrapper/OcciStmt.hpp index b95a715542df24bd1fe655439fa60534dcebd124..6db7e1b80ab028ab14cef37271636c4595643ef7 100644 --- a/rdbms/wrapper/OcciStmt.hpp +++ b/rdbms/wrapper/OcciStmt.hpp @@ -97,6 +97,22 @@ public: */ void bindOptionalUint64(const std::string ¶mName, const optional<uint64_t> ¶mValue) override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindDouble(const std::string ¶mName, const double paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) override; + /** * Binds an SQL parameter of type string. * diff --git a/rdbms/wrapper/PostgresRset.cpp b/rdbms/wrapper/PostgresRset.cpp index 3ba8ab0de5ff793ac34709f0ab75231de8407a49..8ade84da2175cf0c3d74b9080fbaaaa04b32db90 100644 --- a/rdbms/wrapper/PostgresRset.cpp +++ b/rdbms/wrapper/PostgresRset.cpp @@ -124,6 +124,34 @@ optional<uint64_t> PostgresRset::columnOptionalUint64(const std::string &colName return utils::toUint64(stringValue); } +//------------------------------------------------------------------------------ +// columnOptionalDouble +//------------------------------------------------------------------------------ +optional<double> PostgresRset::columnOptionalDouble(const std::string &colName) const { + if (nullptr == m_resItr->get()) { + throw exception::Exception(std::string(__FUNCTION__) + " no row available"); + } + + const int ifield = PQfnumber(m_resItr->get(), colName.c_str()); + if (ifield < 0) { + throw exception::Exception(std::string(__FUNCTION__) + " column does not exist: " + colName); + } + + // the value can be null + if (PQgetisnull(m_resItr->get(), 0, ifield)) { + return nullopt; + } + + const std::string stringValue(PQgetvalue(m_resItr->get(), 0, ifield)); + + if(!utils::isValidDecimal(stringValue)) { + throw exception::Exception(std::string("Column ") + colName + " contains the value " + stringValue + + " which is not a valid decimal"); + } + + return utils::toDouble(stringValue); +} + //------------------------------------------------------------------------------ // getSql //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/PostgresRset.hpp b/rdbms/wrapper/PostgresRset.hpp index 1abc4fa9c2cae01731905c59d066e82c5d253a7e..4936da35e9a70fde804492c86b0903b5a585dbc1 100644 --- a/rdbms/wrapper/PostgresRset.hpp +++ b/rdbms/wrapper/PostgresRset.hpp @@ -80,6 +80,16 @@ public: */ optional<uint64_t> columnOptionalUint64(const std::string &colName) const override; + /** + * Returns the value of the specified column as a double. + * + * This method will return a null column value as an optional with no value. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + optional<double> columnOptionalDouble(const std::string &colName) const override; + /** * Returns the SQL statement. * diff --git a/rdbms/wrapper/PostgresStmt.cpp b/rdbms/wrapper/PostgresStmt.cpp index 2c3882516a1451702d089e889aa8d1b94b5ff4ca..d00e43f99802cf5aca845e038bc2189028486198 100644 --- a/rdbms/wrapper/PostgresStmt.cpp +++ b/rdbms/wrapper/PostgresStmt.cpp @@ -152,6 +152,45 @@ void PostgresStmt::bindUint64(const std::string ¶mName, const uint64_t param } } +//------------------------------------------------------------------------------ +// bindDouble +//------------------------------------------------------------------------------ +void PostgresStmt::bindDouble(const std::string ¶mName, const double paramValue) { + try { + bindOptionalDouble(paramName, paramValue); + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// bindOptionalDouble +//------------------------------------------------------------------------------ +void PostgresStmt::bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) { + threading::RWLockWrLocker locker(m_lock); + + try { + const unsigned int paramIdx = getParamIdx(paramName); // starts from 1. + + if (paramIdx==0 || paramIdx>m_paramValues.size()) { + throw exception::Exception(std::string("Bad index for paramName ") + paramName); + } + + const unsigned int idx = paramIdx - 1; + if (paramValue) { + // we must not cause the vector m_paramValues to resize, otherwise the c-pointers can be invalidated + m_paramValues[idx] = std::to_string(paramValue.value()); + m_paramValuesPtrs[idx] = m_paramValues[idx].c_str(); + } else { + m_paramValues[idx].clear(); + m_paramValuesPtrs[idx] = nullptr; + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + } +} + //------------------------------------------------------------------------------ // clear //------------------------------------------------------------------------------ diff --git a/rdbms/wrapper/PostgresStmt.hpp b/rdbms/wrapper/PostgresStmt.hpp index e0e91648a471753e6985f11cf63875ef15ce0286..396b09c75799ae14e5d2349ec024d262d0907e70 100644 --- a/rdbms/wrapper/PostgresStmt.hpp +++ b/rdbms/wrapper/PostgresStmt.hpp @@ -103,6 +103,22 @@ public: */ void bindUint64(const std::string ¶mName, const uint64_t paramValue) override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindDouble(const std::string ¶mName, const double paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) override; + /** * Clears the prepared statement so that it is ready to be reused. */ diff --git a/rdbms/wrapper/RsetWrapper.hpp b/rdbms/wrapper/RsetWrapper.hpp index 88a210a59c6ce5e587db80933e24e9dfa3670e14..aceff03b11e04242f7d86695273f877659761eeb 100644 --- a/rdbms/wrapper/RsetWrapper.hpp +++ b/rdbms/wrapper/RsetWrapper.hpp @@ -82,6 +82,16 @@ public: */ virtual optional<uint64_t> columnOptionalUint64(const std::string &colName) const = 0; + /** + * Returns the value of the specified column as a double. + * + * This method will return a null column value as an optional with no value. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + virtual optional<double> columnOptionalDouble(const std::string &colName) const = 0; + }; // class RsetWrapper } // namespace wrapper diff --git a/rdbms/wrapper/SqliteRset.cpp b/rdbms/wrapper/SqliteRset.cpp index fa5870c957bea2ea35ee62ae32d06c7744d581fc..9aea8f932faa8f497e81f03c1812fd35d2784301 100644 --- a/rdbms/wrapper/SqliteRset.cpp +++ b/rdbms/wrapper/SqliteRset.cpp @@ -254,6 +254,22 @@ optional<uint64_t> SqliteRset::columnOptionalUint64(const std::string &colName) } } +//------------------------------------------------------------------------------ +// columnOptionalDouble +//------------------------------------------------------------------------------ +optional<double> SqliteRset::columnOptionalDouble(const std::string &colName) const { + try { + const ColumnNameToIdxAndType::IdxAndType idxAndType = m_colNameToIdxAndType.getIdxAndType(colName); + if(SQLITE_NULL == idxAndType.colType) { + return nullopt; + } else { + return optional<double>(sqlite3_column_double(m_stmt.get(), idxAndType.colIdx)); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + } // namespace wrapper } // namespace rdbms } // namespace cta diff --git a/rdbms/wrapper/SqliteRset.hpp b/rdbms/wrapper/SqliteRset.hpp index d9e7cdeabe10021601aae59d29c659dd42d224ff..bc9262d53594eec9ef8fd493665ab75917483281 100644 --- a/rdbms/wrapper/SqliteRset.hpp +++ b/rdbms/wrapper/SqliteRset.hpp @@ -95,6 +95,16 @@ public: */ optional<uint64_t> columnOptionalUint64(const std::string &colName) const override; + /** + * Returns the value of the specified column as a double. + * + * This method will return a null column value as an optional with no value. + * + * @param colName The name of the column. + * @return The value of the specified column. + */ + optional<double> columnOptionalDouble(const std::string &colName) const override; + private: /** diff --git a/rdbms/wrapper/SqliteStmt.cpp b/rdbms/wrapper/SqliteStmt.cpp index 059b60aed4947c4afd603cffd8553479dcb567cc..7f09732a3751552a7394feb53e6547312fe08d04 100644 --- a/rdbms/wrapper/SqliteStmt.cpp +++ b/rdbms/wrapper/SqliteStmt.cpp @@ -171,9 +171,39 @@ void SqliteStmt::bindOptionalUint64(const std::string ¶mName, const optional bindRc = sqlite3_bind_null(m_stmt, paramIdx); } if(SQLITE_OK != bindRc) { - exception::Exception ex; - ex.getMessage() << "sqlite3_bind_int64() failed: " << Sqlite::rcToStr(bindRc); - throw ex; + throw exception::Exception(Sqlite::rcToStr(bindRc)); + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + + getSqlForException() + ": " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// bindDouble +//------------------------------------------------------------------------------ +void SqliteStmt::bindDouble(const std::string ¶mName, const double paramValue) { + try { + bindOptionalDouble(paramName, paramValue); + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// bindOptionalDouble +//------------------------------------------------------------------------------ +void SqliteStmt::bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) { + try { + const unsigned int paramIdx = getParamIdx(paramName); + int bindRc = 0; + if(paramValue) { + bindRc = sqlite3_bind_double(m_stmt, paramIdx, paramValue.value()); + } else { + bindRc = sqlite3_bind_null(m_stmt, paramIdx); + } + if(SQLITE_OK != bindRc) { + throw exception::Exception(Sqlite::rcToStr(bindRc)); } } catch(exception::Exception &ex) { throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + @@ -209,10 +239,7 @@ void SqliteStmt::bindOptionalString(const std::string ¶mName, const optional bindRc = sqlite3_bind_null(m_stmt, paramIdx); } if(SQLITE_OK != bindRc) { - exception::Exception ex; - - ex.getMessage() << "sqlite3_bind_text() failed: " << Sqlite::rcToStr(bindRc); - throw ex; + throw exception::Exception(Sqlite::rcToStr(bindRc)); } } catch(exception::Exception &ex) { throw exception::Exception(std::string(__FUNCTION__) + " failed for SQL statement " + diff --git a/rdbms/wrapper/SqliteStmt.hpp b/rdbms/wrapper/SqliteStmt.hpp index 0bb632fa6d3e9ca0b811c5fa9d13c751ed9d3524..54f104b845fc2f49f229a2d35a3a55455f7f8cdf 100644 --- a/rdbms/wrapper/SqliteStmt.hpp +++ b/rdbms/wrapper/SqliteStmt.hpp @@ -91,6 +91,22 @@ public: */ void bindOptionalUint64(const std::string ¶mName, const optional<uint64_t> ¶mValue) override; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindDouble(const std::string ¶mName, const double paramValue) override; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + void bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) override; + /** * Binds an SQL parameter of type string. * diff --git a/rdbms/wrapper/StmtWrapper.hpp b/rdbms/wrapper/StmtWrapper.hpp index f3472a74f0d066431342950fc4d1b112f9021513..e14221e1e96271c53bdae88a3c502988d46444f1 100644 --- a/rdbms/wrapper/StmtWrapper.hpp +++ b/rdbms/wrapper/StmtWrapper.hpp @@ -111,6 +111,22 @@ public: */ virtual void bindOptionalUint64(const std::string ¶mName, const optional<uint64_t> ¶mValue) = 0; + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + virtual void bindDouble(const std::string ¶mName, const double paramValue) = 0; + + /** + * Binds an SQL parameter. + * + * @param paramName The name of the parameter. + * @param paramValue The value to be bound. + */ + virtual void bindOptionalDouble(const std::string ¶mName, const optional<double> ¶mValue) = 0; + /** * Binds an SQL parameter. * diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp index f61b74c340c16b191988dd6d348ee6e33fb8d1d2..825b7a67c217feed73c74ad011c0863d33a233f4 100644 --- a/scheduler/OStoreDB/OStoreDB.cpp +++ b/scheduler/OStoreDB/OStoreDB.cpp @@ -1377,7 +1377,7 @@ std::list<common::dataStructures::RepackInfo> OStoreDB::getRepackInfo() { // First, try to get the address of of the repack index lockfree. try { ri.setAddress(re.getRepackIndexAddress()); - } catch (RootEntry::NotAllocated &) { + } catch (cta::exception::Exception &) { return ret; } ri.fetchNoLock(); @@ -1402,7 +1402,7 @@ common::dataStructures::RepackInfo OStoreDB::getRepackInfo(const std::string& vi // First, try to get the address of of the repack index lockfree. try { ri.setAddress(re.getRepackIndexAddress()); - } catch (RootEntry::NotAllocated &) { + } catch (cta::exception::Exception &) { throw NoSuchRepackRequest("In OStoreDB::getRepackInfo(): No repack request for this VID (index not present)."); } ri.fetchNoLock(); @@ -1479,7 +1479,7 @@ void OStoreDB::populateRepackRequestsStatistics(RootEntry & re, SchedulerDatabas objectstore::RepackIndex ri(m_objectStore); try { ri.setAddress(re.getRepackIndexAddress()); - } catch (RootEntry::NotAllocated &) { + } catch (cta::exception::Exception &) { return; } ri.fetchNoLock(); @@ -1491,7 +1491,7 @@ void OStoreDB::populateRepackRequestsStatistics(RootEntry & re, SchedulerDatabas } // Ensure existence of stats for important statuses typedef common::dataStructures::RepackInfo::Status Status; - for (auto s: {Status::Pending, Status::ToExpand, Status::Starting}) { + for (auto s: {Status::Pending, Status::ToExpand, Status::Starting, Status::Running}) { stats[s] = 0; } auto fet = fetchers.begin(); @@ -1793,7 +1793,6 @@ void OStoreDB::RepackRetrieveSuccessesReportBatch::report(log::LogContext& lc) { objectstore::ScopedExclusiveLock rrl(m_repackRequest); timingList.insertAndReset("successStatsLockTime", t); m_repackRequest.fetch(); - m_repackRequest.setStatus(common::dataStructures::RepackInfo::Status::Running); timingList.insertAndReset("successStatsFetchTime", t); m_repackRequest.reportRetriveSuccesses(ssl); timingList.insertAndReset("successStatsUpdateTime", t); @@ -2077,13 +2076,16 @@ void OStoreDB::RepackRequest::setLastExpandedFSeq(uint64_t fseq){ //------------------------------------------------------------------------------ // OStoreDB::RepackRequest::addSubrequests() //------------------------------------------------------------------------------ -void OStoreDB::RepackRequest::addSubrequests(std::list<Subrequest>& repackSubrequests, cta::common::dataStructures::ArchiveRoute::FullMap& archiveRoutesMap, uint64_t maxFSeqLowBound, log::LogContext& lc) { +void OStoreDB::RepackRequest::addSubrequestsAndUpdateStats(std::list<Subrequest>& repackSubrequests, cta::common::dataStructures::ArchiveRoute::FullMap& archiveRoutesMap, uint64_t maxFSeqLowBound, const uint64_t maxAddedFSeq, const cta::SchedulerDatabase::RepackRequest::TotalStatsFiles &totalStatsFiles, log::LogContext& lc) { // We need to prepare retrieve requests names and reference them, create them, enqueue them. objectstore::ScopedExclusiveLock rrl (m_repackRequest); m_repackRequest.fetch(); std::set<uint64_t> fSeqs; for (auto rsr: repackSubrequests) fSeqs.insert(rsr.fSeq); auto subrequestsNames = m_repackRequest.getOrPrepareSubrequestInfo(fSeqs, *m_oStoreDB.m_agentReference); + m_repackRequest.setTotalStats(totalStatsFiles); + uint64_t fSeq = std::max(maxFSeqLowBound+1, maxAddedFSeq + 1); + m_repackRequest.setLastExpandedFSeq(fSeq); // We make sure the references to subrequests exist persistently before creating them. m_repackRequest.commit(); // We keep holding the repack request lock: we need to ensure de deleted boolean of each subrequest does @@ -2294,32 +2296,9 @@ void OStoreDB::RepackRequest::expandDone() { // We are now done with the repack request. We can set its status. ScopedExclusiveLock rrl(m_repackRequest); m_repackRequest.fetch(); - // After expansion, 2 statuses are possible: starting (nothing reported as done) or running (anything reported as done). - // We can find that out from the statistics... - typedef objectstore::RepackRequest::StatsType StatsType; - bool running=false; - auto stats=m_repackRequest.getStats(); - for (auto t: {StatsType::ArchiveFailure, StatsType::ArchiveSuccess, StatsType::RetrieveSuccess, StatsType::RetrieveFailure}) { - if (stats.at(t).files) { - running=true; - break; - } - } - if(stats.at(StatsType::RetrieveTotal).files == m_repackRequest.getInfo().totalFilesToRetrieve){ - m_repackRequest.setExpandFinished(true); - } - typedef common::dataStructures::RepackInfo::Status Status; - m_repackRequest.setStatus(running? Status::Running: Status::Starting); - m_repackRequest.commit(); -} -void OStoreDB::RepackRequest::setTotalStats(const TotalStatsFiles& stats){ - ScopedExclusiveLock rrl(m_repackRequest); - m_repackRequest.fetch(); - m_repackRequest.setTotalFileToArchive(stats.totalFilesToArchive); - m_repackRequest.setTotalBytesToArchive(stats.totalBytesToArchive); - m_repackRequest.setTotalFileToRetrieve(stats.totalFilesToRetrieve); - m_repackRequest.setTotalBytesToRetrieve(stats.totalBytesToRetrieve); + m_repackRequest.setExpandFinished(true); + m_repackRequest.setStatus(); m_repackRequest.commit(); } @@ -2333,6 +2312,36 @@ void OStoreDB::RepackRequest::fail() { m_repackRequest.commit(); } +void OStoreDB::RepackRequest::requeueInToExpandQueue(log::LogContext& lc){ + ScopedExclusiveLock rrl(m_repackRequest); + m_repackRequest.fetch(); + std::string previousOwner = m_repackRequest.getOwner(); + m_repackRequest.setStatus(); + m_repackRequest.commit(); + rrl.release(); + std::unique_ptr<cta::objectstore::RepackRequest> rr(new cta::objectstore::RepackRequest(m_repackRequest.getAddressIfSet(),m_oStoreDB.m_objectStore)); + typedef objectstore::ContainerAlgorithms<RepackQueue, RepackQueueToExpand> RQTEAlgo; + RQTEAlgo rqteAlgo(m_oStoreDB.m_objectStore, *m_oStoreDB.m_agentReference); + RQTEAlgo::InsertedElement::list insertedElements; + insertedElements.push_back(RQTEAlgo::InsertedElement()); + insertedElements.back().repackRequest = std::move(rr); + rqteAlgo.referenceAndSwitchOwnership(nullopt, previousOwner, insertedElements, lc); +} + +void OStoreDB::RepackRequest::setExpandStartedAndChangeStatus(){ + ScopedExclusiveLock rrl(m_repackRequest); + m_repackRequest.fetch(); + m_repackRequest.setExpandStarted(true); + m_repackRequest.setStatus(); + m_repackRequest.commit(); +} + +void OStoreDB::RepackRequest::fillLastExpandedFSeqAndTotalStatsFile(uint64_t& fSeq, TotalStatsFiles& totalStatsFiles) { + ScopedExclusiveLock rrl(m_repackRequest); + m_repackRequest.fetch(); + fSeq = m_repackRequest.getLastExpandedFSeq(); + totalStatsFiles = m_repackRequest.getTotalStatsFile(); +} //------------------------------------------------------------------------------ // OStoreDB::cancelRepack() @@ -2345,7 +2354,7 @@ void OStoreDB::cancelRepack(const std::string& vid, log::LogContext & lc) { // First, try to get the address of of the repack index lockfree. try { ri.setAddress(re.getRepackIndexAddress()); - } catch (RootEntry::NotAllocated &) { + } catch (cta::exception::Exception &) { throw NoSuchRepackRequest("In OStoreDB::cancelRepack(): No repack request for this VID (index not present)."); } ri.fetchNoLock(); diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp index 830a3ac1f8fca8a9820eb326493c117ef4a945d1..a5daab47a625e58bf97a5e412ea38a1073e1d1c4 100644 --- a/scheduler/OStoreDB/OStoreDB.hpp +++ b/scheduler/OStoreDB/OStoreDB.hpp @@ -342,13 +342,15 @@ public: public: RepackRequest(const std::string &jobAddress, OStoreDB &oStoreDB) : m_oStoreDB(oStoreDB), m_repackRequest(jobAddress, m_oStoreDB.m_objectStore){} - void addSubrequests(std::list<Subrequest>& repackSubrequests, cta::common::dataStructures::ArchiveRoute::FullMap& archiveRoutesMap, - uint64_t maxFSeqLowBound, log::LogContext& lc) override; + void addSubrequestsAndUpdateStats(std::list<Subrequest>& repackSubrequests, cta::common::dataStructures::ArchiveRoute::FullMap& archiveRoutesMap, + uint64_t maxFSeqLowBound, const uint64_t maxAddedFSeq, const TotalStatsFiles &totalStatsFiles, log::LogContext& lc) override; void expandDone() override; void fail() override; + void requeueInToExpandQueue(log::LogContext& lc) override; + void setExpandStartedAndChangeStatus() override; + void fillLastExpandedFSeqAndTotalStatsFile(uint64_t& fSeq, TotalStatsFiles& totalStatsFiles) override; uint64_t getLastExpandedFSeq() override; void setLastExpandedFSeq(uint64_t fseq) override; - void setTotalStats(const TotalStatsFiles& stats) override; private: OStoreDB & m_oStoreDB; diff --git a/scheduler/RepackRequestManager.cpp b/scheduler/RepackRequestManager.cpp index 41d511b5c495a8b7df7c08ef4a7ed6b84a2b68bc..cf5fbf7b6adc9ef497334c9eafbe8a5384c3a218 100644 --- a/scheduler/RepackRequestManager.cpp +++ b/scheduler/RepackRequestManager.cpp @@ -37,13 +37,8 @@ void RepackRequestManager::runOnePass(log::LogContext& lc) { std::unique_ptr<cta::RepackRequest> repackRequest = m_scheduler.getNextRepackRequestToExpand(); if(repackRequest != nullptr){ //We have a RepackRequest that has the status ToExpand, expand it - timingList.insertAndReset("expandRepackRequestTime", t); try{ m_scheduler.expandRepackRequest(repackRequest,timingList,t,lc); - log::ScopedParamContainer params(lc); - params.add("tapeVid",repackRequest->getRepackInfo().vid); - timingList.addToLog(params); - lc.log(log::INFO, "In RepackRequestManager::runOnePass(): Repack Request expanded"); } catch(const cta::exception::Exception &e){ lc.log(log::ERR,e.what()); repackRequest->fail(); diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp index 29f7526c805257924ae0e596e6bfef8e1674f193..6d6670763e1886d6395321c1db83e82839020916 100644 --- a/scheduler/Scheduler.cpp +++ b/scheduler/Scheduler.cpp @@ -317,6 +317,22 @@ void Scheduler::queueLabel(const common::dataStructures::SecurityIdentity &cliId throw exception::Exception(std::string("Not implemented: ") + __PRETTY_FUNCTION__); } +void Scheduler::checkTapeFullBeforeRepack(std::string vid){ + std::set<std::string> vidToRepack; + vidToRepack.insert(vid); + try{ + auto vidToTapesMap = m_catalogue.getTapesByVid(vidToRepack); //throws an exception if the vid is not found on the database + cta::common::dataStructures::Tape tapeToCheck = vidToTapesMap.at(vid); + if(!tapeToCheck.full){ + throw exception::UserError("You must set the tape as full before repacking it."); + } + } catch(const exception::UserError& userEx){ + throw userEx; + } catch(const cta::exception::Exception & ex){ + throw exception::UserError("The VID provided for repacking does not exist"); + } +} + //------------------------------------------------------------------------------ // repack //------------------------------------------------------------------------------ @@ -326,6 +342,7 @@ void Scheduler::queueRepack(const common::dataStructures::SecurityIdentity &cliI if (vid.empty()) throw exception::UserError("Empty VID name."); if (bufferURL.empty()) throw exception::UserError("Empty buffer URL."); utils::Timer t; + checkTapeFullBeforeRepack(vid); m_db.queueRepack(vid, bufferURL, repackType, lc); log::TimingList tl; tl.insertAndReset("schedulerDbTime", t); @@ -411,13 +428,26 @@ std::unique_ptr<RepackRequest> Scheduler::getNextRepackRequestToExpand() { return nullptr; } +//------------------------------------------------------------------------------ +// setRepackRequestExpansionTimeLimit +//------------------------------------------------------------------------------ +void Scheduler::setRepackRequestExpansionTimeLimit(const double& time) { + m_repackRequestExpansionTimeLimit = time; +} + +//------------------------------------------------------------------------------ +// getRepackRequestExpansionTimeLimit +//------------------------------------------------------------------------------ +double Scheduler::getRepackRequestExpansionTimeLimit() const { + return m_repackRequestExpansionTimeLimit; +} + //------------------------------------------------------------------------------ // expandRepackRequest //------------------------------------------------------------------------------ -void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackRequest, log::TimingList&, utils::Timer&, log::LogContext& lc) { +void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackRequest, log::TimingList& timingList, utils::Timer& t, log::LogContext& lc) { std::list<common::dataStructures::ArchiveFile> files; auto repackInfo = repackRequest->getRepackInfo(); - cta::SchedulerDatabase::RepackRequest::TotalStatsFiles totalStatsFile; typedef cta::common::dataStructures::RepackInfo::Type RepackType; if (repackInfo.type != RepackType::MoveOnly) { @@ -430,6 +460,7 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques //We need to get the ArchiveRoutes to allow the retrieval of the tapePool in which the //tape where the file is is located std::list<common::dataStructures::ArchiveRoute> routes = m_catalogue.getArchiveRoutes(); + timingList.insertAndReset("catalogueGetArchiveRoutesTime",t); //To identify the routes, we need to have both the dist instance name and the storage class name //thus, the key of the map is a pair of string cta::common::dataStructures::ArchiveRoute::FullMap archiveRoutesMap; @@ -437,8 +468,12 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques //insert the route into the map to allow a quick retrieval archiveRoutesMap[std::make_pair(route.diskInstanceName,route.storageClassName)][route.copyNb] = route; } - uint64_t fSeq = repackRequest->m_dbReq->getLastExpandedFSeq() + 1; + uint64_t fSeq; + cta::SchedulerDatabase::RepackRequest::TotalStatsFiles totalStatsFile; + repackRequest->m_dbReq->fillLastExpandedFSeqAndTotalStatsFile(fSeq,totalStatsFile); + timingList.insertAndReset("fillTotalStatsFileBeforeExpandTime",t); cta::catalogue::ArchiveFileItor archiveFilesForCatalogue = m_catalogue.getArchiveFilesForRepackItor(repackInfo.vid, fSeq); + timingList.insertAndReset("catalogueGetArchiveFilesForRepackItorTime",t); std::stringstream dirBufferURL; dirBufferURL << repackInfo.repackBufferBaseURL << "/" << repackInfo.vid << "/"; cta::disk::DirectoryFactory dirFactory; @@ -450,11 +485,14 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques } else { dir->mkdir(); } - while(archiveFilesForCatalogue.hasMore()) { + double elapsedTime = 0; + bool stopExpansion = false; + while(archiveFilesForCatalogue.hasMore() && !stopExpansion) { size_t filesCount = 0; uint64_t maxAddedFSeq = 0; std::list<SchedulerDatabase::RepackRequest::Subrequest> retrieveSubrequests; - while(filesCount < c_defaultMaxNbFilesForRepack && archiveFilesForCatalogue.hasMore()) + repackRequest->m_dbReq->setExpandStartedAndChangeStatus(); + while(filesCount < c_defaultMaxNbFilesForRepack && !stopExpansion && archiveFilesForCatalogue.hasMore()) { filesCount++; fSeq++; @@ -487,8 +525,8 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques cta::disk::DiskFileFactory fileFactory("",0,radosStriperPool); cta::disk::ReadFile *fileReader = fileFactory.createReadFile(dirBufferURL.str() + fileName.str()); if(fileReader->size() == archiveFile.fileSize){ - createArchiveSubrequest = true; - retrieveSubrequests.pop_back(); + /*createArchiveSubrequest = true; + retrieveSubrequests.pop_back();*/ //TODO : We don't want to retrieve the file again, create archive subrequest } } @@ -516,17 +554,27 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques retrieveSubRequest.fileBufferURL = dirBufferURL.str() + fileName.str(); } } + stopExpansion = (elapsedTime >= m_repackRequestExpansionTimeLimit); } // Note: the highest fSeq will be recorded internally in the following call. // We know that the fSeq processed on the tape are >= initial fSeq + filesCount - 1 (or fSeq - 1 as we counted). // We pass this information to the db for recording in the repack request. This will allow restarting from the right // value in case of crash. - repackRequest->m_dbReq->setTotalStats(totalStatsFile); - repackRequest->m_dbReq->addSubrequests(retrieveSubrequests, archiveRoutesMap, fSeq - 1, lc); - fSeq = std::max(fSeq, maxAddedFSeq + 1); - repackRequest->m_dbReq->setLastExpandedFSeq(fSeq); + repackRequest->m_dbReq->addSubrequestsAndUpdateStats(retrieveSubrequests, archiveRoutesMap, fSeq - 1, maxAddedFSeq, totalStatsFile, lc); + timingList.insertAndReset("addSubrequestsAndUpdateStatsTime",t); + } + log::ScopedParamContainer params(lc); + params.add("tapeVid",repackInfo.vid); + timingList.addToLog(params); + if(archiveFilesForCatalogue.hasMore()){ + if(stopExpansion){ + repackRequest->m_dbReq->requeueInToExpandQueue(lc); + lc.log(log::INFO,"Expansion time reached, Repack Request requeued in ToExpand queue."); + } + } else { + repackRequest->m_dbReq->expandDone(); + lc.log(log::INFO,"In Scheduler::expandRepackRequest(), repack request expanded"); } - repackRequest->m_dbReq->expandDone(); } //------------------------------------------------------------------------------ diff --git a/scheduler/Scheduler.hpp b/scheduler/Scheduler.hpp index 5448685c72604d977427db786523ac86053b9266..d0e2aa2985b6bd7078d081d91a10966abd082262 100644 --- a/scheduler/Scheduler.hpp +++ b/scheduler/Scheduler.hpp @@ -265,6 +265,12 @@ public: /*============== Actual mount scheduling and queue status reporting ========*/ private: const size_t c_defaultMaxNbFilesForRepack = 500; + /** + * This time is used to limitate the time an expansion of a RepackRequest will take + * If the RepackRequest has not finished its expansion before this time limit, + * it will be requeued in the RepackQueueToExpand queue. + */ + double m_repackRequestExpansionTimeLimit = 30; typedef std::pair<std::string, common::dataStructures::MountType> tpType; /** @@ -276,6 +282,13 @@ private: std::map<tpType, uint32_t> & existingMountsSummary, std::set<std::string> & tapesInUse, std::list<catalogue::TapeForWriting> & tapeList, double & getTapeInfoTime, double & candidateSortingTime, double & getTapeForWriteTime, log::LogContext & lc); + /** + * Checks wether the tape is full before repacking + * @param vid the vid of the tape to check + * @throws a UserError exception if the vid does not exist or if + * the tape is not full + */ + void checkTapeFullBeforeRepack(std::string vid); public: /** @@ -372,6 +385,10 @@ public: /*======================== Administrator management ========================*/ void authorizeAdmin(const cta::common::dataStructures::SecurityIdentity &cliIdentity, log::LogContext & lc); + + void setRepackRequestExpansionTimeLimit(const double &time); + + double getRepackRequestExpansionTimeLimit() const; private: diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp index 67508481059853932ecc639994fed5f9cb44b3fb..ee1de1f9ba1c223e66c5a0995f4c47411d70b087 100644 --- a/scheduler/SchedulerDatabase.hpp +++ b/scheduler/SchedulerDatabase.hpp @@ -450,11 +450,13 @@ public: //TODO : userprovidedfiles and userprovidedbytes }; - virtual void addSubrequests(std::list<Subrequest>& repackSubrequests, - cta::common::dataStructures::ArchiveRoute::FullMap & archiveRoutesMap, uint64_t maxFSeqLowBound, log::LogContext & lc) = 0; - virtual void setTotalStats(const TotalStatsFiles& stats) = 0; + virtual void addSubrequestsAndUpdateStats(std::list<Subrequest>& repackSubrequests, + cta::common::dataStructures::ArchiveRoute::FullMap & archiveRoutesMap, uint64_t maxFSeqLowBound, const uint64_t maxAddedFSeq, const TotalStatsFiles &totalStatsFiles, log::LogContext & lc) = 0; virtual void expandDone() = 0; virtual void fail() = 0; + virtual void requeueInToExpandQueue(log::LogContext &lc) = 0; + virtual void setExpandStartedAndChangeStatus() = 0; + virtual void fillLastExpandedFSeqAndTotalStatsFile(uint64_t &fSeq, TotalStatsFiles &totalStatsFiles) = 0; virtual ~RepackRequest() {} }; diff --git a/scheduler/SchedulerTest.cpp b/scheduler/SchedulerTest.cpp index e19034f0fabfb562cece3346815ec6f00858a26e..3067e541ae811a8175c9a2cd399127a319de6f68 100644 --- a/scheduler/SchedulerTest.cpp +++ b/scheduler/SchedulerTest.cpp @@ -53,6 +53,7 @@ #include <gtest/gtest.h> #include <memory> #include <utility> +#include <bits/unique_ptr.h> namespace unitTests { @@ -214,7 +215,9 @@ public: const std::string tapePoolComment = "Tape-pool comment"; const std::string vo = "vo"; const bool tapePoolEncryption = false; - catalogue.createTapePool(s_adminOnAdminHost, s_tapePoolName, vo, nbPartialTapes, tapePoolEncryption, tapePoolComment); + const cta::optional<std::string> tapePoolSupply("value for the supply pool mechanism"); + catalogue.createTapePool(s_adminOnAdminHost, s_tapePoolName, vo, nbPartialTapes, tapePoolEncryption, tapePoolSupply, + tapePoolComment); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Archive-route comment"; catalogue.createArchiveRoute(s_adminOnAdminHost, s_diskInstance, s_storageClassName, copyNb, s_tapePoolName, @@ -432,8 +435,9 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -631,8 +635,9 @@ TEST_P(SchedulerTest, archive_and_retrieve_failure) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -881,8 +886,9 @@ TEST_P(SchedulerTest, archive_and_retrieve_report_failure) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1125,8 +1131,9 @@ TEST_P(SchedulerTest, retry_archive_until_max_reached) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1247,16 +1254,35 @@ TEST_P(SchedulerTest, repack) { setupDefaultCatalogue(); Scheduler &scheduler = getScheduler(); - + cta::catalogue::Catalogue& catalogue = getCatalogue(); + log::DummyLogger dl("", ""); log::LogContext lc(dl); typedef cta::common::dataStructures::RepackInfo RepackInfo; typedef cta::common::dataStructures::RepackInfo::Status Status; - // Create and then cancel repack + // Create the environment for the migration to happen (library + tape) + const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + libraryIsDisabled, libraryComment); + common::dataStructures::SecurityIdentity cliId; + cliId.host = "host"; + cliId.username = s_userName; std::string tape1 = "Tape"; + + catalogue.createTape(cliId,tape1,"mediaType","vendor",s_libraryName,s_tapePoolName,500,false,false,"Comment"); + + //The queueing of a repack request should fail if the tape to repack is not full + ASSERT_THROW(scheduler.queueRepack(cliId, tape1, "file://"+tempDirectory.path(), common::dataStructures::RepackInfo::Type::MoveOnly, lc),cta::exception::UserError); + //The queueing of a repack request in a vid that does not exist should throw an exception + ASSERT_THROW(scheduler.queueRepack(cliId, "NOT_EXIST", "file://"+tempDirectory.path(), common::dataStructures::RepackInfo::Type::MoveOnly, lc),cta::exception::UserError); + + catalogue.setTapeFull(cliId,tape1,true); + + // Create and then cancel repack scheduler.queueRepack(cliId, tape1, "file://"+tempDirectory.path(), common::dataStructures::RepackInfo::Type::MoveOnly, lc); { auto repacks = scheduler.getRepacks(); @@ -1267,12 +1293,14 @@ TEST_P(SchedulerTest, repack) { scheduler.cancelRepack(cliId, tape1, lc); ASSERT_EQ(0, scheduler.getRepacks().size()); // Recreate a repack and get it moved to ToExpand - scheduler.queueRepack(cliId, "Tape2", "file://"+tempDirectory.path(), common::dataStructures::RepackInfo::Type::MoveOnly, lc); + std::string tape2 = "Tape2"; + catalogue.createTape(cliId,tape2,"mediaType","vendor",s_libraryName,s_tapePoolName,500,false,true,"Comment"); + scheduler.queueRepack(cliId, tape2, "file://"+tempDirectory.path(), common::dataStructures::RepackInfo::Type::MoveOnly, lc); { auto repacks = scheduler.getRepacks(); ASSERT_EQ(1, repacks.size()); auto repack = scheduler.getRepack(repacks.front().vid); - ASSERT_EQ("Tape2", repack.vid); + ASSERT_EQ(tape2, repack.vid); } scheduler.promoteRepackRequestsToToExpand(lc); { @@ -1289,16 +1317,30 @@ TEST_P(SchedulerTest, getNextRepackRequestToExpand) { setupDefaultCatalogue(); Scheduler &scheduler = getScheduler(); + catalogue::Catalogue& catalogue = getCatalogue(); log::DummyLogger dl("", ""); log::LogContext lc(dl); - // Create a repack request + // Create the environment for the migration to happen (library + tape) + const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + libraryIsDisabled, libraryComment); + common::dataStructures::SecurityIdentity cliId; + cliId.host = "host"; + cliId.username = s_userName; std::string tape1 = "Tape"; + catalogue.createTape(cliId,tape1,"mediaType","vendor",s_libraryName,s_tapePoolName,500,false,true,"Comment"); + + //Queue the first repack request scheduler.queueRepack(cliId, tape1, "file://"+tempDirectory.path(), common::dataStructures::RepackInfo::Type::MoveOnly, lc); std::string tape2 = "Tape2"; + catalogue.createTape(cliId,tape2,"mediaType","vendor",s_libraryName,s_tapePoolName,500,false,true,"Comment"); + + //Queue the second repack request scheduler.queueRepack(cliId,tape2,"file://"+tempDirectory.path(),common::dataStructures::RepackInfo::Type::AddCopiesOnly,lc); //Test the repack request queued has status Pending @@ -1354,7 +1396,7 @@ TEST_P(SchedulerTest, expandRepackRequest) { const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; - const bool fullValue = false; + const bool fullValue = true; const std::string comment = "Create tape"; cta::common::dataStructures::SecurityIdentity admin; admin.username = "admin_user_name"; @@ -1363,7 +1405,8 @@ TEST_P(SchedulerTest, expandRepackRequest) { const std::string diskFileGroup = "public_disk_group"; //Create a logical library in the catalogue - catalogue.createLogicalLibrary(admin, s_libraryName, "Create logical library"); + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); uint64_t nbTapesToRepack = 10; uint64_t nbTapesForTest = 2; //corresponds to the targetAvailableRequests variable in the Scheduler::promoteRepackRequestsToToExpand() method @@ -1510,23 +1553,23 @@ TEST_P(SchedulerTest, expandRepackRequest) { executedJobs.push_back(std::move(retrieveJob)); } //Now, report the retrieve jobs to be completed - castor::tape::tapeserver::daemon::RecallReportPacker rrp(retrieveMount.get(),lc); + castor::tape::tapeserver::daemon::RecallReportPacker rrp(retrieveMount.get(),lc); - rrp.startThreads(); - for(auto it = executedJobs.begin(); it != executedJobs.end(); ++it) - { - rrp.reportCompletedJob(std::move(*it)); - } - rrp.setDiskDone(); - rrp.setTapeDone(); + rrp.startThreads(); + for(auto it = executedJobs.begin(); it != executedJobs.end(); ++it) + { + rrp.reportCompletedJob(std::move(*it)); + } + rrp.setDiskDone(); + rrp.setTapeDone(); - rrp.reportDriveStatus(cta::common::dataStructures::DriveStatus::Unmounting); + rrp.reportDriveStatus(cta::common::dataStructures::DriveStatus::Unmounting); - rrp.reportEndOfSession(); - rrp.waitThread(); + rrp.reportEndOfSession(); + rrp.waitThread(); - ASSERT_EQ(rrp.allThreadsDone(),true); - } + ASSERT_EQ(rrp.allThreadsDone(),true); + } uint64_t archiveFileId = 1; for(uint64_t i = 1; i<= nbTapesForTest ;++i) @@ -1689,7 +1732,7 @@ TEST_P(SchedulerTest, expandRepackRequestRetrieveFailed) { const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; - const bool fullValue = false; + const bool fullValue = true; const std::string comment = "Create tape"; cta::common::dataStructures::SecurityIdentity admin; admin.username = "admin_user_name"; @@ -1698,7 +1741,8 @@ TEST_P(SchedulerTest, expandRepackRequestRetrieveFailed) { const std::string diskFileGroup = "public_disk_group"; //Create a logical library in the catalogue - catalogue.createLogicalLibrary(admin, s_libraryName, "Create logical library"); + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -1928,7 +1972,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveSuccess) { const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; - const bool fullValue = false; + const bool fullValue = true; const std::string comment = "Create tape"; cta::common::dataStructures::SecurityIdentity admin; admin.username = "admin_user_name"; @@ -1937,13 +1981,18 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveSuccess) { const std::string diskFileGroup = "public_disk_group"; //Create a logical library in the catalogue - catalogue.createLogicalLibrary(admin, s_libraryName, "Create logical library"); + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; std::string vid = ossVid.str(); catalogue.createTape(s_adminOnAdminHost,vid, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes, disabledValue, fullValue, comment); + //Create a repack destination tape + std::string vidDestination = "vidDestination"; + catalogue.createTape(s_adminOnAdminHost,vidDestination, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes, + disabledValue, false, comment); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; @@ -2174,7 +2223,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = false; - const bool fullValue = false; + const bool fullValue = true; const std::string comment = "Create tape"; cta::common::dataStructures::SecurityIdentity admin; admin.username = "admin_user_name"; @@ -2183,13 +2232,19 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { const std::string diskFileGroup = "public_disk_group"; //Create a logical library in the catalogue - catalogue.createLogicalLibrary(admin, s_libraryName, "Create logical library"); + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; std::string vid = ossVid.str(); catalogue.createTape(s_adminOnAdminHost,vid, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes, disabledValue, fullValue, comment); + + //Create a repack destination tape + std::string vidDestinationRepack = "vidDestinationRepack"; + catalogue.createTape(s_adminOnAdminHost,vidDestinationRepack, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes, + disabledValue, false, comment); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; @@ -2446,6 +2501,127 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { } } +TEST_P(SchedulerTest, expandRepackRequestExpansionTimeLimitReached) { + using namespace cta; + using namespace cta::objectstore; + unitTests::TempDirectory tempDirectory; + auto &catalogue = getCatalogue(); + auto &scheduler = getScheduler(); + //Set the expansion time limit to 0 + scheduler.setRepackRequestExpansionTimeLimit(0.0); + auto &schedulerDB = getSchedulerDB(); + cta::objectstore::Backend& backend = schedulerDB.getBackend(); + setupDefaultCatalogue(); +#ifdef STDOUT_LOGGING + log::StdoutLogger dl("dummy", "unitTest"); +#else + log::DummyLogger dl("", ""); +#endif + log::LogContext lc(dl); + + //Create an agent to represent this test process + cta::objectstore::AgentReference agentReference("expandRepackRequestTest", dl); + cta::objectstore::Agent agent(agentReference.getAgentAddress(), backend); + agent.initialize(); + agent.setTimeout_us(0); + agent.insertAndRegisterSelf(lc); + + const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; + const bool disabledValue = false; + const bool fullValue = true; + const std::string comment = "Create tape"; + cta::common::dataStructures::SecurityIdentity admin; + admin.username = "admin_user_name"; + admin.host = "admin_host"; + const std::string diskFileUser = "public_disk_user"; + const std::string diskFileGroup = "public_disk_group"; + + //Create a logical library in the catalogue + const bool logicalLibraryIsDisabled = false; + catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + + std::ostringstream ossVid; + ossVid << s_vid << "_" << 1; + std::string vid = ossVid.str(); + catalogue.createTape(s_adminOnAdminHost,vid, s_mediaType, s_vendor, s_libraryName, s_tapePoolName, capacityInBytes, + disabledValue, fullValue, comment); + + //Create a storage class in the catalogue + common::dataStructures::StorageClass storageClass; + storageClass.diskInstance = s_diskInstance; + storageClass.name = s_storageClassName; + storageClass.nbCopies = 2; + storageClass.comment = "Create storage class"; + + const std::string checksumType = "checksum_type"; + const std::string checksumValue = "checksum_value"; + const std::string tapeDrive = "tape_drive"; + const uint64_t nbArchiveFilesPerTape = 10; + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + const uint64_t compressedFileSize = archiveFileSize; + + //Simulate the writing of 10 files in 1 tape in the catalogue + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + { + uint64_t archiveFileId = 1; + std::string currentVid = vid; + for(uint64_t j = 1; j <= nbArchiveFilesPerTape; ++j) { + std::ostringstream diskFileId; + diskFileId << (12345677 + archiveFileId); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_"<<1<<"_"<< j; + auto fileWrittenUP=cta::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = archiveFileId++; + fileWritten.diskInstance = storageClass.diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileUser = diskFileUser; + fileWritten.diskFileGroup = diskFileGroup; + fileWritten.size = archiveFileSize; + fileWritten.checksumType = checksumType; + fileWritten.checksumValue = checksumValue; + fileWritten.storageClassName = s_storageClassName; + fileWritten.vid = currentVid; + fileWritten.fSeq = j; + fileWritten.blockId = j * 100; + fileWritten.compressedSize = compressedFileSize; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + } + //update the DB tape + catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + tapeFilesWrittenCopy1.clear(); + } + //Test the expanding requeue the Repack after the creation of + //one retrieve request + scheduler.waitSchedulerDbSubthreadsComplete(); + { + scheduler.queueRepack(admin,vid,"file://"+tempDirectory.path(),common::dataStructures::RepackInfo::Type::MoveOnly,lc); + scheduler.waitSchedulerDbSubthreadsComplete(); + + log::TimingList tl; + utils::Timer t; + + scheduler.promoteRepackRequestsToToExpand(lc); + scheduler.waitSchedulerDbSubthreadsComplete(); + + auto repackRequestToExpand = scheduler.getNextRepackRequestToExpand(); + scheduler.expandRepackRequest(repackRequestToExpand,tl,t,lc); + scheduler.waitSchedulerDbSubthreadsComplete(); + + ASSERT_EQ(vid,repackRequestToExpand->getRepackInfo().vid); + //Because the timer is set to 0, the Repack Request should + //have been requeued in the ToExpand queue. + //We check that by the getNextRepackRequestToExpand method + repackRequestToExpand = scheduler.getNextRepackRequestToExpand(); + ASSERT_NE(nullptr,repackRequestToExpand); + ASSERT_EQ(vid,repackRequestToExpand->getRepackInfo().vid); + + } +} + #undef TEST_MOCK_DB #ifdef TEST_MOCK_DB static cta::MockSchedulerDatabaseFactory mockDbFactory; diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp index ac371d79d09981b1b9e3720cede9ffbddd26f0fa..4bd976026c1b9892e871d48d0d9544448af9392c 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp @@ -295,8 +295,9 @@ public: const std::string tapePoolComment = "Tape-pool comment"; const std::string vo = "vo"; const bool tapePoolEncryption = false; + const cta::optional<std::string> tapePoolSupply("value for the supply pool mechanism"); ASSERT_NO_THROW(catalogue.createTapePool(s_adminOnAdminHost, s_tapePoolName, vo, nbPartialTapes, tapePoolEncryption, - tapePoolComment)); + tapePoolSupply, tapePoolComment)); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Archive-route comment"; catalogue.createArchiveRoute(s_adminOnAdminHost, s_diskInstance, s_storageClassName, copyNb, s_tapePoolName, @@ -373,8 +374,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayRecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -553,8 +555,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -747,8 +750,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -964,8 +968,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionNoSuchDrive) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1111,8 +1116,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionFailtoMount) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1268,8 +1274,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1410,8 +1417,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionMissingFilesMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1568,8 +1576,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1724,8 +1733,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); @@ -1878,8 +1888,9 @@ TEST_P(DataTransferSessionTest, WriteDataInTapeWithNonSupersededFilesOnIt) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, - libraryComment); + libraryIsDisabled, libraryComment); { auto libraries = catalogue.getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); diff --git a/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp index 297d99caa0a5a6eb7ef515d912f2b69f2890a921..9b7f5028611ccf401b645bd07c184a63d9b348f9 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp @@ -116,16 +116,18 @@ namespace unitTests { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled = false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string createTapeComment = "Create tape"; cta::common::dataStructures::SecurityIdentity admin = cta::common::dataStructures::SecurityIdentity("admin","localhost"); - m_catalogue->createLogicalLibrary(admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(admin, tapePoolName, vo, 2, true, supply, "Create tape pool"); m_catalogue->createTape(admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); @@ -262,16 +264,20 @@ namespace unitTests { const std::string mediaType = "media_type"; const std::string vendor = "vendor"; const std::string logicalLibraryName = "logical_library_name"; + const bool logicalLibraryIsDisabled = false; const std::string tapePoolName = "tape_pool_name"; const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); const uint64_t capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; const bool disabledValue = true; const bool fullValue = false; const std::string createTapeComment = "Create tape"; cta::common::dataStructures::SecurityIdentity admin = cta::common::dataStructures::SecurityIdentity("admin","localhost"); - m_catalogue->createLogicalLibrary(admin, logicalLibraryName, "Create logical library"); - m_catalogue->createTapePool(admin, tapePoolName, vo, 2, true, "Create tape pool"); + m_catalogue->createLogicalLibrary(admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->createTapePool(admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, "Create tape pool"); m_catalogue->createTape(admin, vid1, mediaType, vendor, logicalLibraryName, tapePoolName, capacityInBytes, disabledValue, fullValue, createTapeComment); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 620fd8287a120dfe797ad2fb32f477c2fb9f1094..75f5e3f9504cf8177e0c54e3616ee2d891ad84bc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,7 @@ target_link_libraries(cta-unitTests ctamediachangerunittests ctainmemorycatalogueunittests ctainmemoryconnunittests + ctainmemorystmtunittests ctaobjectstore ctaobjectstoreunittests ctardbmswrapperunittests @@ -58,6 +59,8 @@ add_executable(cta-rdbmsUnitTests target_link_libraries(cta-rdbmsUnitTests ctadbconfigcatalogueunittests ctadbconfigconnunittests + ctadbconfigstmtunittests + ctardbmsunittests gtest pthread) diff --git a/xroot_plugins/XrdCtaTapePoolLs.hpp b/xroot_plugins/XrdCtaTapePoolLs.hpp index de855f0494fc6fa6802cfb1ffb99bd1f89386ffa..595d9ae96d9108d315c0be1ac6cf23e6c734f51f 100644 --- a/xroot_plugins/XrdCtaTapePoolLs.hpp +++ b/xroot_plugins/XrdCtaTapePoolLs.hpp @@ -91,6 +91,7 @@ public: tp_item->set_capacity_bytes(tp.capacityBytes); tp_item->set_data_bytes(tp.dataBytes); tp_item->set_encrypt(tp.encryption); + tp_item->set_supply(tp.supply ? tp.supply.value() : ""); tp_item->mutable_created()->set_username(tp.creationLog.username); tp_item->mutable_created()->set_host(tp.creationLog.host); tp_item->mutable_created()->set_time(tp.creationLog.time); diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.cpp b/xroot_plugins/XrdSsiCtaRequestMessage.cpp index 7a57bd5124c956d7cb3b80a9099a9b9ca5dabbd4..4d4acb1e6dcc1656d6923b2f0e07e05d3fc2f767 100644 --- a/xroot_plugins/XrdSsiCtaRequestMessage.cpp +++ b/xroot_plugins/XrdSsiCtaRequestMessage.cpp @@ -1177,10 +1177,11 @@ void RequestMessage::processLogicalLibrary_Add(const cta::admin::AdminCmd &admin { using namespace cta::admin; - auto &name = getRequired(OptionString::LOGICAL_LIBRARY); - auto &comment = getRequired(OptionString::COMMENT); + auto &name = getRequired(OptionString::LOGICAL_LIBRARY); + auto isDisabled = getOptional(OptionBoolean::DISABLED); + auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createLogicalLibrary(m_cliIdentity, name, comment); + m_catalogue.createLogicalLibrary(m_cliIdentity, name, isDisabled ? isDisabled.value() : false, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1191,10 +1192,16 @@ void RequestMessage::processLogicalLibrary_Ch(const cta::admin::AdminCmd &adminc { using namespace cta::admin; - auto &name = getRequired(OptionString::LOGICAL_LIBRARY); - auto &comment = getRequired(OptionString::COMMENT); + auto &name = getRequired(OptionString::LOGICAL_LIBRARY); + auto disabled = getOptional(OptionBoolean::DISABLED); + auto comment = getOptional(OptionString::COMMENT); - m_catalogue.modifyLogicalLibraryComment(m_cliIdentity, name, comment); + if(disabled) { + m_catalogue.setLogicalLibraryDisabled(m_cliIdentity, name, disabled.value()); + } + if(comment) { + m_catalogue.modifyLogicalLibraryComment(m_cliIdentity, name, comment.value()); + } response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1226,12 +1233,13 @@ void RequestMessage::processLogicalLibrary_Ls(const cta::admin::AdminCmd &adminc { std::vector<std::vector<std::string>> responseTable; std::vector<std::string> header = { - "name","c.user","c.host","c.time","m.user","m.host","m.time","comment" + "name","disabled","c.user","c.host","c.time","m.user","m.host","m.time","comment" }; if(has_flag(OptionBoolean::SHOW_HEADER)) responseTable.push_back(header); for(auto it = list.cbegin(); it != list.cend(); it++) { std::vector<std::string> currentRow; currentRow.push_back(it->name); + currentRow.push_back(std::to_string(it->isDisabled)); addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog); currentRow.push_back(it->comment); responseTable.push_back(currentRow); @@ -2012,8 +2020,9 @@ void RequestMessage::processTapePool_Add(const cta::admin::AdminCmd &admincmd, c auto &ptn = getRequired(OptionUInt64::PARTIAL_TAPES_NUMBER); auto &comment = getRequired(OptionString::COMMENT); auto &encrypted = getRequired(OptionBoolean::ENCRYPTED); + auto supply = getOptional(OptionString::SUPPLY); - m_catalogue.createTapePool(m_cliIdentity, name, vo, ptn, encrypted, comment); + m_catalogue.createTapePool(m_cliIdentity, name, vo, ptn, encrypted, supply, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2029,6 +2038,7 @@ void RequestMessage::processTapePool_Ch(const cta::admin::AdminCmd &admincmd, ct auto ptn = getOptional(OptionUInt64::PARTIAL_TAPES_NUMBER); auto comment = getOptional(OptionString::COMMENT); auto encrypted = getOptional(OptionBoolean::ENCRYPTED); + auto supply = getOptional(OptionString::SUPPLY); if(comment) { m_catalogue.modifyTapePoolComment(m_cliIdentity, name, comment.value()); @@ -2042,6 +2052,9 @@ void RequestMessage::processTapePool_Ch(const cta::admin::AdminCmd &admincmd, ct if(encrypted) { m_catalogue.setTapePoolEncryption(m_cliIdentity, name, encrypted.value()); } + if(supply) { + m_catalogue.modifyTapePoolSupply(m_cliIdentity, name, supply.value()); + } response.set_type(cta::xrd::Response::RSP_SUCCESS); }