From 111f1137cffd1ce7334da885caa6dafc73a2d856 Mon Sep 17 00:00:00 2001
From: Eric Cano <Eric.Cano@cern.ch>
Date: Tue, 16 Jun 2015 11:58:47 +0200
Subject: [PATCH] Added support for TapePool and Libaries in OStoreDB.

---
 objectstore/RootEntry.cpp              | 14 ++++---
 objectstore/RootEntry.hpp              | 13 ++++--
 objectstore/RootEntryTest.cpp          |  6 +--
 objectstore/cta.proto                  |  3 +-
 scheduler/ArchivalRoute.hpp            |  8 +---
 scheduler/FileSystemStorageClasses.hpp |  3 +-
 scheduler/LogicalLibrary.cpp           | 14 ++++---
 scheduler/LogicalLibrary.hpp           | 27 ++++++------
 scheduler/MockSchedulerDatabase.cpp    | 50 +++++++++++++---------
 scheduler/MockSchedulerDatabase.hpp    |  3 +-
 scheduler/OStoreDB/OStoreDB.cpp        | 58 ++++++++++++++++++++------
 scheduler/OStoreDB/OStoreDB.hpp        |  4 +-
 scheduler/OStoreDB/OStoreDBFactory.hpp |  4 +-
 scheduler/Scheduler.cpp                |  3 +-
 scheduler/SchedulerDatabase.hpp        |  3 +-
 scheduler/SchedulerTest.cpp            |  8 ++--
 scheduler/StorageClass.cpp             | 12 +++---
 scheduler/StorageClass.hpp             |  6 +--
 scheduler/TapePool.cpp                 | 15 ++++---
 scheduler/TapePool.hpp                 | 26 +++++++-----
 xroot_plugins/XrdProFile.cpp           | 18 ++++----
 21 files changed, 179 insertions(+), 119 deletions(-)

diff --git a/objectstore/RootEntry.cpp b/objectstore/RootEntry.cpp
index b9e1bea27b..72f20fdcb6 100644
--- a/objectstore/RootEntry.cpp
+++ b/objectstore/RootEntry.cpp
@@ -388,12 +388,14 @@ bool cta::objectstore::RootEntry::libraryExists(const std::string& library) {
   return serializers::isElementPresent(m_payload.libraries(), library);
 }
 
