Commit e072570e authored by Steven Murray's avatar Steven Murray
Browse files

cta/CTA#725 Unit-test createArchiveRoute_two_routes_same_pool now passes

parent 89348721
......@@ -299,6 +299,25 @@ public:
const uint32_t copyNb) = 0;
virtual std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const = 0;
/**
* @return the archive routes of the given storage class and destination tape
* pool.
*
* Under normal circumstances this method should return either 0 or 1 route.
* For a given storage class there should be no more than one route to any
* given tape pool.
*
* @param diskInstanceName The name of the disk instance to which the storage
* class belongs.
* @param storageClassName The name of the storage class which is only
* guaranteed to be unique within its disk instance.
* @param tapePoolName The name of the tape pool.
*/
virtual std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(
const std::string &diskInstanceName, const std::string &storageClassName,
const std::string &tapePoolName) const = 0;
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;
......
......@@ -189,6 +189,10 @@ public:
return retryOnLostConnection(m_log, [&]{return m_catalogue->getArchiveRoutes();}, m_maxTriesToConnect);
}
std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(const std::string &diskInstanceName, const std::string &storageClassName, const std::string &tapePoolName) const override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->getArchiveRoutes(diskInstanceName, storageClassName, tapePoolName);}, m_maxTriesToConnect);
}
void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyArchiveRouteTapePoolName(admin, instanceName, storageClassName, copyNb, tapePoolName);}, m_maxTriesToConnect);
}
......
......@@ -1734,27 +1734,52 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute) {
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");
 
ASSERT_TRUE(m_catalogue->getArchiveRoutes(storageClass.diskInstance, storageClass.name, tapePoolName).empty());
const uint32_t copyNb = 1;
const std::string comment = "Create archive route";
m_catalogue->createArchiveRoute(m_admin, storageClass.diskInstance, storageClass.name, copyNb, tapePoolName, comment);
const std::list<common::dataStructures::ArchiveRoute> routes = m_catalogue->getArchiveRoutes();
{
const std::list<common::dataStructures::ArchiveRoute> routes = m_catalogue->getArchiveRoutes();
ASSERT_EQ(1, routes.size());
ASSERT_EQ(1, routes.size());
const common::dataStructures::ArchiveRoute route = routes.front();
ASSERT_EQ(storageClass.diskInstance, route.diskInstanceName);
ASSERT_EQ(storageClass.name, route.storageClassName);
ASSERT_EQ(copyNb, route.copyNb);
ASSERT_EQ(tapePoolName, route.tapePoolName);
ASSERT_EQ(comment, route.comment);
const common::dataStructures::ArchiveRoute route = routes.front();
ASSERT_EQ(storageClass.diskInstance, route.diskInstanceName);
ASSERT_EQ(storageClass.name, route.storageClassName);
ASSERT_EQ(copyNb, route.copyNb);
ASSERT_EQ(tapePoolName, route.tapePoolName);
ASSERT_EQ(comment, route.comment);
 
const common::dataStructures::EntryLog creationLog = route.creationLog;
ASSERT_EQ(m_admin.username, creationLog.username);
ASSERT_EQ(m_admin.host, creationLog.host);
const common::dataStructures::EntryLog creationLog = route.creationLog;
ASSERT_EQ(m_admin.username, creationLog.username);
ASSERT_EQ(m_admin.host, creationLog.host);
const common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog;
ASSERT_EQ(creationLog, lastModificationLog);
const common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog;
ASSERT_EQ(creationLog, lastModificationLog);
}
{
const std::list<common::dataStructures::ArchiveRoute> routes = m_catalogue->getArchiveRoutes(
storageClass.diskInstance, storageClass.name, tapePoolName);
ASSERT_EQ(1, routes.size());
const common::dataStructures::ArchiveRoute route = routes.front();
ASSERT_EQ(storageClass.diskInstance, route.diskInstanceName);
ASSERT_EQ(storageClass.name, route.storageClassName);
ASSERT_EQ(copyNb, route.copyNb);
ASSERT_EQ(tapePoolName, route.tapePoolName);
ASSERT_EQ(comment, route.comment);
const common::dataStructures::EntryLog creationLog = route.creationLog;
ASSERT_EQ(m_admin.username, creationLog.username);
ASSERT_EQ(m_admin.host, creationLog.host);
const common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog;
ASSERT_EQ(creationLog, lastModificationLog);
}
}
 
TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName) {
......
......@@ -72,6 +72,7 @@ public:
std::list<common::dataStructures::ArchiveFile> getFilesForRepack(const std::string &vid, const uint64_t startFSeq, const uint64_t maxNbFiles) const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
ArchiveFileItor getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(const std::string &diskInstanceName, const std::string &storageClassName, const std::string &tapePoolName) const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
std::list<common::dataStructures::MountPolicy> getMountPolicies() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
......
......@@ -1381,6 +1381,15 @@ void RdbmsCatalogue::createArchiveRoute(
<< "->" << tapePoolName << " because it already exists";
throw ue;
}
{
const auto routes = getArchiveRoutes(conn, diskInstanceName, storageClassName, tapePoolName);
if(!routes.empty()) {
exception::UserError ue;
ue.getMessage() << "Cannot create archive route " << diskInstanceName << ":" << storageClassName << "," << copyNb
<< "->" << tapePoolName << " because a route already exists for this storage class and tape pool";
throw ue;
}
}
if(!storageClassExists(conn, diskInstanceName, storageClassName)) {
exception::UserError ue;
ue.getMessage() << "Cannot create archive route " << diskInstanceName << ":" << storageClassName << "," << copyNb
......@@ -1555,6 +1564,90 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes
}
}
//------------------------------------------------------------------------------
// getArchiveRoutes
//------------------------------------------------------------------------------
std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes(
const std::string &diskInstanceName, const std::string &storageClassName,
const std::string &tapePoolName) const {
try {
auto conn = m_connPool.getConn();
return getArchiveRoutes(conn, diskInstanceName, storageClassName, tapePoolName);
} catch(exception::UserError &) {
throw;
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
// getArchiveRoutes
//------------------------------------------------------------------------------
std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes(rdbms::Conn &conn,
const std::string &diskInstanceName, const std::string &storageClassName, const std::string &tapePoolName) const {
try {
std::list<common::dataStructures::ArchiveRoute> routes;
const char *const sql =
"SELECT" "\n"
"STORAGE_CLASS.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," "\n"
"STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," "\n"
"ARCHIVE_ROUTE.COPY_NB AS COPY_NB," "\n"
"TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "\n"
"ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT," "\n"
"ARCHIVE_ROUTE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," "\n"
"ARCHIVE_ROUTE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," "\n"
"ARCHIVE_ROUTE.CREATION_LOG_TIME AS CREATION_LOG_TIME," "\n"
"ARCHIVE_ROUTE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," "\n"
"ARCHIVE_ROUTE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," "\n"
"ARCHIVE_ROUTE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME" "\n"
"FROM" "\n"
"ARCHIVE_ROUTE" "\n"
"INNER JOIN STORAGE_CLASS ON" "\n"
"ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID" "\n"
"INNER JOIN TAPE_POOL ON" "\n"
"ARCHIVE_ROUTE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID" "\n"
"WHERE" "\n"
"STORAGE_CLASS.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND" "\n"
"STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND" "\n"
"TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME" "\n"
"ORDER BY" "\n"
"DISK_INSTANCE_NAME, STORAGE_CLASS_NAME, COPY_NB";
auto stmt = conn.createStmt(sql);
stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName);
stmt.bindString(":STORAGE_CLASS_NAME", storageClassName);
stmt.bindString(":TAPE_POOL_NAME", tapePoolName);
auto rset = stmt.executeQuery();
while (rset.next()) {
common::dataStructures::ArchiveRoute route;
route.diskInstanceName = rset.columnString("DISK_INSTANCE_NAME");
route.storageClassName = rset.columnString("STORAGE_CLASS_NAME");
route.copyNb = rset.columnUint64("COPY_NB");
route.tapePoolName = rset.columnString("TAPE_POOL_NAME");
route.comment = rset.columnString("USER_COMMENT");
route.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME");
route.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME");
route.creationLog.time = rset.columnUint64("CREATION_LOG_TIME");
route.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME");
route.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME");
route.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME");
routes.push_back(route);
}
return routes;
} catch(exception::UserError &) {
throw;
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
// modifyArchiveRouteTapePoolName
//------------------------------------------------------------------------------
......
......@@ -288,6 +288,25 @@ public:
const uint32_t copyNb) override;
std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const override;
/**
* @return the archive routes of the given storage class and destination tape
* pool.
*
* Under normal circumstances this method should return either 0 or 1 route.
* For a given storage class there should be no more than one route to any
* given tape pool.
*
* @param diskInstanceName The name of the disk instance to which the storage
* class belongs.
* @param storageClassName The name of the storage class which is only
* guaranteed to be unique within its disk instance.
* @param tapePoolName The name of the tape pool.
*/
std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(
const std::string &diskInstanceName, const std::string &storageClassName,
const std::string &tapePoolName) const override;
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;
......@@ -875,6 +894,24 @@ protected:
bool archiveRouteExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &storageClassName,
const uint32_t copyNb) const;
/**
* @return the archive routes of the given storage class and destination tape
* pool.
*
* Under normal circumstances this method should return either 0 or 1 route.
* For a given storage class there should be no more than one route to any
* given tape pool.
*
* @param conn The database connection.
* @param diskInstanceName The name of the disk instance to which the storage
* class belongs.
* @param storageClassName The name of the storage class which is only
* guaranteed to be unique within its disk instance.
* @param tapePoolName The name of the tape pool.
*/
std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(rdbms::Conn &conn,
const std::string &diskInstanceName, const std::string &storageClassName, const std::string &tapePoolName) const;
/**
* Returns true if the specified tape exists.
*
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment