diff --git a/objectstore/CMakeLists.txt b/objectstore/CMakeLists.txt
index 7e7fb2ec98c44316a60634785b4af26e1abf7aef..9e5a4dc6e38d5c624623393d6b7956c3684d3191 100644
--- a/objectstore/CMakeLists.txt
+++ b/objectstore/CMakeLists.txt
@@ -18,44 +18,19 @@ add_library (CTAObjectStore SHARED
   AgentRegister.cpp
   AgentWatchdog.cpp
   TapePool.cpp
+  Tape.cpp
   DriveRegister.cpp
-  #AdminUsersList.cpp
   BackendVFS.cpp
   BackendRados.cpp
   ObjectOps.cpp
   ProtocolBuffersAlgorithms.cpp
-  #FIFO.cpp
   GenericObject.cpp
   GarbageCollector.cpp)
 
-# add_executable(tapeResourceManagerTest tapeResourceManagerTest.cpp)
-# target_link_libraries(tapeResourceManagerTest
-#   protobuf rados CTAObjectStore)
-# 
-# add_executable(dumpStructure dumpStructure.cpp)
-# target_link_libraries(dumpStructure
-#   protobuf rados CTAObjectStore)
-# 
-# add_executable(jobPoster jobPoster.cpp)
-# target_link_libraries(jobPoster
-#   protobuf rados CTAObjectStore)
-# 
-# add_executable(recaller recaller.cpp)
-# target_link_libraries(recaller
-#   protobuf rados CTAObjectStore)
-# 
-# add_executable(garbageCollector garbageCollector.cpp)
-# target_link_libraries(garbageCollector
-#   protobuf rados CTAObjectStore)
-# 
-# add_executable(createEnvironment createEnvironment.cpp)
-# target_link_libraries(createEnvironment
-#   protobuf rados CTAObjectStore)
-
 set(ObjectStoreUnitTests
   BackendTest.cpp
   RootEntryTest.cpp
-  #FIFOTest.cpp
+  TapeTest.cpp
   GarbageCollectorTest.cpp
 )
 
diff --git a/objectstore/CreationLog.hpp b/objectstore/CreationLog.hpp
index 1045c43382eeea4d4d988734942d23bbf83957b6..49a1fce33f68f50fd24cb45e5212afd6e5677b09 100644
--- a/objectstore/CreationLog.hpp
+++ b/objectstore/CreationLog.hpp
@@ -16,6 +16,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#pragma once
+
 #include "common/UserIdentity.hpp"
 #include "objectstore/cta.pb.h"
 #include "scheduler/CreationLog.hpp"
diff --git a/objectstore/ObjectOps.cpp b/objectstore/ObjectOps.cpp
index 8aaba7ff562b37e56fde88b8ded176359a33bc6f..16032a44c3c8fc2d0716053e80bfca78063442c1 100644
--- a/objectstore/ObjectOps.cpp
+++ b/objectstore/ObjectOps.cpp
@@ -23,19 +23,14 @@ namespace cta { namespace objectstore {
   
 #define MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(A) \
   template <> const serializers::ObjectType ObjectOps<serializers::A>::typeId = serializers::A##_t
+
   MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(GenericObject);
   MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(RootEntry);
   MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(AgentRegister);
   MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(Agent);
   MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(TapePool);
   MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(DriveRegister);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(JobPool);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(RecallFIFO);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(MigrationFIFO);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(RecallJob);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(Counter);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(FIFO);
-//  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(AdminUsersList);
+  MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID(Tape);
   
 #undef MAKE_CTA_OBJECTSTORE_OBJECTOPS_TYPEID
 }} 