-std::list<std::string> cta::objectstore::RootEntry::dumpLibraries() {
+auto cta::objectstore::RootEntry::dumpLibraries() -> std::list<LibraryDump> {
   checkPayloadReadable();
-  std::list<std::string> ret;
+  std::list<LibraryDump> ret;
   auto & list=m_payload.libraries();
   for (auto i=list.begin(); i!=list.end(); i++) {
-    ret.push_back(i->name());
+    ret.push_back(LibraryDump());
+    ret.back().library = i->name();
+    ret.back().log.deserialize(i->log());
   }
   return ret;
 }
@@ -413,7 +415,7 @@ namespace {
 }
 
 std::string cta::objectstore::RootEntry::addOrGetTapePoolAndCommit(const std::string& tapePool,
-  Agent& agent, const CreationLog& log) {
+  uint32_t nbPartialTapes, Agent& agent, const CreationLog& log) {
   checkPayloadWritable();
   // Check the tape pool does not already exist
   try {
@@ -436,6 +438,7 @@ std::string cta::objectstore::RootEntry::addOrGetTapePoolAndCommit(const std::st
   auto * tpp = m_payload.mutable_tapepoolpointers()->Add();
   tpp->set_address(tapePoolAddress);
   tpp->set_name(tapePool);
+  tpp->set_nbpartialtapes(nbPartialTapes);
   log.serialize(*tpp->mutable_log());
   // We must commit here to ensure the tape pool object is referenced.
   commit();
@@ -492,7 +495,7 @@ std::string cta::objectstore::RootEntry::getTapePoolAddress(const std::string& t
   }
 }
 
-auto cta::objectstore::RootEntry::dumpTapePool() -> std::list<TapePoolDump> {
+auto cta::objectstore::RootEntry::dumpTapePools() -> std::list<TapePoolDump> {
   checkPayloadReadable();
   std::list<TapePoolDump> ret;
   auto & tpl = m_payload.tapepoolpointers();
@@ -500,6 +503,7 @@ auto cta::objectstore::RootEntry::dumpTapePool() -> std::list<TapePoolDump> {
     ret.push_back(TapePoolDump());
     ret.back().address = i->address();
     ret.back().tapePool = i->name();
+    ret.back().nbPartialTapes = i->nbpartialtapes();
     ret.back().log.deserialize(i->log());
   }
   return ret;
diff --git a/objectstore/RootEntry.hpp b/objectstore/RootEntry.hpp
index 18a19246fc..7005edc365 100644
--- a/objectstore/RootEntry.hpp
+++ b/objectstore/RootEntry.hpp
@@ -114,14 +114,20 @@ public:
   void addLibrary(const std::string & library, const CreationLog & log);
   void removeLibrary(const std::string & library);
   bool libraryExists(const std::string & library);
-  std::list<std::string> dumpLibraries();
+  class LibraryDump {
+  public:
+    std::string library;
+    CreationLog log;
+  };
+  std::list<LibraryDump> dumpLibraries();
   
   // TapePoolManipulations =====================================================
   CTA_GENERATE_EXCEPTION_CLASS(TapePoolNotEmpty);
   CTA_GENERATE_EXCEPTION_CLASS(WrongTapePool);
   /** This function implicitly creates the tape pool structure and updates 
    * the pointer to it. It needs to implicitly commit the object to the store. */
-  std::string addOrGetTapePoolAndCommit(const std::string & tapePool, Agent & agent,
+  std::string addOrGetTapePoolAndCommit(const std::string & tapePool,
+    uint32_t nbPartialTapes, Agent & agent,
     const CreationLog & log);
   /** This function implicitly deletes the tape pool structure. 
    * Fails if it not empty*/
@@ -131,9 +137,10 @@ public:
   public:
     std::string tapePool;
     std::string address;
+    uint32_t nbPartialTapes;
     CreationLog log;
   };
-  std::list<TapePoolDump> dumpTapePool();
+  std::list<TapePoolDump> dumpTapePools();
   
   // Drive register manipulations ==============================================
   CTA_GENERATE_EXCEPTION_CLASS(DriveRegisterNotEmpty);
diff --git a/objectstore/RootEntryTest.cpp b/objectstore/RootEntryTest.cpp
index 18a00bf87e..aeef076aa2 100644
--- a/objectstore/RootEntryTest.cpp
+++ b/objectstore/RootEntryTest.cpp
@@ -413,7 +413,7 @@ TEST(RootEntry, Libraries) {
     ASSERT_TRUE(re.libraryExists("library2"));
     ASSERT_FALSE(re.libraryExists("library3"));
     ASSERT_EQ(1, re.dumpLibraries().size());
-    ASSERT_EQ("library2", re.dumpLibraries().front());
+    ASSERT_EQ("library2", re.dumpLibraries().front().library);
   }
   // Delete the root entry
   cta::objectstore::RootEntry re(be);
@@ -448,7 +448,7 @@ TEST (RootEntry, TapePools) {
     re.fetch();
     ASSERT_THROW(re.getTapePoolAddress("tapePool1"),
       cta::objectstore::RootEntry::NotAllocated);
-    tpAddr1 = re.addOrGetTapePoolAndCommit("tapePool1", ag, cl);
+    tpAddr1 = re.addOrGetTapePoolAndCommit("tapePool1", 100, ag, cl);
     // Check that we car read it
     cta::objectstore::TapePool tp(tpAddr1, be);
     cta::objectstore::ScopedSharedLock tpl(tp);
@@ -459,7 +459,7 @@ TEST (RootEntry, TapePools) {
     cta::objectstore::RootEntry re(be);
     cta::objectstore::ScopedExclusiveLock lock(re);
     re.fetch();
-    tpAddr2 = re.addOrGetTapePoolAndCommit("tapePool2", ag, cl);
+    tpAddr2 = re.addOrGetTapePoolAndCommit("tapePool2", 100, ag, cl);
     ASSERT_TRUE(be.exists(tpAddr2));
   }
   {
diff --git a/objectstore/cta.proto b/objectstore/cta.proto
index 3fbe584805..1ff1efc5c1 100644
--- a/objectstore/cta.proto
+++ b/objectstore/cta.proto
@@ -90,7 +90,8 @@ message StorageClass {
 message TapePoolPointer {
   required string name = 70;
   required string address  = 71;
-  required CreationLog log = 72;
+  required uint32 nbpartialtapes = 72;
+  required CreationLog log = 73;
 }
 
 // Description of a library
diff --git a/scheduler/ArchivalRoute.hpp b/scheduler/ArchivalRoute.hpp
index 5098fe179b..eaa0da3a8b 100644
--- a/scheduler/ArchivalRoute.hpp
+++ b/scheduler/ArchivalRoute.hpp
@@ -27,8 +27,6 @@
 
 namespace cta {
 
-class CreationLog;
-
 /**
  * An archival route.
  */
@@ -52,11 +50,7 @@ public:
    * source disk files.
    * @param copyNb The tape copy number.  Copy numbers start from 1.
    * @param tapePoolName The name of the destination tape pool.
-   * @param creator The identity of the user that created this configuration
-   * item.
-   * @param comment Comment describing this configuration item.
-   * @param creationTime Optionally the absolute time at which this
-   * configuration item was created.  If no value is given then the current
+   * @param creationLog The who, where, when an why of this modification.
    * time is used.
    */
   ArchivalRoute(
diff --git a/scheduler/FileSystemStorageClasses.hpp b/scheduler/FileSystemStorageClasses.hpp
index 686fbc8bc6..31edc24635 100644
--- a/scheduler/FileSystemStorageClasses.hpp
+++ b/scheduler/FileSystemStorageClasses.hpp
@@ -41,8 +41,7 @@ public:
    * @param name The name of the storage class.
    * @param nbCopies The number of copies a file associated with this storage
    * class should have on tape.
-   * @param creator The identity of the user that created the storage class.
-   * @param comment The comment describing the storage class.
+   * @param creationLog The who, where, when an why of this modification.
    */
   void createStorageClass(
     const std::string &name,
diff --git a/scheduler/LogicalLibrary.cpp b/scheduler/LogicalLibrary.cpp
index 946e8828da..13c826d191 100644
--- a/scheduler/LogicalLibrary.cpp
+++ b/scheduler/LogicalLibrary.cpp
@@ -35,11 +35,8 @@ cta::LogicalLibrary::~LogicalLibrary() throw() {
 //------------------------------------------------------------------------------
 cta::LogicalLibrary::LogicalLibrary(
   const std::string &name,
-  const UserIdentity &creator,
-  const std::string &comment,
-  const time_t creationTime):
-  ConfigurationItem(creator, comment, creationTime),
-  m_name(name) {
+  const CreationLog &creationLog):
+  m_name(name), m_creationLog(creationLog) {
 }
 
 //------------------------------------------------------------------------------
@@ -48,3 +45,10 @@ cta::LogicalLibrary::LogicalLibrary(
 const std::string &cta::LogicalLibrary::getName() const throw() {
   return m_name;
 }
+
+//------------------------------------------------------------------------------
+// getCreationLog
+//------------------------------------------------------------------------------
+auto cta::LogicalLibrary::getCreationLog() const throw() -> const CreationLog & {
+  return m_creationLog;
+}
diff --git a/scheduler/LogicalLibrary.hpp b/scheduler/LogicalLibrary.hpp
index c1ab23f818..276238c254 100644
--- a/scheduler/LogicalLibrary.hpp
+++ b/scheduler/LogicalLibrary.hpp
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include "scheduler/ConfigurationItem.hpp"
+#include "scheduler/CreationLog.hpp"
 
 #include <string>
 #include <time.h>
@@ -28,7 +28,7 @@ namespace cta {
 /**
  * Class representing a logical library.
  */
-class LogicalLibrary: public ConfigurationItem {
+class LogicalLibrary  {
 public:
 
   /**
@@ -45,18 +45,12 @@ public:
    * Constructor.
    *
    * @param name The name of the logical library.
-   * @param creator The identity of the user that created this configuration
-   * item.
-   * @param comment The comment describing this configuration item.
-   * @param creationTime Optionally the absolute time at which this
-   * configuration item was created.  If no value is given then the current
+   * @param creationLog The who, where, when an why of this modification.
    * time is used.
    */
   LogicalLibrary(
     const std::string &name,
-    const UserIdentity &creator,
-    const std::string &comment,
-    const time_t creationTime = time(NULL));
+    const CreationLog &creationLog);
 
   /**
    * Returns the name of the logical library.
@@ -64,14 +58,23 @@ public:
    * @return The name of the logical library.
    */
   const std::string &getName() const throw();
-
+    
+  /**
+   * Get the creation log
+   * @return Reference to the creation log
+   */
+  const CreationLog & getCreationLog() const throw();
 private:
 
   /**
    * The name of the logical library.
    */
   std::string m_name;
-
+  
+  /**
+   * The record of the entry's creation
+   */
+  CreationLog m_creationLog;
 }; // class LogicalLibrary
 
 } // namespace cta
diff --git a/scheduler/MockSchedulerDatabase.cpp b/scheduler/MockSchedulerDatabase.cpp
index 2a4d3a3313..7fbbabd36e 100644
--- a/scheduler/MockSchedulerDatabase.cpp
+++ b/scheduler/MockSchedulerDatabase.cpp
@@ -314,7 +314,7 @@ cta::TapePool cta::MockSchedulerDatabase::getTapePool(const std::string &name)
   const {
   std::ostringstream query;
   cta::TapePool pool;
-  query << "SELECT NAME, NBPARTIALTAPES, UID, GID, CREATIONTIME, COMMENT"
+  query << "SELECT NAME, NBPARTIALTAPES, UID, GID, HOST, CREATIONTIME, COMMENT"
     " FROM TAPEPOOL WHERE NAME='" << name << "';";
   sqlite3_stmt *s = NULL;
   const int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &s, 0 );
@@ -331,10 +331,13 @@ cta::TapePool cta::MockSchedulerDatabase::getTapePool(const std::string &name)
       pool = TapePool(
         (char *)sqlite3_column_text(statement.get(),idx("NAME")),
         sqlite3_column_int(statement.get(),idx("NBPARTIALTAPES")),
-        UserIdentity(sqlite3_column_int(statement.get(),idx("UID")),
-        sqlite3_column_int(statement.get(),idx("GID"))),
-        (char *)sqlite3_column_text(statement.get(),idx("COMMENT")),
-        time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME")))
+        CreationLog(
+          UserIdentity(sqlite3_column_int(statement.get(),idx("UID")),
+            sqlite3_column_int(statement.get(),idx("GID"))),
+          (char *)sqlite3_column_text(statement.get(),idx("HOST")),
+          time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME"))),
+          (char *)sqlite3_column_text(statement.get(),idx("COMMENT"))
+        )
       );
     }
     break;
@@ -1044,7 +1047,7 @@ void cta::MockSchedulerDatabase::deleteTapePool(
 std::list<cta::TapePool> cta::MockSchedulerDatabase::getTapePools() const {
   std::ostringstream query;
   std::list<cta::TapePool> pools;
-  query << "SELECT NAME, NBPARTIALTAPES, UID, GID, CREATIONTIME, COMMENT FROM"
+  query << "SELECT NAME, NBPARTIALTAPES, UID, GID, HOST, CREATIONTIME, COMMENT FROM"
     " TAPEPOOL ORDER BY NAME;";
   sqlite3_stmt *s = NULL;
   const int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &s, 0 );
@@ -1059,10 +1062,13 @@ std::list<cta::TapePool> cta::MockSchedulerDatabase::getTapePools() const {
     pools.push_back(TapePool(
       (char *)sqlite3_column_text(statement.get(),idx("NAME")),
       sqlite3_column_int(statement.get(),idx("NBPARTIALTAPES")),
-      UserIdentity(sqlite3_column_int(statement.get(),idx("UID")),
-      sqlite3_column_int(statement.get(),idx("GID"))),
-      (char *)sqlite3_column_text(statement.get(),idx("COMMENT")),
-      time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME")))
+      CreationLog(
+          UserIdentity(sqlite3_column_int(statement.get(),idx("UID")),
+            sqlite3_column_int(statement.get(),idx("GID"))),
+          (char *)sqlite3_column_text(statement.get(),idx("HOST")),
+          time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME"))),
+          (char *)sqlite3_column_text(statement.get(),idx("COMMENT"))
+        )
     ));
   }
   return pools;
@@ -1252,14 +1258,15 @@ std::list<cta::ArchivalRoute> cta::MockSchedulerDatabase::
 // createLogicalLibrary
 //------------------------------------------------------------------------------
 void cta::MockSchedulerDatabase::createLogicalLibrary(
-  const SecurityIdentity &requester,
   const std::string &name,
-  const std::string &comment) {
+  const cta::CreationLog& creationLog) {
   char *zErrMsg = 0;
   std::ostringstream query;
-  query << "INSERT INTO LOGICALLIBRARY(NAME, UID, GID, CREATIONTIME, COMMENT)"
-    " VALUES('" << name << "',"<< requester.getUser().uid << "," <<
-    requester.getUser().gid << "," << (int)time(NULL) << ",'" << comment <<
+  query << "INSERT INTO LOGICALLIBRARY(NAME, UID, GID, HOST, CREATIONTIME, COMMENT)"
+    << " VALUES('" << name << "',"<< creationLog.user.uid << ","
+    << creationLog.user.gid << "," 
+    << " '" << creationLog.host << "', "
+    << creationLog.time << ",'" << creationLog.comment <<
     "');";
   if(SQLITE_OK != sqlite3_exec(m_dbHandle, query.str().c_str(), 0, 0,
     &zErrMsg)) {
@@ -1302,7 +1309,7 @@ std::list<cta::LogicalLibrary> cta::MockSchedulerDatabase::getLogicalLibraries()
   const {
   std::ostringstream query;
   std::list<cta::LogicalLibrary> list;
-  query << "SELECT NAME, UID, GID, CREATIONTIME, COMMENT"
+  query << "SELECT NAME, UID, GID, HOST, CREATIONTIME, COMMENT"
     " FROM LOGICALLIBRARY ORDER BY NAME;";
   sqlite3_stmt *s = NULL;
   const int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &s, 0 );
@@ -1316,10 +1323,13 @@ std::list<cta::LogicalLibrary> cta::MockSchedulerDatabase::getLogicalLibraries()
     SqliteColumnNameToIndex idx(statement.get());
     list.push_back(LogicalLibrary(
       (char *)sqlite3_column_text(statement.get(),idx("NAME")),
-      UserIdentity(sqlite3_column_int(statement.get(),idx("UID")),
-      sqlite3_column_int(statement.get(),idx("GID"))),
-      (char *)sqlite3_column_text(statement.get(),idx("COMMENT")),
-      time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME")))
+      CreationLog(
+        UserIdentity(sqlite3_column_int(statement.get(),idx("UID")),
+          sqlite3_column_int(statement.get(),idx("GID"))),
+        (char *)sqlite3_column_text(statement.get(),idx("HOST")),
+        time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME"))),
+        (char *)sqlite3_column_text(statement.get(),idx("COMMENT"))
+      )
     ));
   }
   return list;
diff --git a/scheduler/MockSchedulerDatabase.hpp b/scheduler/MockSchedulerDatabase.hpp
index 00c7104296..4637101fd6 100644
--- a/scheduler/MockSchedulerDatabase.hpp
+++ b/scheduler/MockSchedulerDatabase.hpp
@@ -332,9 +332,8 @@ public:
    * @param comment The comment describing the logical library.
    */
   void createLogicalLibrary(
-    const SecurityIdentity &requester,
     const std::string &name,
-    const std::string &comment);
+    const cta::CreationLog& creationLog);
 
   /**
    * Deletes the logical library with the specified name.
diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp
index a41369a9e0..50b5909c37 100644
--- a/scheduler/OStoreDB/OStoreDB.cpp
+++ b/scheduler/OStoreDB/OStoreDB.cpp
@@ -20,10 +20,12 @@
 #include "scheduler/SecurityIdentity.hpp"
 #include "objectstore/RootEntry.hpp"
 #include "common/exception/Exception.hpp"
-#include "scheduler/StorageClass.hpp"
 #include "scheduler/AdminHost.hpp"
 #include "scheduler/AdminUser.hpp"
 #include "scheduler/ArchivalRoute.hpp"
+#include "scheduler/LogicalLibrary.hpp"
+#include "scheduler/StorageClass.hpp"
+#include "scheduler/TapePool.hpp"
 #include <algorithm>
 
 namespace cta {
@@ -234,27 +236,36 @@ void OStoreDB::deleteArchivalRoute(const SecurityIdentity& requester,
   re.commit();
 }
 
-void OStoreDB::fileEntryCreatedInNS(const std::string &archiveFile) {
-  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
-} 
-
 void OStoreDB::createTapePool(const std::string& name,
   const uint32_t nbPartialTapes, const cta::CreationLog &creationLog) {
   RootEntry re(m_objectStore);
   ScopedExclusiveLock rel(re);
   re.fetch();
   assertAgentSet();
-  re.addOrGetTapePoolAndCommit(name, *m_agent, creationLog);
+  re.addOrGetTapePoolAndCommit(name, nbPartialTapes, *m_agent, creationLog);
   re.commit();
 }
 
 std::list<TapePool> OStoreDB::getTapePools() const {
-  throw exception::Exception("Not Implemented");
+  RootEntry re(m_objectStore);
+  ScopedSharedLock rel(re);
+  re.fetch();
+  auto tpd = re.dumpTapePools();
+  rel.release();
+  std::list<TapePool> ret;
+  for (auto tp=tpd.begin(); tp!=tpd.end(); tp++) {
+    ret.push_back(cta::TapePool(tp->tapePool, tp->nbPartialTapes, tp->log));
+  }
+  return ret;
 }
 
 void OStoreDB::deleteTapePool(const SecurityIdentity& requester, 
   const std::string& name) {
-  throw exception::Exception("Not Implemented");
+  RootEntry re(m_objectStore);
+  ScopedExclusiveLock rel(re);
+  re.fetch();
+  re.removeTapePoolAndCommit(name);
+  re.commit();
 }
 
 void OStoreDB::createTape(const SecurityIdentity& requester, 
@@ -273,18 +284,35 @@ void OStoreDB::deleteTape(const SecurityIdentity& requester,
   throw exception::Exception("Not Implemented");
 }
 
-void OStoreDB::createLogicalLibrary(const SecurityIdentity& requester,
-  const std::string& name, const std::string& comment) {
-  throw exception::Exception("Not Implemented");
+void OStoreDB::createLogicalLibrary(const std::string& name, 
+  const cta::CreationLog& creationLog) {
+  RootEntry re(m_objectStore);
+  ScopedExclusiveLock rel(re);
+  re.fetch();
+  re.addLibrary(name, creationLog);
+  re.commit();
 }
 
 std::list<LogicalLibrary> OStoreDB::getLogicalLibraries() const {
-  throw exception::Exception("Not Implemented");
+  RootEntry re(m_objectStore);
+  ScopedSharedLock rel(re);
+  re.fetch();
+  auto ll = re.dumpLibraries();
+  rel.release();
+  std::list<LogicalLibrary> ret;
+  for (auto l=ll.begin(); l!=ll.end(); l++) {
+    ret.push_back(LogicalLibrary(l->library, l->log));
+  }
+  return ret;
 }
 
 void OStoreDB::deleteLogicalLibrary(const SecurityIdentity& requester, 
   const std::string& name) {
-  throw exception::Exception("Not Implemented");
+  RootEntry re(m_objectStore);
+  ScopedExclusiveLock rel(re);
+  re.fetch();
+  re.removeLibrary(name);
+  re.commit();
 }
 
 void OStoreDB::queue(const ArchiveToFileRequest& rqst) {
@@ -295,6 +323,10 @@ void OStoreDB::queue(const ArchiveToDirRequest& rqst) {
   throw exception::Exception("Not Implemented");
 }
 
+void OStoreDB::fileEntryCreatedInNS(const std::string &archiveFile) {
+  throw exception::Exception(std::string(__FUNCTION__) + " not implemented");
+} 
+
 void OStoreDB::deleteArchiveRequest(const SecurityIdentity& requester, 
   const std::string& archiveFile) {
   throw exception::Exception("Not Implemented");
diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp
index 65f343b109..d7655458f1 100644
--- a/scheduler/OStoreDB/OStoreDB.hpp
+++ b/scheduler/OStoreDB/OStoreDB.hpp
@@ -110,8 +110,8 @@ public:
   virtual void deleteTape(const SecurityIdentity& requester, const std::string& vid);
 
   /* === Libraries handling  ================================================ */
-  virtual void createLogicalLibrary(const SecurityIdentity& requester, 
-    const std::string& name, const std::string& comment);
+  virtual void createLogicalLibrary(const std::string& name,
+    const cta::CreationLog& creationLog);
 
   virtual std::list<LogicalLibrary> getLogicalLibraries() const;
 
diff --git a/scheduler/OStoreDB/OStoreDBFactory.hpp b/scheduler/OStoreDB/OStoreDBFactory.hpp
index 84b7f7d492..5256ebdaf0 100644
--- a/scheduler/OStoreDB/OStoreDBFactory.hpp
+++ b/scheduler/OStoreDB/OStoreDBFactory.hpp
@@ -87,8 +87,8 @@ public:
     m_OStoreDB.createArchivalRoute(storageClassName, copyNb, tapePoolName, creationLog);
   }
 
-  virtual void createLogicalLibrary(const SecurityIdentity& requester, const std::string& name, const std::string& comment) {
-    m_OStoreDB.createLogicalLibrary(requester, name, comment);
+  virtual void createLogicalLibrary(const std::string& name, const cta::CreationLog& creationLog) {
+    m_OStoreDB.createLogicalLibrary(name, creationLog);
   }
 
   virtual void createStorageClass(const std::string& name, const uint16_t nbCopies, const CreationLog& creationLog) {
diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp
index 5adf2276bc..c0cbb49b23 100644
--- a/scheduler/Scheduler.cpp
+++ b/scheduler/Scheduler.cpp
@@ -296,7 +296,8 @@ void cta::Scheduler::createLogicalLibrary(
   const std::string &name,
   const std::string &comment) {
   m_db.assertIsAdminOnAdminHost(requester);
-  m_db.createLogicalLibrary(requester, name, comment);
+  m_db.createLogicalLibrary(name, CreationLog(requester.getUser(),
+      requester.getHost(), time(NULL), comment));
 }
 
 //------------------------------------------------------------------------------
diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp
index a00e982e59..26c0cf0402 100644
--- a/scheduler/SchedulerDatabase.hpp
+++ b/scheduler/SchedulerDatabase.hpp
@@ -346,9 +346,8 @@ public:
    * @param comment The comment describing the logical library.
    */
   virtual void createLogicalLibrary(
-    const SecurityIdentity &requester,
     const std::string &name,
-    const std::string &comment) = 0;
+    const cta::CreationLog& creationLog) = 0;
 
   /**
    * Deletes the logical library with the specified name.
diff --git a/scheduler/SchedulerTest.cpp b/scheduler/SchedulerTest.cpp
index 5e1ae25360..863da6ca0e 100644
--- a/scheduler/SchedulerTest.cpp
+++ b/scheduler/SchedulerTest.cpp
@@ -804,7 +804,7 @@ TEST_P(SchedulerTest, admin_createTape_new) {
     LogicalLibrary logicalLibrary;
     ASSERT_NO_THROW(logicalLibrary = libraries.front());
     ASSERT_EQ(libraryName, logicalLibrary.getName());
-    ASSERT_EQ(libraryComment, logicalLibrary.getComment());
+    ASSERT_EQ(libraryComment, logicalLibrary.getCreationLog().comment);
   }
 
   const std::string tapePoolName = "TestTapePool";
@@ -820,7 +820,7 @@ TEST_P(SchedulerTest, admin_createTape_new) {
     TapePool tapePool;
     ASSERT_NO_THROW(tapePool = tapePools.front());
     ASSERT_EQ(tapePoolName, tapePool.getName());
-    ASSERT_EQ(comment, tapePool.getComment());
+    ASSERT_EQ(comment, tapePool.getCreationLog().comment);
   } 
 
   const std::string vid = "TestVid";
@@ -885,7 +885,7 @@ TEST_P(SchedulerTest,
     TapePool tapePool;
     ASSERT_NO_THROW(tapePool = tapePools.front());
     ASSERT_EQ(tapePoolName, tapePool.getName());
-    ASSERT_EQ(comment, tapePool.getComment());
+    ASSERT_EQ(comment, tapePool.getCreationLog().comment);
   } 
 
   const std::string vid = "TestVid";
@@ -931,7 +931,7 @@ TEST_P(SchedulerTest, admin_createTape_new_non_existing_pool) {
     LogicalLibrary logicalLibrary;
     ASSERT_NO_THROW(logicalLibrary = libraries.front());
     ASSERT_EQ(libraryName, logicalLibrary.getName());
-    ASSERT_EQ(libraryComment, logicalLibrary.getComment());
+    ASSERT_EQ(libraryComment, logicalLibrary.getCreationLog().comment);
   }
 
   const std::string tapePoolName = "TestTapePool";
diff --git a/scheduler/StorageClass.cpp b/scheduler/StorageClass.cpp
index e88aa281c8..bfa8c82056 100644
--- a/scheduler/StorageClass.cpp
+++ b/scheduler/StorageClass.cpp
@@ -58,6 +58,12 @@ uint16_t cta::StorageClass::getNbCopies() const throw() {
   return m_nbCopies;
 }
 
+//------------------------------------------------------------------------------
+// getCreationLog
+//------------------------------------------------------------------------------
+auto cta::StorageClass::getCreationLog() const throw() -> const CreationLog & {
+  return m_creationLog;
+}
 //------------------------------------------------------------------------------
 // operator<
 //------------------------------------------------------------------------------
@@ -65,10 +71,4 @@ bool cta::StorageClass::operator<(const StorageClass& rhs) const {
   return m_name < rhs.m_name;
 }
 
-//------------------------------------------------------------------------------
-// getCreationLog
-//------------------------------------------------------------------------------
-auto cta::StorageClass::getCreationLog() const throw() -> const CreationLog & {
-  return m_creationLog;
-}
 
diff --git a/scheduler/StorageClass.hpp b/scheduler/StorageClass.hpp
index b4f8c82ef4..83ae27d56d 100644
--- a/scheduler/StorageClass.hpp
+++ b/scheduler/StorageClass.hpp
@@ -49,11 +49,7 @@ public:
    * @param name The name of the storage class.
    * @param nbCopies The number of copies a file associated with this storage
    * class should have on tape.
-   * @param creator The identity of the user that created this configuration
-   * item.
-   * @param comment The comment describing this configuration item.
-   * @param creationTime Optionally the absolute time at which this
-   * configuration item was created.  If no value is given then the current
+   * @param creationLog The who, where, when an why of this modification.
    * time is used.
    */
   StorageClass(
diff --git a/scheduler/TapePool.cpp b/scheduler/TapePool.cpp
index 629a59cf2d..3c86499024 100644
--- a/scheduler/TapePool.cpp
+++ b/scheduler/TapePool.cpp
@@ -37,12 +37,10 @@ cta::TapePool::~TapePool() throw() {
 cta::TapePool::TapePool(
   const std::string &name,
   const uint32_t nbPartialTapes,
-  const UserIdentity &creator,
-  const std::string &comment,
-  const time_t creationTime):
-  ConfigurationItem(creator, comment, creationTime),
+  const CreationLog &creationLog):
   m_name(name),
-  m_nbPartialTapes(nbPartialTapes) {
+  m_nbPartialTapes(nbPartialTapes),
+  m_creationLog(creationLog) {
 }
 
 //------------------------------------------------------------------------------
@@ -65,3 +63,10 @@ const std::string &cta::TapePool::getName() const throw() {
 uint32_t cta::TapePool::getNbPartialTapes() const throw() {
   return m_nbPartialTapes;
 }
+
+//------------------------------------------------------------------------------
+// getCreationLog
+//------------------------------------------------------------------------------
+auto cta::TapePool::getCreationLog() const throw() -> const CreationLog & {
+  return m_creationLog;
+}
diff --git a/scheduler/TapePool.hpp b/scheduler/TapePool.hpp
index 195aefee38..4a4dc8af9c 100644
--- a/scheduler/TapePool.hpp
+++ b/scheduler/TapePool.hpp
@@ -18,7 +18,7 @@
 
 #pragma once
 
-#include "scheduler/ConfigurationItem.hpp"
+#include "scheduler/CreationLog.hpp"
 
 #include <string>
 
@@ -27,7 +27,7 @@ namespace cta {
 /**
  * Class representing a tape pool.
  */
-class TapePool: public ConfigurationItem {
+class TapePool {
 public:
 
   /**
@@ -46,19 +46,13 @@ public:
    * @param name The name of the tape pool.
    * @param nbPartialTapes The maximum number of tapes that can be partially
    * full at any moment in time.
-   * @param creator The identity of the user that created this configuration
-   * item.
-   * @param comment The comment describing this configuration item.
-   * @param creationTime Optionally the absolute time at which this
-   * configuration item was created.  If no value is given then the current
+   * @param creationLog The who, where, when an why of this modification.
    * time is used.
    */
   TapePool(
     const std::string &name,
     const uint32_t nbPartialTapes,
-    const UserIdentity &creator,
-    const std::string &comment,
-    const time_t creationTime = time(NULL));
+    const CreationLog &creationLog);
 
   /**
    * Less than operator.
@@ -82,6 +76,12 @@ public:
    * moment in time.
    */
   uint32_t getNbPartialTapes() const throw();
+  
+  /**
+   * Get the creation log
+   * @return Reference to the creation log
+   */
+  const CreationLog & getCreationLog() const throw();
 
 private:
 
@@ -95,7 +95,11 @@ private:
    * time.
    */
   uint32_t m_nbPartialTapes;
-
+  
+  /**
+   * The record of the entry's creation
+   */
+  CreationLog m_creationLog;
 }; // class TapePool
 
 } // namespace cta
diff --git a/xroot_plugins/XrdProFile.cpp b/xroot_plugins/XrdProFile.cpp
index 7e0356e0a7..44d18c6854 100644
--- a/xroot_plugins/XrdProFile.cpp
+++ b/xroot_plugins/XrdProFile.cpp
@@ -602,10 +602,11 @@ void XrdProFile::xCom_tapepool(const std::vector<std::string> &tokens, const cta
     for(auto it = list.begin(); it != list.end(); it++) {
       responseSS << it->getName()  
                  << " " << it->getNbPartialTapes()
-                 << " " << it->getCreator().uid 
-                 << " " << it->getCreator().gid 
-                 << " " << it->getCreationTime() 
-                 << " " << it->getComment();
+                 << " " << it->getCreationLog().user.uid 
+                 << " " << it->getCreationLog().user.gid 
+                 << " " << it->getCreationLog().host
+                 << " " << it->getCreationLog().time
+                 << " " << it->getCreationLog().comment;
     }
     m_data = responseSS.str();
   }
@@ -725,10 +726,11 @@ void XrdProFile::xCom_logicallibrary(const std::vector<std::string> &tokens, con
     std::ostringstream responseSS;
     for(auto it = list.begin(); it != list.end(); it++) {
       responseSS << it->getName() 
-                 << " " << it->getCreator().uid 
-                 << " " << it->getCreator().gid 
-                 << " " << it->getCreationTime() 
-                 << " " << it->getComment();
+                 << " " << it->getCreationLog().user.uid 
+                 << " " << it->getCreationLog().user.gid
+                 << " " << it->getCreationLog().host
+                 << " " << it->getCreationLog().time
+                 << " " << it->getCreationLog().comment;
     }
     m_data = responseSS.str();
   }
-- 
GitLab