Commit 17f93d5a authored by Victor Kotlyar's avatar Victor Kotlyar
Browse files

cta/CTA#506: tape-labeling in CTA

Add standalone command line tool cta-tape-label.

Command mount, label, umount the tape pointed by VID option. Tape drive
and library parameters used from /etc/cta/TPCONFIG file and catalogue
parameters from /etc/cta/cta-catalogue.conf.
To be labelled the tape must be present in the catalogue and must be
empty.
By default the tool labels the tape with enabled logical block protection
if drive supports such mode. For non-blank tapes command checks previous tape
label and label only if the old label is the same or match to the label in the
command line oldLabel option. To skip label checks for non-blank tapes --force
option could be used.
parent ca67e589
......@@ -346,6 +346,23 @@ public:
* @param vid The volume identifier of the tape to be reclaimed.
*/
virtual void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) = 0;
/**
* Checks the specified tape for the tape label command.
*
* This method checks if the tape is safe to be labeled and will throw an
* exception if the specified tape does not ready to be labeled.
*
* @param vid The volume identifier of the tape to be checked.
*/
virtual void checkTapeForLabel(const std::string &vid) = 0;
/**
* Returns the number of any files contained in the tape identified by its vid
* @param vid the vid in which we will count non superseded files
* @return the number of files on the tape
*/
virtual uint64_t getNbFilesOnTape(const std::string &vid) const = 0 ;
virtual void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) = 0;
virtual void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &vendor) = 0;
......
......@@ -233,6 +233,14 @@ public:
return retryOnLostConnection(m_log, [&]{return m_catalogue->reclaimTape(admin, vid);}, m_maxTriesToConnect);
}
void checkTapeForLabel(const std::string &vid) override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->checkTapeForLabel(vid);}, m_maxTriesToConnect);
}
uint64_t getNbFilesOnTape(const std::string &vid) const override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->getNbFilesOnTape(vid);}, m_maxTriesToConnect);
}
void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapeMediaType(admin, vid, mediaType);}, m_maxTriesToConnect);
}
......
This diff is collapsed.
......@@ -112,6 +112,8 @@ public:
const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string& diskInstanceName, const uint64_t archiveFileId, const common::dataStructures::RequesterIdentity& user, const optional<std::string>& activity, log::LogContext& lc) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
void reclaimTape(const common::dataStructures::SecurityIdentity& admin, const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
void checkTapeForLabel(const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
uint64_t getNbFilesOnTape(const std::string& vid) const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
void setTapeDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool disabledValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
void setTapeFull(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool fullValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
void setTapeReadOnly(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const bool readOnlyValue) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
......
......@@ -2379,6 +2379,42 @@ uint64_t RdbmsCatalogue::getNbNonSupersededFilesOnTape(rdbms::Conn& conn, const
}
//------------------------------------------------------------------------------
// getNbFilesOnTape
//------------------------------------------------------------------------------
uint64_t RdbmsCatalogue::getNbFilesOnTape(const std::string& vid) const {
try {
auto conn = m_connPool.getConn();
return getNbFilesOnTape(conn, vid);
} catch(exception::UserError &) {
throw;
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
//getNbFilesOnTape
//------------------------------------------------------------------------------
uint64_t RdbmsCatalogue::getNbFilesOnTape(rdbms::Conn& conn, const std::string& vid) const {
try {
const char *const sql =
"SELECT COUNT(*) AS NB_FILES FROM TAPE_FILE "
"WHERE VID = :VID ";
auto stmt = conn.createStmt(sql);
stmt.bindString(":VID", vid);
auto rset = stmt.executeQuery();
rset.next();
return rset.columnUint64("NB_FILES");
} catch(exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
throw;
}
}
void RdbmsCatalogue::deleteTapeFiles(rdbms::Conn& conn, const std::string& vid) const {
try {
const char * const sql =
......@@ -2455,6 +2491,38 @@ void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity
}
}
//------------------------------------------------------------------------------
// checkTapeForLabel
//------------------------------------------------------------------------------
void RdbmsCatalogue::checkTapeForLabel(const std::string &vid) {
try{
auto conn = m_connPool.getConn();
TapeSearchCriteria searchCriteria;
searchCriteria.vid = vid;
const auto tapes = getTapes(conn, searchCriteria);
if(tapes.empty()) {
throw exception::UserError(std::string("Cannot label tape ") + vid +
" because it does not exist");
}
//The tape exists checks any files on it
const uint64_t nbFilesOnTape = getNbFilesOnTape(conn, vid);
if( 0 != nbFilesOnTape) {
throw exception::UserError(std::string("Cannot label tape ") + vid +
" because it has " +
std::to_string(nbFilesOnTape) +
" file(s)");
}
} catch (exception::UserError& ue) {
throw;
}
catch (exception::Exception &ex) {
ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str());
throw;
}
}
//------------------------------------------------------------------------------
// getTapeLogFromRset
//------------------------------------------------------------------------------
......
......@@ -336,13 +336,40 @@ public:
* @param vid The volume identifier of the tape to be reclaimed.
*/
void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid) override;
/**
/**
* Checks the specified tape for the tape label command.
*
* This method checks if the tape is safe to be labeled and will throw an
* exception if the specified tape does not ready to be labeled.
*
* @param vid The volume identifier of the tape to be checked.
*/
void checkTapeForLabel(const std::string &vid) override;
/**
* Returns the number of non superseded files contained in the tape identified by its vid
* @param conn the database connection
* @param vid the vid in which we will count non superseded files
* @return the number of non superseded files on the vid
*/
uint64_t getNbNonSupersededFilesOnTape(rdbms::Conn &conn, const std::string &vid) const;
/**
* Returns the number of any files contained in the tape identified by its vid
* @param vid the vid in which we will count non superseded files
* @return the number of files on the tape
*/
uint64_t getNbFilesOnTape(const std::string &vid) const override;
/**
* Returns the number of any files contained in the tape identified by its vid
* @param conn the database connection
* @param vid the vid in which we will count non superseded files
* @return the number of files on the tape
*/
uint64_t getNbFilesOnTape(rdbms::Conn &conn, const std::string &vid) const;
/**
* Delete all the tape files of the VID passed in parameter
* @param conn the database connection
......
......@@ -29,6 +29,7 @@ namespace cta {
const int CA_MAXVIDLEN = 6; // maximum length for a VID
const int CTA_SCHEMA_VERSION_MAJOR = 0;
const int CTA_SCHEMA_VERSION_MINOR = 0;
const int TAPE_LABEL_UNITREADY_TIMEOUT = 300;
} // namespace cta
......
......@@ -79,7 +79,7 @@ else
fi
: <<'COMMENT_LABEL_PART'
if [ ! $LIBRARYTYPE == "mhvtl" ]; then
echo "Real tapes, not labelling";
else
......@@ -108,5 +108,6 @@ else
echo "OK"
done
fi
COMMENT_LABEL_PART
echo "### INIT COMPLETED ###"
......@@ -8,7 +8,7 @@ if [ ! -e /etc/buildtreeRunner ]; then
yum-config-manager --enable castor
# Install missing RPMs
yum -y install mt-st lsscsi sg3_utils cta-taped cta-debuginfo ceph-common
yum -y install mt-st lsscsi sg3_utils cta-taped cta-tape-label cta-debuginfo ceph-common
fi
echo "Using this configuration for library:"
......
......@@ -135,6 +135,20 @@ echo "Preparing CTA configuration for tests"
--name powerusers \
--mountpolicy ctasystest --comment "ctasystest"
echo "Labeling tapes:"
# add all tapes
for ((i=0; i<${#TAPES[@]}; i++)); do
VID=${TAPES[${i}]}
echo " cta-tape-label --vid ${VID}"
# for debug use
# kubectl --namespace ${NAMESPACE} exec tpsrv01 -c taped -- cta-tape-label --vid ${VID} --debug
kubectl --namespace ${NAMESPACE} exec tpsrv01 -c taped -- cta-tape-label --vid ${VID}
if [ $? -ne 0 ]; then
echo "ERROR: failed to label the tape ${VID}"
exit 1
fi
done
echo "Setting drive up: ${DRIVENAMES[${driveslot}]}"
kubectl --namespace ${NAMESPACE} exec ctacli -- cta-admin drive up ${DRIVENAMES[${driveslot}]}
kubectl --namespace ${NAMESPACE} exec ctacli -- cta-admin drive ls
......
......@@ -123,6 +123,9 @@ The tape server daemon
%attr(0644,root,root) %config(noreplace) /etc/sysconfig/cta-taped
%attr(0644,root,root) %config(noreplace) /etc/systemd/system/cta-taped.service
%attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-label.1cta.gz
%attr(0755,root,root) %{_bindir}/cta-tape-label
%post -n cta-taped
%systemd_post cta-taped.service
%systemdDaemonReload
......@@ -251,6 +254,7 @@ Unit tests and system tests with virtual tape drives
%{_libdir}/libctadaemonunittests.so*
%{_libdir}/libctamediachangerunittests.so*
%{_libdir}/libctadiskunittests.so*
%{_libdir}/libctatapelabelunittests.so*
%{_bindir}/cta-systemTests
%{_libdir}/libctadaemonunittests-multiprocess.so*
%attr(0644,root,root) %{_datadir}/%{name}-%{ctaVersion}/unittest/*.suppr
......@@ -347,6 +351,18 @@ The client of the Remote Media Changer Daemon (rmcd)
%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cta/cta-smc.conf
%attr(0644,root,root) %doc /usr/share/man/man1/cta-smc.1cta.gz
%package -n cta-tape-label
Summary: The command-line tool for pre-labelling a CTA tape.
Group: Application/CTA
Requires: cta-lib = %{version}-%{release}
%description -n cta-tape-label
CERN Tape Archive:
The command-line tool for pre-labelling a CTA tape.
%files -n cta-tape-label
%defattr(-,root,root)
%attr(0755,root,root) %{_bindir}/cta-tape-label
%attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-label.1cta.gz
%package -n cta-common
Summary: CERN Tape Archive common items
Group: Application/CTA
......
......@@ -8,6 +8,7 @@ add_subdirectory (daemon)
add_subdirectory (session)
# The tape session's threads are in a separate directory (session, but compiled
# from the previous one to create a single library).
add_subdirectory (tapelabel)
include_directories (${PROTOBUF3_INCLUDE_DIRS})
add_executable (cta-taped cta-taped.cpp)
......
......@@ -35,7 +35,7 @@ namespace tape {
/**
* The full path of the TPCONFIG file which is installed on each tape server.
*/
const char *const TPCONFIGPATH = "/etc/castor/TPCONFIG";
const char *const TPCONFIGPATH = "/etc/cta/TPCONFIG";
} // namespace tape
} // namespace castor
......
......@@ -22,7 +22,7 @@
*****************************************************************************/
#pragma once
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
#include "tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp"
namespace castor {
namespace tape {
......
......@@ -23,8 +23,8 @@
#pragma once
#include "castor/tape/tapeserver/file/Structures.hpp"
#include "castor/tape/tapeserver/daemon/VolumeInfo.hpp"
#include "tapeserver/castor/tape/tapeserver/file/Structures.hpp"
#include "tapeserver/castor/tape/tapeserver/daemon/VolumeInfo.hpp"
#include "common/exception/Exception.hpp"
#include "scheduler/ArchiveJob.hpp"
#include "scheduler/RetrieveJob.hpp"
......
# 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/>.
cmake_minimum_required (VERSION 2.6)
add_executable(cta-tape-label
TapeLabelCmd.cpp
CmdLineTool.cpp
TapeLabelCmdLineArgs.cpp
TapeLabelCmdMain.cpp)
target_link_libraries (cta-tape-label
ctacommon
TapeDrive
ctamediachanger
ctacatalogue
SCSI
)
# need to be removed when drop dependencies to taped
find_package(Protobuf3 REQUIRED)
set_property (TARGET cta-tape-label APPEND PROPERTY INSTALL_RPATH ${PROTOBUF3_RPATH})
if (OCCI_SUPPORT)
set_property (TARGET cta-tape-label APPEND PROPERTY INSTALL_RPATH ${ORACLE-INSTANTCLIENT_RPATH})
endif (OCCI_SUPPORT)
install (TARGETS cta-tape-label DESTINATION /usr/bin)
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/cta-tape-label.1cta DESTINATION /usr/share/man/man1)
add_library(ctatapelabelunittests SHARED
TapeLabelCmdLineArgs.cpp
TapeLabelCmdLineArgsTest.cpp)
set_property(TARGET ctatapelabelunittests PROPERTY SOVERSION "${CTA_SOVERSION}")
set_property(TARGET ctatapelabelunittests PROPERTY VERSION "${CTA_LIBVERSION}")
install (TARGETS ctatapelabelunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
/*
* 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 "tapeserver/tapelabel/CmdLineTool.hpp"
#include "common/exception/CommandLineNotParsed.hpp"
#include <unistd.h>
namespace cta {
namespace tapeserver {
namespace tapelabel {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
CmdLineTool::CmdLineTool(
std::istream &inStream,
std::ostream &outStream,
std::ostream &errStream) noexcept:
m_in(inStream),
m_out(outStream),
m_err(errStream) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
CmdLineTool::~CmdLineTool() noexcept {
}
//------------------------------------------------------------------------------
// getUsername
//------------------------------------------------------------------------------
std::string CmdLineTool::getUsername() {
char buf[256];
if(getlogin_r(buf, sizeof(buf))) {
return "UNKNOWN";
} else {
return buf;
}
}
//------------------------------------------------------------------------------
// getHostname
//------------------------------------------------------------------------------
std::string CmdLineTool::getHostname() {
char buf[256];
if(gethostname(buf, sizeof(buf))) {
return "UNKNOWN";
} else {
buf[sizeof(buf) - 1] = '\0';
return buf;
}
}
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int CmdLineTool::main(const int argc, char *const *const argv) {
bool cmdLineNotParsed = false;
std::string errorMessage;
try {
return exceptionThrowingMain(argc, argv);
} catch(exception::CommandLineNotParsed &ue) {
errorMessage = ue.getMessage().str();
cmdLineNotParsed = true;
} catch(exception::Exception &ex) {
errorMessage = ex.getMessage().str();
} catch(std::exception &se) {
errorMessage = se.what();
} catch(...) {
errorMessage = "An unknown exception was thrown";
}
// Reaching this point means the command has failed, an exception was throw
// and errorMessage has been set accordingly
m_err << "Aborting: " << errorMessage << std::endl;
if(cmdLineNotParsed) {
m_err << std::endl;
printUsage(m_err);
}
return 1;
}
} // namespace tapelabel
} // namespace tapeserver
} // namespace cta
/*
* 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 <istream>
#include <ostream>
namespace cta {
namespace tapeserver {
namespace tapelabel {
/**
* Abstract class implementing common code and data structures for a
* command-line tool.
*/
class CmdLineTool {
public:
/**
* Constructor.
*
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
*/
CmdLineTool(std::istream &inStream, std::ostream &outStream, std::ostream &errStream) noexcept;
/**
* Pure-virtual destructor to guarantee this class is abstract.
*/
virtual ~CmdLineTool() noexcept = 0;
/**
* The object's implementation of main() that should be called from the main()
* of the program.
*
* @param argc The number of command-line arguments including the program name.
* @param argv The command-line arguments.
* @return The exit value of the program.
*/
int main(const int argc, char *const *const argv);
protected:
/**
* An exception throwing version of main().
*
* @param argc The number of command-line arguments including the program name.
* @param argv The command-line arguments.
* @return The exit value of the program.
*/
virtual int exceptionThrowingMain(const int argc, char *const *const argv) = 0;
/**
* Prints the usage message of the command-line tool.
*
* @param os The output stream to which the usage message is to be printed.
*/
virtual void printUsage(std::ostream &os) = 0;
/**
* Standard input stream.
*/
std::istream &m_in;
/**
* Standard output stream.
*/
std::ostream &m_out;
/**
* Standard error stream.
*/
std::ostream &m_err;
/**
* Returns the name of the user running the command-line tool.
*
* @return The name of the user running the command-line tool.
*/
static std::string getUsername();
/**
* Returns the name of the host on which the command-line tool is running.
*
* @return The name of the host on which the command-line tool is running.
*/
static std::string getHostname();
}; // class CmdLineTool
} // namespace tapelabel
} // namespace catalogue
} // namespace cta
This diff is collapsed.
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/log/StdoutLogger.hpp"
#include "common/log/LogContext.hpp"
#include "common/processCap/ProcessCap.hpp"
#include "tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp"
#include "tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp"
#include "tapeserver/castor/tape/tapeserver/daemon/EncryptionControl.hpp"
#include "tapeserver/daemon/Tpconfig.hpp"
#include "tapeserver/tapelabel/CmdLineTool.hpp"
#include "catalogue/CatalogueFactoryFactory.hpp"
#include "mediachanger/MediaChangerFacade.hpp"
#include <memory>
namespace cta {