\ No newline at end of file
diff --git a/objectstore/RootEntry.cpp b/objectstore/RootEntry.cpp
index 1894993331762c1a4b5c697e76bfa10d9a9b8afd..60524149f130f3918266108718298a015b141839 100644
--- a/objectstore/RootEntry.cpp
+++ b/objectstore/RootEntry.cpp
@@ -456,6 +456,7 @@ std::string cta::objectstore::RootEntry::addOrGetTapePoolAndCommit(const std::st
   // Insert the tape pool, then its pointer, with agent intent log update
   // First generate the intent. We expect the agent to be passed locked.
   std::string tapePoolAddress = agent.nextId("tapePool");
+  // TODO Do we expect the agent to be passed locked or not: to be clarified.
   ScopedExclusiveLock agl(agent);
   agent.fetch();
   agent.addToOwnership(tapePoolAddress);
@@ -762,6 +763,6 @@ std::string cta::objectstore::RootEntry::dump () {
 //  if (m_payload.has_jobpool()) ret << "jobPool=" << m_payload.jobpool() << std::endl;
 /*  if (m_payload.has_driveregister()) ret << "driveRegister=" << m_payload.driveregister() << std::endl;
   if (m_payload.has_taperegister()) ret << "tapeRegister=" << m_payload.taperegister() << std::endl;*/
-  ret << ">>>> Root entry dump start" << std::endl;
+  ret << ">>>> Root entry dump end" << std::endl;
   return ret.str();
 }
diff --git a/objectstore/Tape.cpp b/objectstore/Tape.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dc3b27e9f82bec66084ff12c8efaa91e903726ad
--- /dev/null
+++ b/objectstore/Tape.cpp
@@ -0,0 +1,97 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Tape.hpp"
+#include "GenericObject.hpp"
+
+cta::objectstore::Tape::Tape(const std::string& address, Backend& os):
+  ObjectOps<serializers::Tape>(os, address) { }
+
+cta::objectstore::Tape::Tape(GenericObject& go):
+  ObjectOps<serializers::Tape>(go.objectStore()){
+  // Here we transplant the generic object into the new object
+  go.transplantHeader(*this);
+  // And interpret the header.
+  getPayloadFromHeader();
+}
+
+void cta::objectstore::Tape::initialize(const std::string &name) {
+  ObjectOps<serializers::Tape>::initialize();
+  // Set the reguired fields
+  m_payload.set_vid(name);
+  m_payload.set_bytesstored(0);
+  m_payload.set_lastfseq(0);
+  m_payloadInterpreted = true;
+}
+
+
+bool cta::objectstore::Tape::isEmpty() {
+  checkPayloadReadable();
+  return !m_payload.retrievaljobs_size();
+}
+
+void cta::objectstore::Tape::removeIfEmpty() {
+  checkPayloadWritable();
+  if (!isEmpty()) {
+    throw NotEmpty("In Tape::removeIfEmpty: trying to remove an tape with retrievals queued");
+  }
+  remove();
+}
+
+void cta::objectstore::Tape::addStoredData(uint64_t bytes) {
+  checkPayloadWritable();
+  m_payload.set_bytesstored(m_payload.bytesstored()+bytes);
+}
+
+uint64_t cta::objectstore::Tape::getStoredData() {
+  checkPayloadReadable();
+  return m_payload.bytesstored();
+}
+
+std::string cta::objectstore::Tape::getVid() {
+  checkPayloadReadable();
+  return m_payload.vid();
+}
+
+std::string cta::objectstore::Tape::dump() {
+  checkPayloadReadable();
+  std::stringstream ret;
+  ret << "<<<< Tape dump start: vid=" << m_payload.vid() << std::endl;
+  ret << "  lastFseq=" << m_payload.lastfseq() 
+      << " bytesStored=" << m_payload.bytesstored() << std::endl;
+  ret << "  Retrieval jobs queued: " << m_payload.retrievaljobs_size() << std::endl;
+  if (m_payload.readmounts_size()) {
+    auto lrm = m_payload.readmounts(0);
+    ret << "  Latest read for mount: " << lrm.host() << " " << lrm.time() << " " 
+        << lrm.drivevendor() << " " << lrm.drivemodel() << " " 
+        << lrm.driveserial() << std::endl;
+  }
+  if (m_payload.writemounts_size()) {
+    auto lwm = m_payload.writemounts(0);
+    ret << "  Latest write for mount: " << lwm.host() << " " << lwm.time() << " " 
+        << lwm.drivevendor() << " " << lwm.drivemodel() << " " 
+        << lwm.driveserial() << std::endl;
+  }
+  ret << ">>>> Tape dump end" << std::endl;
+  return ret.str();
+}
+
+
+
+
+
diff --git a/objectstore/Tape.hpp b/objectstore/Tape.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ca188a48c8e76b66c6f1253bd5680922df72263f
--- /dev/null
+++ b/objectstore/Tape.hpp
@@ -0,0 +1,48 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ObjectOps.hpp"
+#include "objectstore/cta.pb.h"
+
+namespace cta { namespace objectstore {
+  
+class Backend;
+class Agent;
+class GenericObject;
+
+class Tape: public ObjectOps<serializers::Tape> {
+public:
+  Tape(const std::string & address, Backend & os);
+  Tape(GenericObject & go);
+  void initialize(const std::string & vid);
+  void garbageCollect();
+  bool isEmpty();
+  CTA_GENERATE_EXCEPTION_CLASS(NotEmpty);
+  void removeIfEmpty();
+  std::string dump();
+  
+  // -- Stored data counting ---------------------------------------------------
+  uint64_t getStoredData();
+  std::string getVid();
+  void setStoredData(uint64_t bytes);
+  void addStoredData(uint64_t bytes);
+};
+
+}}
\ No newline at end of file
diff --git a/objectstore/TapePool.cpp b/objectstore/TapePool.cpp
index 56f17bee5f8ac9a2f2d4e1c094edf8de900fee18..53db02bf75f4ac915860c3b779a80468ac3b89e2 100644
--- a/objectstore/TapePool.cpp
+++ b/objectstore/TapePool.cpp
@@ -18,6 +18,9 @@
 
 #include "TapePool.hpp"
 #include "GenericObject.hpp"
+#include "ProtcolBuffersAlgorithms.hpp"
+#include "CreationLog.hpp"
+#include "Tape.hpp"
 
 cta::objectstore::TapePool::TapePool(const std::string& address, Backend& os):
   ObjectOps<serializers::TapePool>(os, address) { }
@@ -42,6 +45,107 @@ void cta::objectstore::TapePool::initialize(const std::string& name) {
   m_payloadInterpreted = true;
 }
 
+namespace {
+  bool operator == (const std::string & vid,
+    const cta::objectstore::serializers::TapePointer &t) {
+    return vid==t.vid();
+  }
+}
+
+std::string cta::objectstore::TapePool::addOrGetTapeAndCommit(const std::string& vid, 
+  const std::string& logicalLibraryName, const uint64_t capacityInBytes, 
+  Agent& agent, const cta::CreationLog& creationLog) {
+  checkPayloadWritable();
+  // Check the tape already exists
+  try {
+    return serializers::findElement(m_payload.tapes(), vid).address();
+  } catch (serializers::NotFound &) {}
+  // Insert the tape, then its pointer, with agent intent log update
+  // first generate the intent. We expect the agent to be passed locked.
+  std::string tapeAddress = agent.nextId(std::string("tape_") + vid + "_");
+  // TODO Do we expect the agent to be passed locked or not: to be clarified.
+  ScopedExclusiveLock agl(agent);
+  agent.fetch();
+  agent.addToOwnership(tapeAddress);
+  agent.commit();
+  // The create the tape object
+  Tape t(tapeAddress, ObjectOps<serializers::TapePool>::m_objectStore);
+  t.initialize(vid);
+  t.setOwner(agent.getAddressIfSet());
+  t.setBackupOwner(getAddressIfSet());
+  t.insert();
+  ScopedExclusiveLock tl(t);
+  // Now reference the tape in the pool
+  auto * pt = m_payload.mutable_tapes()->Add();
+  pt->set_address(tapeAddress);
+  pt->set_capacity(capacityInBytes);
+  pt->set_library(logicalLibraryName);
+  pt->set_vid(vid);
+  objectstore::CreationLog oslog(creationLog);
+  oslog.serialize(*pt->mutable_log());
+  commit();
+  // Switch the tape ownership
+  t.setOwner(getAddressIfSet());
+  t.commit();
+  // Clean up the agent. We're done.
+  agent.removeFromOwnership(tapeAddress);
+  agent.commit();
+  return tapeAddress;
+}
+
+void cta::objectstore::TapePool::removeTapeAndCommit(const std::string& vid) {
+  checkPayloadWritable();
+  try {
+    // Find the tape
+    auto tp = serializers::findElement(m_payload.tapes(), vid);
+    // Open the tape object
+    Tape t(tp.address(), m_objectStore);
+    ScopedExclusiveLock tl(t);
+    t.fetch();
+    // Verify this is the tape we're looking for.
+    if (t.getVid() != vid) {
+      std::stringstream err;
+      err << "Unexpected tape VID found in object pointed to for tape: "
+          << vid << " found: " << t.getVid();
+      throw WrongTape(err.str());
+    }
+    // We can now delete the tape
+    t.remove();
+    // And remove it from our entry
+    serializers::removeOccurences(m_payload.mutable_tapes(), vid);
+    // We commit for safety and symmetry with the add operation
+    commit();
+  } catch (serializers::NotFound &) {
+    // No such tape. Nothing to to.
+    throw NoSuchTape("In TapePool::removeTapeAndCommit: trying to remove non-existing tape");
+  }
+}
+
+auto cta::objectstore::TapePool::dumpTapes() -> std::list<TapeDump>{
+  checkPayloadReadable();
+  std::list<TapeDump> ret;
+  auto & tl = m_payload.tapes();
+  for (auto t=tl.begin(); t!=tl.end(); t++) {
+    ret.push_back(TapeDump());
+    ret.back().address = t->address();
+    ret.back().vid = t->vid();
+    ret.back().capacityInBytes = t->capacity();
+    ret.back().logicalLibraryName = t->library();
+    ret.back().log.deserialize(t->log());
+  }
+  return ret;
+}
+
+std::string cta::objectstore::TapePool::getTapeAddress(const std::string& vid) {
+  checkPayloadReadable();
+  return serializers::findElement(m_payload.tapes(), vid).address();
+}
+
+
+
+
+
+
 bool cta::objectstore::TapePool::isEmpty() {
   checkPayloadReadable();
   // Check we have no tapes in pool
@@ -57,7 +161,7 @@ bool cta::objectstore::TapePool::isEmpty() {
 void cta::objectstore::TapePool::garbageCollect() {
   checkPayloadWritable();
   if (!isEmpty()) {
-    throw (NotEmpty("Trying to garbage collect a non-empty AgentRegister: internal error"));
+    throw (NotEmpty("Trying to garbage collect a non-empty TapePool: internal error"));
   }
   remove();
 }
diff --git a/objectstore/TapePool.hpp b/objectstore/TapePool.hpp
index be5a4a9f6edde0fa2b7114fdd20b03be330430d7..e35fb6bdf873e73e803bfb41864858e51779da5b 100644
--- a/objectstore/TapePool.hpp
+++ b/objectstore/TapePool.hpp
@@ -22,6 +22,9 @@
 #include "ObjectOps.hpp"
 #include <string>
 #include "objectstore/cta.pb.h"
+#include "scheduler/CreationLog.hpp"
+#include "CreationLog.hpp"
+#include "Agent.hpp"
 
 namespace cta { namespace objectstore {
   
@@ -42,6 +45,26 @@ public:
   void setName(const std::string & name);
   std::string getName();
   
+  // Tapes management ==========================================================
+  std::string addOrGetTapeAndCommit(const std::string &vid, 
+    const std::string &logicalLibraryName, const uint64_t capacityInBytes, 
+    Agent & agent, const cta::CreationLog & CreationLog);
+  CTA_GENERATE_EXCEPTION_CLASS(NoSuchTape);
+  CTA_GENERATE_EXCEPTION_CLASS(WrongTape);
+  void removeTapeAndCommit(const std::string &vid);
+  std::string getTapeAddress(const std::string &vid);
+  class TapeDump {
+  public:
+    std::string vid;
+    std::string address;
+    std::string logicalLibraryName;
+    uint64_t capacityInBytes;
+    objectstore::CreationLog log;
+  };
+  std::list<TapeDump> dumpTapes();
+  
+  // Archival jobs management ==================================================
+  
   // Check that the tape pool is empty (of both tapes and jobs)
   bool isEmpty();
  
diff --git a/objectstore/TapeTest.cpp b/objectstore/TapeTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1161a89087e4d0743fb3bd56b4a90698244d4b52
--- /dev/null
+++ b/objectstore/TapeTest.cpp
@@ -0,0 +1,52 @@
+/*
+ * The CERN Tape Archive (CTA) project
+ * Copyright (C) 2015  CERN
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include "Tape.hpp"
+#include "BackendVFS.hpp"
+#include "Agent.hpp"
+
+namespace unitTests {
+  
+TEST(Tape, BasicAccess) {
+  cta::objectstore::BackendVFS be;
+  cta::objectstore::Agent agent(be);
+  agent.generateName("unitTest");
+  std::string tapeAddress = agent.nextId("Tape");
+  { 
+    // Try to create the tape entry
+    cta::objectstore::Tape t(tapeAddress, be);
+    t.initialize("V12345");
+    t.insert();
+  }
+  {
+    // Try to read back and dump the tape
+    cta::objectstore::Tape t(tapeAddress, be);
+    ASSERT_THROW(t.fetch(), cta::exception::Exception);
+    cta::objectstore::ScopedSharedLock lock(t);
+    ASSERT_NO_THROW(t.fetch());
+    t.dump();
+  }
+  // Delete the root entry
+  cta::objectstore::Tape t(tapeAddress, be);
+  cta::objectstore::ScopedExclusiveLock lock(t);
+  t.fetch();
+  t.removeIfEmpty();
+  ASSERT_EQ(false, t.exists());
+}
+}
\ No newline at end of file
diff --git a/objectstore/cta.proto b/objectstore/cta.proto
index 1ff1efc5c16e8af423aa7ff39c0ac97a3766bf9a..1974b0c7d5968e6be3b5c165c372a8cc030beb4a 100644
--- a/objectstore/cta.proto
+++ b/objectstore/cta.proto
@@ -8,14 +8,7 @@ enum ObjectType {
   Agent_t = 2;
   TapePool_t = 3;
   DriveRegister_t = 4;
-//  JobPool_t = 3;
-//  RecallFIFO_t = 4;
-//  MigrationFIFO_t = 5;
-//  RecallJob_t = 6;
-//  Counter_t = 7;
-//  FIFO_t = 8;
-//  AdminUsersList_t = 9;
-//  StorageClassList_t = 10;
+  Tape_t = 5;
   GenericObject_t = 1000;
 }
 
@@ -149,13 +142,6 @@ message Agent {
   repeated string ownedobjects = 2003;
 }
 
-////// The registers (simple name arrays)
-////message Register {
-////  repeated string elements = 150;
-////}
-////
-// The agent register holds 2 lists:
-// a full list, and a list of agents not yet watched
 message AgentRegister {
   repeated string agents = 2100;
   repeated string untrackedagents = 2101;
@@ -168,12 +154,19 @@ message ArchivalJobPointer {
   required string address = 3002;
 }
 
+message RetrievalJobPointer {
+  required uint64 size = 3001;
+  required string address = 3002;
+}
+
 // ------------- Tape pools  ---------------------------------------------------
 
 message TapePointer {
-  required string name = 4000;
+  required string vid = 4000;
   required string address  = 4001;
-  required CreationLog log = 4002;
+  required string library = 4002;
+  required uint64 capacity = 4003;
+  required CreationLog log = 4004;
 }
 
 message TapePool {
@@ -183,131 +176,30 @@ message TapePool {
   required uint64 ArchivalJobsTotalSize = 4103;
 }
 
+// ------------- Tape ----------------------------------------------------------
+
+message MountInfo {
+  required string host = 4200;
+  required string drivevendor = 4201;
+  required string drivemodel = 4202;
+  required string driveserial = 4203;
+  required uint64 time = 4204;
+}
+
+message Tape {
+  required string vid = 4300;
+  required uint64 lastfseq = 4301;
+  required uint64 bytesstored = 4302;
+  repeated MountInfo readmounts = 4303;
+  repeated MountInfo writemounts = 4304;
+  repeated RetrievalJobPointer retrievaljobs = 4305;
+}
+
 // ------------- Drives handling  ----------------------------------------------
 
 message DriveRegister {
   repeated string drivenames = 5000;
 }
 
-////
-////// A basic FIFO
-////// poping is done by increasing the read pointer, and from time to time
-////// collapsing the name array.
-////// There is no write pointer because we always append at the end of the name
-////// array.
-////message FIFO {
-////  required uint64 readPointer = 200;
-////  repeated string name = 201;
-////}
-////
-////// A basic shared counter
-////message Counter {
-////  required uint64 count = 300;
-////}
-////
-////// The agents's elements:
-////message ObjectCreationIntent {
-////  required ObjectType type = 1101;
-////  required string name = 1102;
-////  required string container = 1103;
-////}
-////
-////message ObjectOwnershipIntent {
-////  required ObjectType type = 1111;
-////  required string name = 1112;
-////}
-////
-////// The tape record
-////message Tape {
-////  required string type = 2001;
-////  required string format = 2002;
-////  required string vid = 2003;
-////  required uint64 maxFseq = 2004;
-////  required string status = 2005 ;
-////}
-////
-////// The drive record
-////message Drive {
-////  required string name = 3001;
-////  required string status = 3002;
-////}
-////
-////// The jobs
-////message MigrationJob {
-////  required string owner = 4001;
-////  required string status = 4002;
-////  required string source = 4003;
-////  required string destination = 4004;
-////}
-////
-////message RecallJob {
-////  required string owner = 5001;
-////  required string status = 5002;
-////  required string source = 5003;
-////  required string destination = 5004;
-////}
-////
-////// The job pool
-////message JobPool {
-////  required string migration = 7001;
-////  required string recall = 7002;
-////  required string recallcounter = 7003;
-////}
-////
-////message RecallFIFO {}
-////
-////message MigrationFIFO {}
-////
-////message UserIdentity {
-////  required uint32 uid = 8001;
-////  required uint32 gid = 8002;
-////}
-////
-////message AdminUser  {
-////  required UserIdentity user = 8010;
-////  required UserIdentity creator = 8011;
-////  required uint64 creationTime = 8012;
-////  required string comment = 8013;
-////}
-////
-////// AdminHosts are just strings
-////
-////message ArchivalRoute {
-////  required uint32 copynb = 8100;
-////  required string tapepool = 8101;
-////}
-////
-////message StorageClass {
-////  required string name = 8200;
-////  required uint32 nbcopies = 8201;
-////  repeated ArchivalRoute routes = 8202;
-////}
-////
-////message Tape {
-////  required uint64 capacity = 8300;
-////  required uint64 dataontape = 8301;
-////  required string logicallibrary = 8302;
-////}
-////
-////message TapePool {
-////  
-////}
-////
-////
-////
-////message ConfigurationItem {
-////  required UserIdentity creator = 9002;
-////  optional string comment = 9003;
-////}
-////
-////message StorageClass {
-////  required string name = 9000;
-////  required uint32 nbCopies = 9001;
-////
-////}
-////
-////message StorageClassList {
-////  repeated StorageClass element = 9050;
-////}
 
 
diff --git a/scheduler/MockSchedulerDatabase.cpp b/scheduler/MockSchedulerDatabase.cpp
index 1e95dbf3225b80405b34b964dc3f388a92f862ff..cf9bf81ed3c91d266d657eeab2fe73768b22195c 100644
--- a/scheduler/MockSchedulerDatabase.cpp
+++ b/scheduler/MockSchedulerDatabase.cpp
@@ -578,7 +578,7 @@ cta::Tape cta::MockSchedulerDatabase::getTape(const std::string &vid) const {
   std::ostringstream query;
   cta::Tape tape;
   query << "SELECT VID, LOGICALLIBRARY, TAPEPOOL, CAPACITY_BYTES,"
-    " DATAONTAPE_BYTES, UID, GID, CREATIONTIME, COMMENT FROM TAPE WHERE VID='"
+    " DATAONTAPE_BYTES, UID, GID, HOST, CREATIONTIME, COMMENT FROM TAPE WHERE VID='"
     << vid << "';";
   sqlite3_stmt *s = NULL;
   const int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &s, 0 );
@@ -598,10 +598,11 @@ cta::Tape cta::MockSchedulerDatabase::getTape(const std::string &vid) const {
         (char *)sqlite3_column_text(statement.get(),idx("TAPEPOOL")),
         (uint64_t)sqlite3_column_int64(statement.get(),idx("CAPACITY_BYTES")),
         (uint64_t)sqlite3_column_int64(statement.get(),idx("DATAONTAPE_BYTES")),
-        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("COMMENT")),
+          time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME"))),
+          (char *)sqlite3_column_text(statement.get(),idx("COMMENT")))
       );
     }
     break;
@@ -1374,20 +1375,20 @@ std::list<cta::LogicalLibrary> cta::MockSchedulerDatabase::getLogicalLibraries()
 // createTape
 //------------------------------------------------------------------------------
 void cta::MockSchedulerDatabase::createTape(
-  const SecurityIdentity &requester,
   const std::string &vid,
   const std::string &logicalLibraryName,
   const std::string &tapePoolName,
   const uint64_t capacityInBytes,
-  const std::string &comment) {
+  const CreationLog &creationLog) {
   char *zErrMsg = 0;
   std::ostringstream query;
   query << "INSERT INTO TAPE(VID, LOGICALLIBRARY, TAPEPOOL,"
-    " CAPACITY_BYTES, DATAONTAPE_BYTES, UID, GID, CREATIONTIME, COMMENT)"
+    " CAPACITY_BYTES, DATAONTAPE_BYTES, UID, GID, HOST, CREATIONTIME, COMMENT)"
     " VALUES('" << vid << "','" << logicalLibraryName << "','" << tapePoolName
     << "',"<< (long unsigned int)capacityInBytes << ",0," <<
-    requester.getUser().uid << "," << requester.getUser().gid << ","
-    << (int)time(NULL) << ",'" << comment << "');";
+    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)) {
     std::ostringstream msg;
@@ -1429,7 +1430,7 @@ std::list<cta::Tape> cta::MockSchedulerDatabase::getTapes() const {
   std::ostringstream query;
   std::list<cta::Tape> tapes;
   query << "SELECT VID, LOGICALLIBRARY, TAPEPOOL, CAPACITY_BYTES,"
-    " DATAONTAPE_BYTES, UID, GID, CREATIONTIME, COMMENT"
+    " DATAONTAPE_BYTES, UID, GID, HOST, CREATIONTIME, COMMENT"
     " FROM TAPE ORDER BY VID;";
   sqlite3_stmt *s = NULL;
   const int rc = sqlite3_prepare(m_dbHandle, query.str().c_str(), -1, &s, 0 );
@@ -1447,10 +1448,11 @@ std::list<cta::Tape> cta::MockSchedulerDatabase::getTapes() const {
       (char *)sqlite3_column_text(statement.get(),idx("TAPEPOOL")),
       (uint64_t)sqlite3_column_int64(statement.get(),idx("CAPACITY_BYTES")),
       (uint64_t)sqlite3_column_int64(statement.get(),idx("DATAONTAPE_BYTES")),
-      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("COMMENT")),
+        time_t(sqlite3_column_int(statement.get(),idx("CREATIONTIME"))),
+        (char *)sqlite3_column_text(statement.get(),idx("COMMENT")))
     ));
   }
   return tapes;
diff --git a/scheduler/MockSchedulerDatabase.hpp b/scheduler/MockSchedulerDatabase.hpp
index 3774ed163c6830d7573708282cdd4ec2eadf34b1..0a1d781e1c78554283731dee3a997130f5c78afd 100644
--- a/scheduler/MockSchedulerDatabase.hpp
+++ b/scheduler/MockSchedulerDatabase.hpp
@@ -383,21 +383,19 @@ public:
   /**
    * Creates a tape.
    *
-   * @param requester The identity of the requester.
    * @param vid The volume identifier of the tape.
    * @param logicalLibraryName The name of the logical library to which the tape
    * belongs.
    * @param tapePoolName The name of the tape pool to which the tape belongs.
    * @param capacityInBytes The capacity of the tape.
-   * @param comment The comment describing the logical library.
+   * @param creationLog The who, where, when an why of this modification.
    */
-  void createTape(
-    const SecurityIdentity &requester,
+  virtual void createTape(
     const std::string &vid,
     const std::string &logicalLibraryName,
     const std::string &tapePoolName,
     const uint64_t capacityInBytes,
-    const std::string &comment);
+    const CreationLog &creationLog);
 
   /**
    * Deletes the tape with the specified volume identifier.
diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp
index 6a3b00f9a751be26d4e4ea1074423e5f67584fb6..d7f3025644ccdeab963f1c4a8e1bf607ba718972 100644
--- a/scheduler/OStoreDB/OStoreDB.cpp
+++ b/scheduler/OStoreDB/OStoreDB.cpp
@@ -19,6 +19,8 @@
 #include "OStoreDB.hpp"
 #include "scheduler/SecurityIdentity.hpp"
 #include "objectstore/RootEntry.hpp"
+#include "objectstore/TapePool.hpp"
+#include "objectstore/Tape.hpp"
 #include "common/exception/Exception.hpp"
 #include "scheduler/AdminHost.hpp"
 #include "scheduler/AdminUser.hpp"
@@ -26,6 +28,7 @@
 #include "scheduler/LogicalLibrary.hpp"
 #include "scheduler/StorageClass.hpp"
 #include "scheduler/TapePool.hpp"
+#include "scheduler/Tape.hpp"
 #include <algorithm>
 
 namespace cta {
@@ -259,13 +262,13 @@ void OStoreDB::createTapePool(const std::string& name,
   re.commit();
 }
 
-std::list<TapePool> OStoreDB::getTapePools() const {
+std::list<cta::TapePool> OStoreDB::getTapePools() const {
   RootEntry re(m_objectStore);
   ScopedSharedLock rel(re);
   re.fetch();
   auto tpd = re.dumpTapePools();
   rel.release();
-  std::list<TapePool> ret;
+  std::list<cta::TapePool> ret;
   for (auto tp=tpd.begin(); tp!=tpd.end(); tp++) {
     ret.push_back(cta::TapePool(tp->tapePool, tp->nbPartialTapes, tp->log));
   }
@@ -281,15 +284,62 @@ void OStoreDB::deleteTapePool(const SecurityIdentity& requester,
   re.commit();
 }
 
-void OStoreDB::createTape(const SecurityIdentity& requester, 
-  const std::string& vid, const std::string& logicalLibraryName, 
+void OStoreDB::createTape(const std::string& vid, 
+  const std::string& logicalLibraryName, 
   const std::string& tapePoolName, const uint64_t capacityInBytes, 
-  const std::string& comment) {
-  throw exception::Exception("Not Implemented");
-}
-
-std::list<Tape> OStoreDB::getTapes() const {
-  throw exception::Exception("Not Implemented");
+  const cta::CreationLog& creationLog) {
+  // To create a tape, we have to
+  // - Find the storage class and lock for write.
+  // - Create the tape object.
+  // - Connect the tape object to the tape pool.
+  RootEntry re(m_objectStore);
+  ScopedSharedLock rel(re);
+  re.fetch();
+  // Check the library exists
+  auto libs = re.dumpLibraries();
+  for (auto l=libs.begin(); l!=libs.end(); l++) {
+    if (l->library == logicalLibraryName)
+      goto found;
+  }
+  throw NoSuchLibrary("In OStoreDB::createTape: trying to create a tape in a non-existing library");
+  found:
+  std::string tpAddress = re.getTapePoolAddress(tapePoolName);
+  // Take hold of the tape pool
+  objectstore::TapePool tp(tpAddress, m_objectStore);
+  ScopedExclusiveLock tpl(tp);
+  tp.fetch();
+  // Check that the tape exists and throw an exception if it does.
+  try {
+    tp.getTapeAddress(vid);
+    throw TapeAlreadyExists("In OStoreDB::createTape: trying to create an existing tape.");
+  } catch (cta::exception::Exception &) {}
+  // Create the tape. The tape pool method takes care of the gory details for us.
+  tp.addOrGetTapeAndCommit(vid, logicalLibraryName, capacityInBytes, 
+      *m_agent, creationLog);
+  tp.commit();
+}
+
+std::list<cta::Tape> OStoreDB::getTapes() const {
+  std::list<cta::Tape> ret;
+  // Got through all tape pools. Get the list of them
+  RootEntry re(m_objectStore);
+  ScopedSharedLock rel(re);
+  re.fetch();
+  auto tpl = re.dumpTapePools();
+  for (auto tpi=tpl.begin(); tpi!=tpl.end(); tpi++) {
+    objectstore::TapePool tp(tpi->address, m_objectStore);
+    ScopedSharedLock tpl(tp);
+    tp.fetch();
+    auto tl=tp.dumpTapes();
+    for (auto ti=tl.begin(); ti!=tl.end(); ti++) {
+      objectstore::Tape t(ti->address, m_objectStore);
+      ScopedSharedLock tl(t);
+      t.fetch();
+      ret.push_back(cta::Tape(ti->vid, ti->logicalLibraryName, tpi->tapePool,
+        ti->capacityInBytes, t.getStoredData(), ti->log));
+    }
+  }
+  return ret;
 }
 
 void OStoreDB::deleteTape(const SecurityIdentity& requester, 
@@ -323,6 +373,18 @@ void OStoreDB::deleteLogicalLibrary(const SecurityIdentity& requester,
   const std::string& name) {
   RootEntry re(m_objectStore);
   ScopedExclusiveLock rel(re);
+  // Check we are not deleting a non-empty library
+  auto tpl = re.dumpTapePools();
+  for (auto tpp=tpl.begin(); tpp!=tpl.end(); tpp++) {
+    objectstore::TapePool tp(tpp->address, m_objectStore);
+    ScopedSharedLock tplock(tp);
+    tp.fetch();
+    auto tl=tp.dumpTapes();
+    for (auto t=tl.begin(); t!=tl.end(); t++) {
+      if (t->logicalLibraryName == name)
+        throw LibraryInUse("In OStoreDB::deleteLogicalLibrary: trying to delete a library used by a tape.");
+    }
+  }
   re.fetch();
   re.removeLibrary(name);
   re.commit();
@@ -346,7 +408,7 @@ void OStoreDB::markArchiveRequestForDeletion(const SecurityIdentity& requester,
   throw exception::Exception("Not Implemented");
 }
 
-std::map<TapePool, std::list<ArchiveToTapeCopyRequest> >
+std::map<cta::TapePool, std::list<ArchiveToTapeCopyRequest> >
   OStoreDB::getArchiveRequests() const {
   throw exception::Exception("Not Implemented");
 }
@@ -368,7 +430,7 @@ std::list<RetrieveFromTapeCopyRequest> OStoreDB::getRetrieveRequests(const std::
   throw exception::Exception("Not Implemented");
 }
 
-std::map<Tape, std::list<RetrieveFromTapeCopyRequest> > OStoreDB::getRetrieveRequests() const {
+std::map<cta::Tape, std::list<RetrieveFromTapeCopyRequest> > OStoreDB::getRetrieveRequests() const {
   throw exception::Exception("Not Implemented");
 }
 
diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp
index fc5b0fd947e701c06a7ebad63b2ae721658475af..e3d247c6e126a13dcc100c938528d5bc62351b99 100644
--- a/scheduler/OStoreDB/OStoreDB.hpp
+++ b/scheduler/OStoreDB/OStoreDB.hpp
@@ -101,10 +101,11 @@ public:
   virtual void deleteTapePool(const SecurityIdentity& requester, const std::string& name);
 
   /* === Tapes handling  ==================================================== */
-  virtual void createTape(const SecurityIdentity& requester, 
-    const std::string& vid, const std::string& logicalLibraryName, 
+  CTA_GENERATE_EXCEPTION_CLASS(TapeAlreadyExists);
+  CTA_GENERATE_EXCEPTION_CLASS(NoSuchLibrary);
+  virtual void createTape(const std::string& vid, const std::string& logicalLibraryName, 
     const std::string& tapePoolName, const uint64_t capacityInBytes, 
-    const std::string& comment);
+    const cta::CreationLog& creationLog);
 
   virtual std::list<Tape> getTapes() const;
 
@@ -116,6 +117,7 @@ public:
 
   virtual std::list<LogicalLibrary> getLogicalLibraries() const;
 
+  CTA_GENERATE_EXCEPTION_CLASS(LibraryInUse);
   virtual void deleteLogicalLibrary(const SecurityIdentity& requester, const std::string& name);
 
   /* === Archival requests handling  ======================================== */
diff --git a/scheduler/OStoreDB/OStoreDBFactory.hpp b/scheduler/OStoreDB/OStoreDBFactory.hpp
index 380e3aebfa2820fb678c2ba88ed98de19b948ab0..0abd0a4d36136175d7528457671107b56838673c 100644
--- a/scheduler/OStoreDB/OStoreDBFactory.hpp
+++ b/scheduler/OStoreDB/OStoreDBFactory.hpp
@@ -98,8 +98,8 @@ public:
     m_OStoreDB.createStorageClass(name, nbCopies, creationLog);
   }
 
-  virtual void createTape(const SecurityIdentity& requester, const std::string& vid, const std::string& logicalLibraryName, const std::string& tapePoolName, const uint64_t capacityInBytes, const std::string& comment) {
-    m_OStoreDB.createTape(requester, vid, logicalLibraryName, tapePoolName, capacityInBytes, comment);
+  virtual void createTape(const std::string& vid, const std::string& logicalLibraryName, const std::string& tapePoolName, const uint64_t capacityInBytes, const cta::CreationLog & creationLog) {
+    m_OStoreDB.createTape(vid, logicalLibraryName, tapePoolName, capacityInBytes, creationLog);
   }
 
   virtual void createTapePool(const std::string& name, const uint32_t nbPartialTapes, const CreationLog& creationLog) {
diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp
index cf0afe480c34b116b5170ed6455e977cf114b77d..89037124c15cadb713717d122894cfac5a5ceb54 100644
--- a/scheduler/Scheduler.cpp
+++ b/scheduler/Scheduler.cpp
@@ -328,10 +328,10 @@ void cta::Scheduler::createTape(
   const std::string &logicalLibraryName,
   const std::string &tapePoolName,
   const uint64_t capacityInBytes,
-  const std::string &comment) {
+  const CreationLog &creationLog) {
   m_db.assertIsAdminOnAdminHost(requester);
-  m_db.createTape(requester, vid, logicalLibraryName, tapePoolName,
-    capacityInBytes, comment);
+  m_db.createTape(vid, logicalLibraryName, tapePoolName,
+    capacityInBytes, creationLog);
 }
 
 //------------------------------------------------------------------------------
diff --git a/scheduler/Scheduler.hpp b/scheduler/Scheduler.hpp
index a59b8d733a5c09e7592c97950f5a8adf78eaf18e..71ac6e9e5062566b235f6c504ed2e0d550c310ba 100644
--- a/scheduler/Scheduler.hpp
+++ b/scheduler/Scheduler.hpp
@@ -382,14 +382,13 @@ public:
   /**
    * Creates a tape.
    *
-   * @param requester The identity of the user requesting the creation of the
-   * tape.
+   * @param requester The identity of the requester.
    * @param vid The volume identifier of the tape.
    * @param logicalLibraryName The name of the logical library to which the tape
    * belongs.
    * @param tapePoolName The name of the tape pool to which the tape belongs.
    * @param capacityInBytes The capacity of the tape.
-   * @param comment The comment describing the logical library.
+   * @param creationLog The who, where, when an why of this modification.
    */
   void createTape(
     const SecurityIdentity &requester,
@@ -397,7 +396,7 @@ public:
     const std::string &logicalLibraryName,
     const std::string &tapePoolName,
     const uint64_t capacityInBytes,
-    const std::string &comment);
+    const CreationLog &creationLog);
 
   /**
    * Deletes the tape with the specified volume identifier.
diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp
index 4a6e13fd2be0126eab94d70a649d1d779660194e..d34ac6c5475acbaa7e63f4033c5583930b938d3a 100644
--- a/scheduler/SchedulerDatabase.hpp
+++ b/scheduler/SchedulerDatabase.hpp
@@ -397,21 +397,19 @@ public:
   /**
    * Creates a tape.
    *
-   * @param requester The identity of the requester.
    * @param vid The volume identifier of the tape.
    * @param logicalLibraryName The name of the logical library to which the tape
    * belongs.
    * @param tapePoolName The name of the tape pool to which the tape belongs.
    * @param capacityInBytes The capacity of the tape.
-   * @param comment The comment describing the logical library.
+   * @param creationLog The who, where, when an why of this modification.
    */
   virtual void createTape(
-    const SecurityIdentity &requester,
     const std::string &vid,
     const std::string &logicalLibraryName,
     const std::string &tapePoolName,
     const uint64_t capacityInBytes,
-    const std::string &comment) = 0;
+    const CreationLog &creationLog) = 0;
 
   /**
    * Deletes the tape with the specified volume identifier.
diff --git a/scheduler/SchedulerTest.cpp b/scheduler/SchedulerTest.cpp
index 1ea6f1c45ffefbe1bb9c6c73a287d6de54da832a..c3ec14680f86ad8a151f3ca4452a6dbaf6e9ff9f 100644
--- a/scheduler/SchedulerTest.cpp
+++ b/scheduler/SchedulerTest.cpp
@@ -826,8 +826,10 @@ TEST_P(SchedulerTest, admin_createTape_new) {
   const std::string vid = "TestVid";
   const uint64_t capacityInBytes = 12345678;
   const std::string tapeComment = "Tape comment";
+  CreationLog log(s_adminOnAdminHost.getUser(), s_adminOnAdminHost.getHost(), 
+    time(NULL), tapeComment);
   ASSERT_NO_THROW(scheduler.createTape(s_adminOnAdminHost, vid, libraryName, tapePoolName,
-    capacityInBytes, tapeComment));
+    capacityInBytes, log));
   {
     std::list<Tape> tapes;
     ASSERT_NO_THROW(tapes = scheduler.getTapes(s_adminOnAdminHost));
@@ -840,7 +842,7 @@ TEST_P(SchedulerTest, admin_createTape_new) {
     ASSERT_EQ(tapePoolName, tape.getTapePoolName());
     ASSERT_EQ(capacityInBytes, tape.getCapacityInBytes());
     ASSERT_EQ(0, tape.getDataOnTapeInBytes());
-    ASSERT_EQ(tapeComment, tape.getComment());
+    ASSERT_EQ(tapeComment, tape.getCreationLog().comment);
   } 
 }
 
@@ -891,8 +893,10 @@ TEST_P(SchedulerTest,
   const std::string vid = "TestVid";
   const uint64_t capacityInBytes = 12345678;
   const std::string tapeComment = "Tape comment";
+  CreationLog log(s_adminOnAdminHost.getUser(), s_adminOnAdminHost.getHost(), 
+    time(NULL), tapeComment);
   ASSERT_THROW(scheduler.createTape(s_adminOnAdminHost, vid, libraryName, tapePoolName,
-    capacityInBytes, tapeComment), std::exception);
+    capacityInBytes, log), std::exception);
 }
 
 TEST_P(SchedulerTest, admin_createTape_new_non_existing_pool) {
@@ -939,8 +943,10 @@ TEST_P(SchedulerTest, admin_createTape_new_non_existing_pool) {
   const std::string vid = "TestVid";
   const uint64_t capacityInBytes = 12345678;
   const std::string tapeComment = "Tape comment";
+  CreationLog log(s_adminOnAdminHost.getUser(), s_adminOnAdminHost.getHost(), 
+    time(NULL), tapeComment);
   ASSERT_THROW(scheduler.createTape(s_adminOnAdminHost, vid, libraryName, tapePoolName,
-    capacityInBytes, tapeComment), std::exception);
+    capacityInBytes, log), std::exception);
 }
 
 TEST_P(SchedulerTest, getDirContents_root_dir_is_empty) {
@@ -2276,8 +2282,10 @@ TEST_P(SchedulerTest, archive_and_retrieve_new_file) {
   const std::string vid = "TestVid";
   const uint64_t capacityInBytes = 12345678;
   const std::string tapeComment = "Tape comment";
-  ASSERT_NO_THROW(scheduler.createTape(s_adminOnAdminHost, vid, libraryName, tapePoolName,
-    capacityInBytes, tapeComment));
+  CreationLog log(s_adminOnAdminHost.getUser(), s_adminOnAdminHost.getHost(), 
+    time(NULL), tapeComment);
+  ASSERT_NO_THROW(scheduler.createTape(s_adminOnAdminHost, vid, libraryName,
+    tapePoolName, capacityInBytes, log));
 
   const uint16_t copyNb = 1;
   const std::string archivalRouteComment = "Archival-route comment";
diff --git a/scheduler/Tape.cpp b/scheduler/Tape.cpp
index 305a3914f4428c389b8e33ea2c497c24bd154373..784cecaa62bfec456b5e8c2da93df96f2790cbc6 100644
--- a/scheduler/Tape.cpp
+++ b/scheduler/Tape.cpp
@@ -41,15 +41,13 @@ cta::Tape::Tape(
     const std::string &tapePoolName,
     const uint64_t capacityInBytes,
     const uint64_t dataOnTapeInBytes,
-    const UserIdentity &creator,
-    const std::string &comment,
-    const time_t creationTime):
-    ConfigurationItem(creator, comment, creationTime),
+    const CreationLog & creationLog):
     m_vid(vid),
     m_logicalLibraryName(logicalLibraryName),
     m_tapePoolName(tapePoolName),
     m_capacityInBytes(capacityInBytes),
-    m_dataOnTapeInBytes(dataOnTapeInBytes) {
+    m_dataOnTapeInBytes(dataOnTapeInBytes),
+    m_creationLog(creationLog){
 }
 
 //------------------------------------------------------------------------------
@@ -93,3 +91,10 @@ uint64_t cta::Tape::getCapacityInBytes() const throw() {
 uint64_t cta::Tape::getDataOnTapeInBytes() const throw() {
   return m_dataOnTapeInBytes;
 }
+
+//------------------------------------------------------------------------------
+// getCreationLog
+//------------------------------------------------------------------------------
+auto cta::Tape::getCreationLog() const throw() -> const CreationLog & {
+  return m_creationLog;
+}
\ No newline at end of file
diff --git a/scheduler/Tape.hpp b/scheduler/Tape.hpp
index d3a64af08f4643bc080f80bc6f33a2f17652a341..82656855359f9624001303a5fecca3918e46bf03 100644
--- a/scheduler/Tape.hpp
+++ b/scheduler/Tape.hpp
@@ -19,7 +19,7 @@
 #pragma once
 
 #include "common/UserIdentity.hpp"
-#include "scheduler/ConfigurationItem.hpp"
+#include "scheduler/CreationLog.hpp"
 
 #include <stdint.h>
 #include <string>
@@ -29,7 +29,7 @@ namespace cta {
 /**
  * Class representing a tape.
  */
-class Tape: public ConfigurationItem {
+class Tape {
 public:
 
   /**
@@ -52,12 +52,7 @@ public:
    * @param capacityInBytes The capacity of the tape.
    * @param dataOnTapeInBytes The amount of data currently stored on the tape in
    * bytes.
-   * @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
-   * time is used.
+   * @param creationLog The who, where, when an why of this modification.
    */
   Tape(
     const std::string &vid,
@@ -65,9 +60,7 @@ public:
     const std::string &tapePoolName,
     const uint64_t capacityInBytes,
     const uint64_t dataOnTapeInBytes,
-    const UserIdentity &creator,
-    const std::string &comment,
-    const time_t creationTime = time(NULL));
+    const CreationLog &creationLog);
 
   /**
    * Less than operator.
@@ -111,6 +104,13 @@ public:
    */
   uint64_t getDataOnTapeInBytes() const throw();
 
+  
+  /**
+   * Get the creation log
+   * @return Reference to the creation log
+   */
+  const CreationLog & getCreationLog() const throw();
+  
 private:
 
   /**
@@ -138,6 +138,10 @@ private:
    */
   uint64_t m_dataOnTapeInBytes;
 
+  /**
+   * The record of the entry's creation
+   */
+  CreationLog m_creationLog;
 }; // class Tape
 
 } // namespace cta
diff --git a/xroot_plugins/XrdProFile.cpp b/xroot_plugins/XrdProFile.cpp
index a679169967b1ae44fdc67aa2b246b6ab0c41bca9..16faa3983c3b70b9e6286879b51fe0949180a24f 100644
--- a/xroot_plugins/XrdProFile.cpp
+++ b/xroot_plugins/XrdProFile.cpp
@@ -796,7 +796,8 @@ void XrdProFile::xCom_tape(const std::vector<std::string> &tokens, const cta::Se
     std::istringstream capacity_ss(capacity_s);
     uint64_t capacity = 0;
     capacity_ss >> capacity;
-    m_scheduler->createTape(requester, vid, logicalLibrary, tapePool, capacity, comment);
+    cta::CreationLog log(requester.getUser(), requester.getHost(), time(NULL), comment);
+    m_scheduler->createTape(requester, vid, logicalLibrary, tapePool, capacity, log);
   }
   else if("ch" == tokens[2]) {
     std::string vid = getOptionValue(tokens, "-v", "--vid");
@@ -830,10 +831,11 @@ void XrdProFile::xCom_tape(const std::vector<std::string> &tokens, const cta::Se
                  << " " << it->getCapacityInBytes()
                  << " " << it->getTapePoolName()
                  << " " << it->getDataOnTapeInBytes()
-                 << " " << it->getCreator().uid 
-                 << " " << it->getCreator().gid 
-                 << " " << it->getCreationTime() 
-                 << " " << it->getComment() << std::endl;
+                 << " " << it->getCreationLog().user.uid 
+                 << " " << it->getCreationLog().user.gid 
+                 << " " << it->getCreationLog().host
+                 << " " << it->getCreationLog().time
+                 << " " << it->getCreationLog().comment << std::endl;
     }
     m_data = responseSS.str();
   }