diff --git a/libs/middletier/SqliteDatabase.cpp b/libs/middletier/SqliteDatabase.cpp index 9786ee106c8a77f8deed47230b901c4382a8dfd1..d47ead86a1d19199876172d968da3b040a1b2e0e 100644 --- a/libs/middletier/SqliteDatabase.cpp +++ b/libs/middletier/SqliteDatabase.cpp @@ -113,64 +113,6 @@ void cta::SqliteDatabase::createTapePoolTable() { } } -//------------------------------------------------------------------------------ -// createDirectoryTable -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::createDirectoryTable() { - char *zErrMsg = 0; - int rc = sqlite3_exec(m_dbHandle, - "CREATE TABLE DIRECTORY(" - "PATH TEXT PRIMARY KEY," - "STORAGECLASS_NAME TEXT," - "UID INTEGER," - "GID INTEGER," - "CREATIONTIME INTEGER," - "MODE INTEGER," - "FOREIGN KEY (STORAGECLASS_NAME) REFERENCES STORAGECLASS(NAME)" - ");", - 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "createDirectoryTable() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } - std::ostringstream query; - query << "INSERT INTO DIRECTORY VALUES('/',NULL,0,0," << (int)time(NULL) << ",0);"; - rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "createDirectoryTable() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// createFileTable -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::createFileTable() { - char *zErrMsg = 0; - int rc = sqlite3_exec(m_dbHandle, - "CREATE TABLE FILE(" - "PATH TEXT," - "NAME TEXT," - "UID INTEGER," - "GID INTEGER," - "CREATIONTIME INTEGER," - "MODE INTEGER," - "PRIMARY KEY (PATH, NAME)," - "FOREIGN KEY (PATH) REFERENCES DIRECTORY(PATH)" - ");", - 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "createFileTable() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - //------------------------------------------------------------------------------ // createTapeTable //------------------------------------------------------------------------------ @@ -329,8 +271,6 @@ void cta::SqliteDatabase::createSchema() { createStorageClassTable(); createTapePoolTable(); createArchiveRouteTable(); - createDirectoryTable(); - createFileTable(); createLogicalLibraryTable(); createTapeTable(); createAdminUserTable(); @@ -435,283 +375,6 @@ void cta::SqliteDatabase::insertLogicalLibrary(const SecurityIdentity &requester } } -//------------------------------------------------------------------------------ -// insertFile -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::insertFile(const SecurityIdentity &requester, const std::string &pathname, const uint16_t mode) { - cta::Utils::checkAbsolutePathSyntax(pathname); - std::string path = cta::Utils::getEnclosingDirPath(pathname); - std::string name = cta::Utils::getEnclosedName(pathname); - getDirectoryStorageClass(requester, path); //just check if the path exists - char *zErrMsg = 0; - std::ostringstream query; - query << "INSERT INTO FILE VALUES('" << path << "','" << name << "',"<< requester.user.getUid() << "," << requester.user.getGid() << "," << (int)time(NULL) << "," << (int)mode << ");"; - int rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "insertFile() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// checkFileExists -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::checkFileExists(const std::string &path, const std::string &name){ - char *zErrMsg = 0; - std::ostringstream query; - query << "SELECT * FROM FILE WHERE NAME='" << name << "' AND PATH='" << path << "';"; - sqlite3_stmt *statement; - int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &statement, 0 ); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "checkFileExists() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } - int res = sqlite3_step(statement); - if(res==SQLITE_ROW) { - return; - } - else if(res==SQLITE_DONE){ - std::ostringstream message; - message << "FILE: " << path << "/" << name << " does not exist"; - throw(Exception(message.str())); - } - else { - std::ostringstream message; - message << "checkFileExists() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// deleteFile -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::deleteFile(const SecurityIdentity &requester, const std::string &pathname) { - cta::Utils::checkAbsolutePathSyntax(pathname); - std::string path = cta::Utils::getEnclosingDirPath(pathname); - std::string name = cta::Utils::getEnclosedName(pathname); - checkFileExists(path, name); - char *zErrMsg = 0; - std::ostringstream query; - query << "DELETE FROM FILE WHERE NAME='" << name << "' AND PATH='" << path << "';"; - int rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "deleteFile() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// getDirectoryStorageClass -//------------------------------------------------------------------------------ -std::string cta::SqliteDatabase::getDirectoryStorageClass(const SecurityIdentity &requester, const std::string &path){ - char *zErrMsg = 0; - std::ostringstream query; - std::list<cta::TapePool> pools; - query << "SELECT STORAGECLASS_NAME FROM DIRECTORY WHERE PATH='" << path << "';"; - sqlite3_stmt *statement; - int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &statement, 0 ); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "getDirectoryStorageClass() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } - int res = sqlite3_step(statement); - if(res==SQLITE_ROW) { - return std::string((char *)sqlite3_column_text(statement,0)); - } - else if(res==SQLITE_DONE){ - std::ostringstream message; - message << "PATH: " << path << " does not exist"; - throw(Exception(message.str())); - } - else { - std::ostringstream message; - message << "getDirectoryStorageClass() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// setDirectoryStorageClass -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::setDirectoryStorageClass(const SecurityIdentity &requester, const std::string &path, const std::string &storageClassName){ - char *zErrMsg = 0; - std::ostringstream query; - query << "UPDATE DIRECTORY SET STORAGECLASS_NAME='" << storageClassName << "' WHERE PATH='" << path << "';"; - int rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "setDirectoryStorageClass() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// clearDirectoryStorageClass -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::clearDirectoryStorageClass(const SecurityIdentity &requester, const std::string &path){ - char *zErrMsg = 0; - std::ostringstream query; - query << "UPDATE DIRECTORY SET STORAGECLASS_NAME=NULL WHERE PATH='" << path << "';"; - int rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "clearDirectoryStorageClass() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// checkDirectoryExists -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::checkDirectoryExists(const std::string &path){ - char *zErrMsg = 0; - std::ostringstream query; - query << "SELECT * FROM DIRECTORY WHERE PATH='" << path << "';"; - sqlite3_stmt *statement; - int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &statement, 0 ); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "checkDirectoryExists() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } - int res = sqlite3_step(statement); - if(res==SQLITE_ROW) { - return; - } - else if(res==SQLITE_DONE){ - std::ostringstream message; - message << "DIRECTORY: " << path << " does not exist"; - throw(Exception(message.str())); - } - else { - std::ostringstream message; - message << "checkDirectoryExists() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// checkDirectoryContainsNoDirectories -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::checkDirectoryContainsNoDirectories(const std::string &path){ - char *zErrMsg = 0; - std::ostringstream query; - query << "SELECT * FROM DIRECTORY WHERE PATH LIKE '" << path << "%';"; - sqlite3_stmt *statement; - int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &statement, 0 ); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "checkDirectoryContainsNoDirectories() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } - sqlite3_step(statement); // we will have at least one match: the directory itself. so we skip the first result! - int res = sqlite3_step(statement); - if(res==SQLITE_ROW) { - std::ostringstream message; - message << "DIRECTORY " << path << " not empty: contains at least one directory"; - throw(Exception(message.str())); - } - else if(res==SQLITE_DONE){ //OK - } - else { - std::ostringstream message; - message << "checkDirectoryContainsNoDirectories() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// checkDirectoryContainsNoFiles -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::checkDirectoryContainsNoFiles(const std::string &path){ - char *zErrMsg = 0; - std::ostringstream query; - query << "SELECT * FROM FILE WHERE PATH='" << path << "%';"; - sqlite3_stmt *statement; - int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &statement, 0 ); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "checkDirectoryContainsNoFiles() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } - int res = sqlite3_step(statement); - if(res==SQLITE_ROW) { - std::ostringstream message; - message << "DIRECTORY " << path << " not empty: contains at least one file"; - throw(Exception(message.str())); - } - else if(res==SQLITE_DONE){ //OK - } - else { - std::ostringstream message; - message << "checkDirectoryContainsNoFiles() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// deleteDirectory -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::deleteDirectory(const SecurityIdentity &requester, const std::string &pathname) { - cta::Utils::checkAbsolutePathSyntax(pathname); - checkDirectoryExists(pathname); - checkDirectoryContainsNoDirectories(pathname); - checkDirectoryContainsNoFiles(pathname); - char *zErrMsg = 0; - std::ostringstream query; - query << "DELETE FROM DIRECTORY WHERE PATH='" << pathname << "';"; - int rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "deleteDirectory() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - -//------------------------------------------------------------------------------ -// insertDirectory -//------------------------------------------------------------------------------ -void cta::SqliteDatabase::insertDirectory(const SecurityIdentity &requester, const std::string &pathname, const uint16_t mode) { - cta::Utils::checkAbsolutePathSyntax(pathname); - std::string path = cta::Utils::getEnclosingDirPath(pathname); - std::string name = cta::Utils::getEnclosedName(pathname); - std::string storageClass = getDirectoryStorageClass(requester, path); - char *zErrMsg = 0; - std::ostringstream query; - if(storageClass!="") { - query << "INSERT INTO DIRECTORY VALUES('" << pathname << "','" << storageClass << "'," << requester.user.getUid() << "," << requester.user.getGid() << "," << (int)time(NULL) << "," << (int)mode << ");"; - } - else { - query << "INSERT INTO DIRECTORY VALUES('" << pathname << "',NULL," << requester.user.getUid() << "," << requester.user.getGid() << "," << (int)mode << ");"; - } - int rc = sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0, &zErrMsg); - if(rc!=SQLITE_OK){ - std::ostringstream message; - message << "insertDirectory() - SQLite error: " << zErrMsg; - sqlite3_free(zErrMsg); - throw(Exception(message.str())); - } -} - //------------------------------------------------------------------------------ // insertTapePool //------------------------------------------------------------------------------ diff --git a/libs/middletier/SqliteDatabase.hpp b/libs/middletier/SqliteDatabase.hpp index 13117b811eefe359526539e63096a3c21b1d2adf..830e2f0dc4840a3de95f1f9e750d11630239435f 100644 --- a/libs/middletier/SqliteDatabase.hpp +++ b/libs/middletier/SqliteDatabase.hpp @@ -93,28 +93,7 @@ public: cta::TapePool getTapePoolByName(const SecurityIdentity &requester, const std::string &name); - cta::Tape getTapeByVid(const SecurityIdentity &requester, const std::string &vid); - - - - - void setDirectoryStorageClass(const SecurityIdentity &requester, const std::string &path, const std::string &storageClassName); - - void clearDirectoryStorageClass(const SecurityIdentity &requester, const std::string &path); - - std::string getDirectoryStorageClass(const SecurityIdentity &requester, const std::string &path); - - void insertFile(const SecurityIdentity &requester, const std::string &pathname, const uint16_t mode); - - void insertDirectory(const SecurityIdentity &requester, const std::string &pathname, const uint16_t mode); - - void deleteFile(const SecurityIdentity &requester, const std::string &pathname); - - void deleteDirectory(const SecurityIdentity &requester, const std::string &pathname); - -// cta::DirectoryIterator getDirectoryContents(const SecurityIdentity &requester, const std::string &dirPath); - - + cta::Tape getTapeByVid(const SecurityIdentity &requester, const std::string &vid); private: @@ -161,21 +140,6 @@ private: void checkLogicalLibraryExists(const std::string &name); - - - - void checkFileExists(const std::string &path, const std::string &name); - - void checkDirectoryExists(const std::string &path); - - void checkDirectoryContainsNoDirectories(const std::string &path); - - void checkDirectoryContainsNoFiles(const std::string &path); - - void createDirectoryTable(); - - void createFileTable(); - }; // struct SqliteDatabase } // namespace cta diff --git a/libs/middletier/SqliteMiddleTierAdmin.cpp b/libs/middletier/SqliteMiddleTierAdmin.cpp index 0e285a9c855a805529bba4db0acce8fdbf62522a..6077ab2135f8fa69240683c43f0ae7360f8620e9 100644 --- a/libs/middletier/SqliteMiddleTierAdmin.cpp +++ b/libs/middletier/SqliteMiddleTierAdmin.cpp @@ -8,8 +8,8 @@ //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::SqliteMiddleTierAdmin::SqliteMiddleTierAdmin(SqliteDatabase &sqlite_db): - m_sqlite_db(sqlite_db) { +cta::SqliteMiddleTierAdmin::SqliteMiddleTierAdmin(Vfs &vfs, SqliteDatabase &sqlite_db): + m_sqlite_db(sqlite_db), m_vfs(vfs) { } //------------------------------------------------------------------------------ @@ -86,6 +86,7 @@ void cta::SqliteMiddleTierAdmin::createStorageClass( //------------------------------------------------------------------------------ void cta::SqliteMiddleTierAdmin::deleteStorageClass(const SecurityIdentity &requester, const std::string &name) { + m_vfs.checkStorageClassIsNotInUse(requester, name, "/"); m_sqlite_db.deleteStorageClass(requester, name); } diff --git a/libs/middletier/SqliteMiddleTierAdmin.hpp b/libs/middletier/SqliteMiddleTierAdmin.hpp index e503a2eb1c6c5fff397b958fd5b0cdb4eac79cd4..9d7a4b5446b5450a984b58a84bbdb3c77117956b 100644 --- a/libs/middletier/SqliteMiddleTierAdmin.hpp +++ b/libs/middletier/SqliteMiddleTierAdmin.hpp @@ -3,6 +3,7 @@ #include "MiddleTierAdmin.hpp" #include "MockDatabase.hpp" #include "SqliteDatabase.hpp" +#include "Vfs.hpp" namespace cta { @@ -17,7 +18,7 @@ public: * * @param db The database of the mock middle-tier. */ - SqliteMiddleTierAdmin(SqliteDatabase &sqlite_db); + SqliteMiddleTierAdmin(Vfs &vfs, SqliteDatabase &sqlite_db); /** * Destructor. @@ -315,6 +316,8 @@ protected: bool isAnExistingDirectory(const std::string &path) const throw(); SqliteDatabase &m_sqlite_db; + + Vfs &m_vfs; }; // class SqliteMiddleTierAdmin diff --git a/libs/middletier/SqliteMiddleTierAdminTest.cpp b/libs/middletier/SqliteMiddleTierAdminTest.cpp index 91d58ca3ebdc9cc4662b84c2c57eeff6c964ad13..060055d8b28417eb226243e5a93af5045aa1e9f2 100644 --- a/libs/middletier/SqliteMiddleTierAdminTest.cpp +++ b/libs/middletier/SqliteMiddleTierAdminTest.cpp @@ -21,7 +21,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, createStorageClass_new) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -53,7 +54,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -87,7 +89,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -120,7 +123,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, deleteStorageClass_existing) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -159,7 +163,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -185,7 +190,6 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, ASSERT_EQ(nbCopies, storageClass.getNbCopies()); } - Vfs vfs; SqliteMiddleTierUser userApi(vfs,sqlitedb); ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, "/", storageClassName)); @@ -219,7 +223,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, deleteStorageClass_in_use_by_route) using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -313,7 +318,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, deleteStorageClass_non_existing) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -336,7 +342,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, deleteTapePool_in_use) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -394,7 +401,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, createArchiveRoute_new) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -439,7 +447,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -486,7 +495,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, deleteArchiveRoute_existing) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -539,7 +549,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, deleteArchiveRoute_non_existing) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -571,7 +582,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, createTape_new) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -650,7 +662,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { @@ -701,7 +714,8 @@ TEST_F(cta_client_SqliteMiddleTierAdminTest, createTape_new_non_existing_pool) { using namespace cta; SqliteDatabase sqlitedb; - SqliteMiddleTierAdmin adminApi(sqlitedb); + Vfs vfs; + SqliteMiddleTierAdmin adminApi(vfs, sqlitedb); const SecurityIdentity requester; { diff --git a/libs/middletier/SqliteMiddleTierUser.cpp b/libs/middletier/SqliteMiddleTierUser.cpp index 1d98f79e0fb84e2c7d045b87878dd3891b67d967..4920592c89a9fe9737949dd5cc39d5efc3169ad7 100644 --- a/libs/middletier/SqliteMiddleTierUser.cpp +++ b/libs/middletier/SqliteMiddleTierUser.cpp @@ -24,7 +24,7 @@ cta::SqliteMiddleTierUser::~SqliteMiddleTierUser() throw() { //------------------------------------------------------------------------------ void cta::SqliteMiddleTierUser::createDirectory(const SecurityIdentity &requester, const std::string &dirPath) { - m_vfs.clearDirectoryStorageClass(requester, dirPath); + m_vfs.createDirectory(requester, dirPath, 0777); } //------------------------------------------------------------------------------ diff --git a/libs/middletier/SqliteMiddleTierUserTest.cpp b/libs/middletier/SqliteMiddleTierUserTest.cpp index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3ab30df7b81327c0414fd403a90b8fc75eaca082 100644 --- a/libs/middletier/SqliteMiddleTierUserTest.cpp +++ b/libs/middletier/SqliteMiddleTierUserTest.cpp @@ -0,0 +1,976 @@ +#include "SqliteMiddleTierAdmin.hpp" +#include "SqliteMiddleTierUser.hpp" + +#include <gtest/gtest.h> +#include <set> + +namespace unitTests { + +class cta_client_SqliteMiddleTierUserTest: public ::testing::Test { +protected: + + virtual void SetUp() { + } + + virtual void TearDown() { + } +}; + +TEST_F(cta_client_SqliteMiddleTierUserTest, + getDirectoryContents_root_dir_is_empty) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/"; + + DirectoryIterator itor; + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + ASSERT_FALSE(itor.hasMore()); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, createDirectory_empty_string) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = ""; + + ASSERT_THROW(userApi.createDirectory(requester, dirPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + createDirectory_consecutive_slashes) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "//"; + + ASSERT_THROW(userApi.createDirectory(requester, dirPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, createDirectory_invalid_chars) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/grandparent/?parent"; + + ASSERT_THROW(userApi.createDirectory(requester, dirPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, createDirectory_top_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, createDirectory_second_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + + ASSERT_TRUE(userApi.getDirectoryStorageClass(requester, "/").empty()); + + { + const std::string topLevelDirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, topLevelDirPath)); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + } + + ASSERT_TRUE(userApi.getDirectoryStorageClass(requester, "/grandparent").empty()); + + { + const std::string secondLevelDirPath = "/grandparent/parent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, secondLevelDirPath)); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/grandparent")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("parent"), entry.getName()); + } + + ASSERT_TRUE(userApi.getDirectoryStorageClass(requester, + "/grandparent/parent").empty()); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + createDirectory_inherit_storage_class) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + + ASSERT_TRUE(userApi.getDirectoryStorageClass(requester, "/").empty()); + + { + SqliteMiddleTierAdmin adminApi(vfs, db); + const std::string name = "TestStorageClass"; + const uint16_t nbCopies = 2; + const std::string comment = "Comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, name, nbCopies, comment)); + } + + { + const std::string topLevelDirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, topLevelDirPath)); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + + ASSERT_TRUE(userApi.getDirectoryStorageClass(requester, "/grandparent").empty()); + + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, "/grandparent", + "TestStorageClass")); + } + + ASSERT_EQ(std::string("TestStorageClass"), + userApi.getDirectoryStorageClass(requester, "/grandparent")); + + { + const std::string secondLevelDirPath = "/grandparent/parent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, secondLevelDirPath)); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/grandparent")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("parent"), entry.getName()); + } + + ASSERT_EQ(std::string("TestStorageClass"), + userApi.getDirectoryStorageClass(requester, "/grandparent/parent")); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, deleteDirectory_root) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/"; + + ASSERT_THROW(userApi.deleteDirectory(requester, "/"), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, deleteDirectory_existing_top_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + } + + ASSERT_NO_THROW(userApi.deleteDirectory(requester, "/grandparent")); + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_FALSE(itor.hasMore()); + } +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + deleteDirectory_non_empty_top_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + + { + const std::string topLevelDirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, topLevelDirPath)); + + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + } + + { + const std::string secondLevelDirPath = "/grandparent/parent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, secondLevelDirPath)); + + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + } + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/grandparent")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("parent"), entry.getName()); + } + + ASSERT_THROW(userApi.deleteDirectory(requester, "/grandparent"), std::exception); + + { + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/grandparent")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("parent"), entry.getName()); + } +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + deleteDirectory_non_existing_top_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + + ASSERT_THROW(userApi.deleteDirectory(requester, "/grandparent"), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, setDirectoryStorageClass_top_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + + { + std::string name; + ASSERT_NO_THROW(name = userApi.getDirectoryStorageClass(requester, dirPath)); + ASSERT_TRUE(name.empty()); + } + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 2; + const std::string comment = "Comment"; + { + SqliteMiddleTierAdmin adminApi(vfs, db); + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, comment)); + } + + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + { + std::string name; + ASSERT_NO_THROW(name = userApi.getDirectoryStorageClass(requester, dirPath)); + ASSERT_EQ(storageClassName, name); + } +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + clearDirectoryStorageClass_top_level) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + const SecurityIdentity requester; + const std::string dirPath = "/grandparent"; + + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + + DirectoryIterator itor; + + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + + ASSERT_TRUE(itor.hasMore()); + + DirectoryEntry entry; + + ASSERT_NO_THROW(entry = itor.next()); + + ASSERT_EQ(std::string("grandparent"), entry.getName()); + + { + std::string name; + ASSERT_NO_THROW(name = userApi.getDirectoryStorageClass(requester, dirPath)); + ASSERT_TRUE(name.empty()); + } + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 2; + const std::string comment = "Comment"; + SqliteMiddleTierAdmin adminApi(vfs, db); + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, comment)); + + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + { + std::string name; + ASSERT_NO_THROW(name = userApi.getDirectoryStorageClass(requester, dirPath)); + ASSERT_EQ(storageClassName, name); + } + + ASSERT_THROW(adminApi.deleteStorageClass(requester, storageClassName), + std::exception); + + ASSERT_NO_THROW(userApi.clearDirectoryStorageClass(requester, dirPath)); + + { + std::string name; + ASSERT_NO_THROW(name = userApi.getDirectoryStorageClass(requester, dirPath)); + ASSERT_TRUE(name.empty()); + } + + ASSERT_NO_THROW(adminApi.deleteStorageClass(requester, storageClassName)); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, archive_to_new_file) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 1; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + const std::string tapePoolName = "TestTapePool"; + const uint16_t nbDrives = 1; + const uint16_t nbPartialTapes = 1; + const std::string tapePoolComment = "Tape-pool comment"; + ASSERT_NO_THROW(adminApi.createTapePool(requester, tapePoolName, nbDrives, + nbPartialTapes, tapePoolComment)); + + const uint16_t copyNb = 1; + const std::string archiveRouteComment = "Archive-route comment"; + ASSERT_NO_THROW(adminApi.createArchiveRoute(requester, storageClassName, + copyNb, tapePoolName, archiveRouteComment)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl"); + const std::string dstPath = "/grandparent/parent_file"; + ASSERT_NO_THROW(userApi.archive(requester, srcUrls, dstPath)); + + { + DirectoryIterator itor; + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + ASSERT_TRUE(itor.hasMore()); + DirectoryEntry entry; + ASSERT_NO_THROW(entry = itor.next()); + ASSERT_EQ(std::string("grandparent"), entry.getName()); + ASSERT_EQ(DirectoryEntry::ENTRYTYPE_DIRECTORY, entry.getType()); + ASSERT_EQ(storageClassName, entry.getStorageClassName()); + } + + { + DirectoryIterator itor; + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, + "/grandparent")); + ASSERT_TRUE(itor.hasMore()); + DirectoryEntry entry; + ASSERT_NO_THROW(entry = itor.next()); + ASSERT_EQ(std::string("parent_file"), entry.getName()); + ASSERT_EQ(DirectoryEntry::ENTRYTYPE_FILE, entry.getType()); + ASSERT_EQ(storageClassName, entry.getStorageClassName()); + } + + { + DirectoryEntry entry; + ASSERT_NO_THROW(entry = userApi.stat(requester, dstPath)); + ASSERT_EQ(DirectoryEntry::ENTRYTYPE_FILE, entry.getType()); + ASSERT_EQ(storageClassName, entry.getStorageClassName()); + } + + { + const std::map<TapePool, std::list<ArchivalJob> > allJobs = + userApi.getArchivalJobs(requester); + ASSERT_EQ(1, allJobs.size()); + std::map<TapePool, std::list<ArchivalJob> >::const_iterator + poolItor = allJobs.begin(); + ASSERT_FALSE(poolItor == allJobs.end()); + const TapePool &pool = poolItor->first; + ASSERT_TRUE(tapePoolName == pool.getName()); + const std::list<ArchivalJob> &poolJobs = poolItor->second; + ASSERT_EQ(1, poolJobs.size()); + std::set<std::string> srcUrls; + std::set<std::string> dstPaths; + for(std::list<ArchivalJob>::const_iterator jobItor = poolJobs.begin(); + jobItor != poolJobs.end(); jobItor++) { + ASSERT_EQ(ArchivalJobState::PENDING, jobItor->getState()); + srcUrls.insert(jobItor->getSrcUrl()); + dstPaths.insert(jobItor->getDstPath()); + } + ASSERT_EQ(1, srcUrls.size()); + ASSERT_FALSE(srcUrls.find("diskUrl") == srcUrls.end()); + ASSERT_EQ(1, dstPaths.size()); + ASSERT_FALSE(dstPaths.find("/grandparent/parent_file") == dstPaths.end()); + } + + { + const std::list<ArchivalJob> poolJobs = userApi.getArchivalJobs(requester, + tapePoolName); + ASSERT_EQ(1, poolJobs.size()); + std::set<std::string> srcUrls; + std::set<std::string> dstPaths; + for(std::list<ArchivalJob>::const_iterator jobItor = poolJobs.begin(); + jobItor != poolJobs.end(); jobItor++) { + ASSERT_EQ(ArchivalJobState::PENDING, jobItor->getState()); + srcUrls.insert(jobItor->getSrcUrl()); + dstPaths.insert(jobItor->getDstPath()); + } + ASSERT_EQ(1, srcUrls.size()); + ASSERT_FALSE(srcUrls.find("diskUrl") == srcUrls.end()); + ASSERT_EQ(1, dstPaths.size()); + ASSERT_FALSE(dstPaths.find("/grandparent/parent_file") == dstPaths.end()); + } +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + archive_to_new_file_with_no_storage_class) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl"); + const std::string dstPath = "/grandparent/parent_file"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + archive_to_new_file_with_zero_copy_storage_class) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 0; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl"); + const std::string dstPath = "/grandparent/parent_file"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, archive_to_new_file_with_no_route) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 1; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + const std::string tapePoolName = "TestTapePool"; + const uint16_t nbDrives = 1; + const uint16_t nbPartialTapes = 1; + const std::string tapePoolComment = "Tape-pool comment"; + ASSERT_NO_THROW(adminApi.createTapePool(requester, tapePoolName, nbDrives, + nbPartialTapes, tapePoolComment)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl"); + const std::string dstPath = "/grandparent/parent_file"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + archive_to_new_file_with_incomplete_routing) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 2; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + const std::string tapePoolName = "TestTapePool"; + const uint16_t nbDrives = 1; + const uint16_t nbPartialTapes = 1; + const std::string tapePoolComment = "Tape-pool comment"; + ASSERT_NO_THROW(adminApi.createTapePool(requester, tapePoolName, nbDrives, + nbPartialTapes, tapePoolComment)); + + const uint16_t copyNb = 1; + const std::string archiveRouteComment = "Archive-route comment"; + ASSERT_NO_THROW(adminApi.createArchiveRoute(requester, storageClassName, + copyNb, tapePoolName, archiveRouteComment)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl"); + const std::string dstPath = "/grandparent/parent_file"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, archive_to_directory) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 1; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + const std::string tapePoolName = "TestTapePool"; + const uint16_t nbDrives = 1; + const uint16_t nbPartialTapes = 1; + const std::string tapePoolComment = "Tape-pool comment"; + ASSERT_NO_THROW(adminApi.createTapePool(requester, tapePoolName, nbDrives, + nbPartialTapes, tapePoolComment)); + + const uint16_t copyNb = 1; + const std::string archiveRouteComment = "Archive-route comment"; + ASSERT_NO_THROW(adminApi.createArchiveRoute(requester, storageClassName, + copyNb, tapePoolName, archiveRouteComment)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl1"); + srcUrls.push_back("diskUrl2"); + srcUrls.push_back("diskUrl3"); + srcUrls.push_back("diskUrl4"); + const std::string dstPath = "/grandparent"; + ASSERT_NO_THROW(userApi.archive(requester, srcUrls, dstPath)); + + { + DirectoryIterator itor; + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, "/")); + ASSERT_TRUE(itor.hasMore()); + DirectoryEntry entry; + ASSERT_NO_THROW(entry = itor.next()); + ASSERT_EQ(std::string("grandparent"), entry.getName()); + ASSERT_EQ(DirectoryEntry::ENTRYTYPE_DIRECTORY, entry.getType()); + ASSERT_EQ(storageClassName, entry.getStorageClassName()); + } + + { + std::set<std::string> archiveFileNames; + DirectoryIterator itor; + ASSERT_NO_THROW(itor = userApi.getDirectoryContents(requester, + "/grandparent")); + while(itor.hasMore()) { + const DirectoryEntry entry = itor.next(); + archiveFileNames.insert(entry.getName()); + } + ASSERT_EQ(4, archiveFileNames.size()); + ASSERT_TRUE(archiveFileNames.find("diskUrl1") != archiveFileNames.end()); + ASSERT_TRUE(archiveFileNames.find("diskUrl2") != archiveFileNames.end()); + ASSERT_TRUE(archiveFileNames.find("diskUrl3") != archiveFileNames.end()); + ASSERT_TRUE(archiveFileNames.find("diskUrl4") != archiveFileNames.end()); + } + + { + const std::map<TapePool, std::list<ArchivalJob> > allJobs = + userApi.getArchivalJobs(requester); + ASSERT_EQ(1, allJobs.size()); + std::map<TapePool, std::list<ArchivalJob> >::const_iterator + poolItor = allJobs.begin(); + ASSERT_FALSE(poolItor == allJobs.end()); + const TapePool &pool = poolItor->first; + ASSERT_TRUE(tapePoolName == pool.getName()); + const std::list<ArchivalJob> &poolJobs = poolItor->second; + ASSERT_EQ(4, poolJobs.size()); + std::set<std::string> srcUrls; + std::set<std::string> dstPaths; + for(std::list<ArchivalJob>::const_iterator jobItor = poolJobs.begin(); + jobItor != poolJobs.end(); jobItor++) { + ASSERT_EQ(ArchivalJobState::PENDING, jobItor->getState()); + srcUrls.insert(jobItor->getSrcUrl()); + dstPaths.insert(jobItor->getDstPath()); + } + ASSERT_EQ(4, srcUrls.size()); + ASSERT_FALSE(srcUrls.find("diskUrl1") == srcUrls.end()); + ASSERT_FALSE(srcUrls.find("diskUrl2") == srcUrls.end()); + ASSERT_FALSE(srcUrls.find("diskUrl3") == srcUrls.end()); + ASSERT_FALSE(srcUrls.find("diskUrl4") == srcUrls.end()); + ASSERT_EQ(4, dstPaths.size()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl1") == srcUrls.end()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl2") == srcUrls.end()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl3") == srcUrls.end()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl4") == srcUrls.end()); + } + + { + const std::list<ArchivalJob> poolJobs = userApi.getArchivalJobs(requester, + tapePoolName); + ASSERT_EQ(4, poolJobs.size()); + std::set<std::string> srcUrls; + std::set<std::string> dstPaths; + for(std::list<ArchivalJob>::const_iterator jobItor = poolJobs.begin(); + jobItor != poolJobs.end(); jobItor++) { + ASSERT_EQ(ArchivalJobState::PENDING, jobItor->getState()); + srcUrls.insert(jobItor->getSrcUrl()); + dstPaths.insert(jobItor->getDstPath()); + } + ASSERT_EQ(4, srcUrls.size()); + ASSERT_FALSE(srcUrls.find("diskUrl1") == srcUrls.end()); + ASSERT_FALSE(srcUrls.find("diskUrl2") == srcUrls.end()); + ASSERT_FALSE(srcUrls.find("diskUrl3") == srcUrls.end()); + ASSERT_FALSE(srcUrls.find("diskUrl4") == srcUrls.end()); + ASSERT_EQ(4, dstPaths.size()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl1") == srcUrls.end()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl2") == srcUrls.end()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl3") == srcUrls.end()); + ASSERT_FALSE(dstPaths.find("/grandparent/diskUrl4") == srcUrls.end()); + } +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + archive_to_directory_without_storage_class) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl1"); + srcUrls.push_back("diskUrl2"); + srcUrls.push_back("diskUrl3"); + srcUrls.push_back("diskUrl4"); + const std::string dstPath = "/grandparent"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + archive_to_directory_with_zero_copy_storage_class) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 0; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl1"); + srcUrls.push_back("diskUrl2"); + srcUrls.push_back("diskUrl3"); + srcUrls.push_back("diskUrl4"); + const std::string dstPath = "/grandparent"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, archive_to_directory_with_no_route) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 1; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + const std::string tapePoolName = "TestTapePool"; + const uint16_t nbDrives = 1; + const uint16_t nbPartialTapes = 1; + const std::string tapePoolComment = "Tape-pool comment"; + ASSERT_NO_THROW(adminApi.createTapePool(requester, tapePoolName, nbDrives, + nbPartialTapes, tapePoolComment)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl1"); + srcUrls.push_back("diskUrl2"); + srcUrls.push_back("diskUrl3"); + srcUrls.push_back("diskUrl4"); + const std::string dstPath = "/grandparent"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +TEST_F(cta_client_SqliteMiddleTierUserTest, + archive_to_directory_with_incomplete_routing) { + using namespace cta; + + SqliteDatabase db; + Vfs vfs; + SqliteMiddleTierUser userApi(vfs, db); + SqliteMiddleTierAdmin adminApi(vfs, db); + const SecurityIdentity requester; + + const std::string storageClassName = "TestStorageClass"; + const uint16_t nbCopies = 2; + const std::string storageClassComment = "Storage-class comment"; + ASSERT_NO_THROW(adminApi.createStorageClass(requester, storageClassName, + nbCopies, storageClassComment)); + + const std::string dirPath = "/grandparent"; + ASSERT_NO_THROW(userApi.createDirectory(requester, dirPath)); + ASSERT_NO_THROW(userApi.setDirectoryStorageClass(requester, dirPath, + storageClassName)); + + const std::string tapePoolName = "TestTapePool"; + const uint16_t nbDrives = 1; + const uint16_t nbPartialTapes = 1; + const std::string tapePoolComment = "Tape-pool comment"; + ASSERT_NO_THROW(adminApi.createTapePool(requester, tapePoolName, nbDrives, + nbPartialTapes, tapePoolComment)); + + const uint16_t copyNb = 1; + const std::string archiveRouteComment = "Archive-route comment"; + ASSERT_NO_THROW(adminApi.createArchiveRoute(requester, storageClassName, + copyNb, tapePoolName, archiveRouteComment)); + + std::list<std::string> srcUrls; + srcUrls.push_back("diskUrl1"); + srcUrls.push_back("diskUrl2"); + srcUrls.push_back("diskUrl3"); + srcUrls.push_back("diskUrl4"); + const std::string dstPath = "/grandparent"; + ASSERT_THROW(userApi.archive(requester, srcUrls, dstPath), std::exception); +} + +} // namespace unitTests diff --git a/libs/middletier/Vfs.cpp b/libs/middletier/Vfs.cpp index 68c5441e810fc358bc7bae8479e032fe21863458..2211c757d87859d523031b066b8ff26a484c69e5 100644 --- a/libs/middletier/Vfs.cpp +++ b/libs/middletier/Vfs.cpp @@ -71,6 +71,35 @@ void cta::Vfs::checkPathnameDoesNotExist(const std::string &dirPath) { } } +//------------------------------------------------------------------------------ +// checkStorageClassIsNotInUse +//------------------------------------------------------------------------------ +void cta::Vfs::checkStorageClassIsNotInUse(const SecurityIdentity &requester, const std::string &storageClass, const std::string &dirPath) { + if(getDirectoryStorageClass(requester, dirPath)==storageClass) { + std::ostringstream message; + message << "checkStorageClassIsNotInUse() - " << dirPath << " has the " << storageClass << " storage class."; + throw(Exception(message.str())); + } + + struct dirent *entry; + DIR *dp = opendir((m_fsDir+dirPath).c_str()); + if (dp == NULL) { + char buf[256]; + std::ostringstream message; + message << "checkStorageClassIsNotInUse() - opendir " << m_fsDir+dirPath << " error. Reason: \n" << strerror_r(errno, buf, 256); + throw(Exception(message.str())); + } + + while((entry = readdir(dp))) { + if(entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { + const std::string dirEntryPathname = dirPath+(entry->d_name); + checkStorageClassIsNotInUse(requester, storageClass, dirEntryPathname); + } + } + + closedir(dp); +} + //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ diff --git a/libs/middletier/Vfs.hpp b/libs/middletier/Vfs.hpp index a87436e93174bd1dff71749219cd5f6a7461e526..e3e57293d66785494d3dc8ba421aa3a39bc6682e 100644 --- a/libs/middletier/Vfs.hpp +++ b/libs/middletier/Vfs.hpp @@ -43,6 +43,8 @@ public: bool isExistingDirectory(const SecurityIdentity &requester, const std::string &dirPath); std::string getVidOfFile(const SecurityIdentity &requester, const std::string &pathname, uint16_t copyNb); + + void checkStorageClassIsNotInUse(const SecurityIdentity &requester, const std::string &storageClass, const std::string &dirPath); private: