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

Moved LabelSession to ProcessForker

PLEASE NOTE - The bad day tape label scenarios are broken by this
commit.  I will fix them in a future commit.
parent 7b64b452
...@@ -261,7 +261,7 @@ public: ...@@ -261,7 +261,7 @@ public:
template<int numParams> void operator() ( template<int numParams> void operator() (
const int priority, const int priority,
const std::string &msg, const std::string &msg,
castor::log::Param(&params)[numParams], const log::Param(&params)[numParams],
const struct timeval &timeStamp) throw() { const struct timeval &timeStamp) throw() {
operator() (priority, msg, numParams, params, timeStamp); operator() (priority, msg, numParams, params, timeStamp);
} }
...@@ -282,7 +282,7 @@ public: ...@@ -282,7 +282,7 @@ public:
template<int numParams> void operator() ( template<int numParams> void operator() (
const int priority, const int priority,
const std::string &msg, const std::string &msg,
castor::log::Param(&params)[numParams]) throw() { const log::Param(&params)[numParams]) throw() {
operator() (priority, msg, numParams, params); operator() (priority, msg, numParams, params);
} }
......
...@@ -5,6 +5,7 @@ PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles}) ...@@ -5,6 +5,7 @@ PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
add_library(castormessages SHARED add_library(castormessages SHARED
${ProtoSources} ${ProtoSources}
Constants.cpp
Frame.cpp Frame.cpp
messages.cpp messages.cpp
SmartZmqContext.cpp SmartZmqContext.cpp
......
...@@ -16,28 +16,59 @@ ...@@ -16,28 +16,59 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* *
* *
* *
* @author Castor Dev team, castor-dev@cern.ch * @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/ *****************************************************************************/
#include "castor/tape/tapeserver/daemon/ProcessForkerMsgType.hpp" #include "castor/messages/Constants.hpp"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// toString // msgTypeToString
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
const char *castor::tape::tapeserver::daemon::ProcessForkerMsgType:: const char *castor::messages::msgTypeToString(const MsgType msgType) throw() {
toString(const Enum value) throw() { switch(msgType) {
switch(value) { case MSG_TYPE_NONE:
case MSG_NONE : return "None"; return "None";
case MSG_EXCEPTION : return "Exception"; case MSG_TYPE_EXCEPTION:
case MSG_FORKCLEANER : return "ForkCleaner"; return "Exception";
case MSG_FORKDATATRANSFER : return "ForkDataTransfer"; case MSG_TYPE_FORKCLEANER:
case MSG_FORKLABEL : return "ForkLabel"; return "ForkCleaner";
case MSG_FORKSUCCEEDED : return "ForkSucceeded"; case MSG_TYPE_FORKDATATRANSFER:
case MSG_PROCESSCRASHED : return "ProcessCrashed"; return "ForkDataTransfer";
case MSG_PROCESSEXITED : return "ProcessExited"; case MSG_TYPE_FORKLABEL:
case MSG_STOPPROCESSFORKER: return "StopProcessForker"; return "ForkLabel";
default : return "Unknown"; case MSG_TYPE_FORKSUCCEEDED:
return "ForkSucceeded";
case MSG_TYPE_HEARTBEAT:
return "Heartbeat";
case MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY:
return "MigrationJobFromTapeGateway";
case MSG_TYPE_MIGRATIONJOBFROMWRITETP:
return "MigrationJobFromWriteTp";
case MSG_TYPE_NBFILESONTAPE:
return "NbFilesOnTape";
case MSG_TYPE_PROCESSCRASHED:
return "ProcessCrashed";
case MSG_TYPE_PROCESSEXITED:
return "ProcessExited";
case MSG_TYPE_RECALLJOBFROMREADTP:
return "RecallJobFromReadTp";
case MSG_TYPE_RECALLJOBFROMTAPEGATEWAY:
return "RecallJobFromTapeGAteway";
case MSG_TYPE_RETURNVALUE:
return "ReturnValue";
case MSG_TYPE_STOPPROCESSFORKER:
return "StopProcessForker";
case MSG_TYPE_TAPEMOUNTEDFORMIGRATION:
return "TapeMountedForMigration";
case MSG_TYPE_TAPEMOUNTEDFORRECALL:
return "TapeMountedForRecall";
case MSG_TYPE_TAPEUNMOUNTSTARTED:
return "TapeUnmounStarted";
case MSG_TYPE_TAPEUNMOUNTED:
return "TapeUnmounted";
default:
return "Unknown";
} }
} } // msgTypeToString()
...@@ -20,24 +20,34 @@ ...@@ -20,24 +20,34 @@
* *
* @author Castor Dev team, castor-dev@cern.ch * @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
namespace castor { namespace castor {
namespace messages { namespace messages {
enum ProtocolType { enum ProtocolType {
PROTOCOL_TYPE_NONE,
PROTOCOL_TYPE_TAPE PROTOCOL_TYPE_TAPE
}; };
enum MsgType { enum MsgType {
MSG_TYPE_NONE,
MSG_TYPE_EXCEPTION, MSG_TYPE_EXCEPTION,
MSG_TYPE_FORKCLEANER,
MSG_TYPE_FORKDATATRANSFER,
MSG_TYPE_FORKLABEL,
MSG_TYPE_FORKSUCCEEDED,
MSG_TYPE_HEARTBEAT, MSG_TYPE_HEARTBEAT,
MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY, MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY,
MSG_TYPE_MIGRATIONJOBFROMWRITETP, MSG_TYPE_MIGRATIONJOBFROMWRITETP,
MSG_TYPE_NBFILESONTAPE, MSG_TYPE_NBFILESONTAPE,
MSG_TYPE_PROCESSCRASHED,
MSG_TYPE_PROCESSEXITED,
MSG_TYPE_RECALLJOBFROMREADTP, MSG_TYPE_RECALLJOBFROMREADTP,
MSG_TYPE_RECALLJOBFROMTAPEGATEWAY, MSG_TYPE_RECALLJOBFROMTAPEGATEWAY,
MSG_TYPE_RETURNVALUE, MSG_TYPE_RETURNVALUE,
MSG_TYPE_STOPPROCESSFORKER,
MSG_TYPE_TAPEMOUNTEDFORMIGRATION, MSG_TYPE_TAPEMOUNTEDFORMIGRATION,
MSG_TYPE_TAPEMOUNTEDFORRECALL, MSG_TYPE_TAPEMOUNTEDFORRECALL,
MSG_TYPE_TAPEUNMOUNTSTARTED, MSG_TYPE_TAPEUNMOUNTSTARTED,
...@@ -45,8 +55,21 @@ enum MsgType { ...@@ -45,8 +55,21 @@ enum MsgType {
}; };
enum ProtocolVersion { enum ProtocolVersion {
PROTOCOL_VERSION_NONE,
PROTOCOL_VERSION_1 PROTOCOL_VERSION_1
}; };
/**
* Returns the string representation of the specified message type.
*
* This method is thread safe because it only returns pointers to string
* literals.
*
* In the case where the specified message type is unknown this method does not
* throw an exception, instead is returns a string literal that explains the
* message type is unknown.
*/
const char *msgTypeToString(const MsgType msgType) throw();
} // namespace messages } // namespace messages
} // namespace castor } // namespace castor
...@@ -20,11 +20,6 @@ ...@@ -20,11 +20,6 @@
* *
* @author Castor Dev team, castor-dev@cern.ch * @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/ *****************************************************************************/
/*
* Author: dcome
*
* Created on March 26, 2014, 9:38 AM
*/
#pragma once #pragma once
......
...@@ -26,7 +26,6 @@ add_library(castorTapeServerDaemon ...@@ -26,7 +26,6 @@ add_library(castorTapeServerDaemon
ProcessForker.cpp ProcessForker.cpp
ProcessForkerConnectionHandler.cpp ProcessForkerConnectionHandler.cpp
ProcessForkerProxy.cpp ProcessForkerProxy.cpp
ProcessForkerMsgType.cpp
ProcessForkerProxySocket.cpp ProcessForkerProxySocket.cpp
ProcessForkerUtils.cpp ProcessForkerUtils.cpp
RecallMemoryManager.cpp RecallMemoryManager.cpp
......
...@@ -38,11 +38,6 @@ castor::tape::tapeserver::daemon::DriveCatalogue::~DriveCatalogue() throw() { ...@@ -38,11 +38,6 @@ castor::tape::tapeserver::daemon::DriveCatalogue::~DriveCatalogue() throw() {
itor++) { itor++) {
const DriveCatalogueEntry *drive = itor->second; const DriveCatalogueEntry *drive = itor->second;
if(DriveCatalogueEntry::SESSION_TYPE_LABEL == drive->getSessionType() &&
DriveCatalogueSession::SESSION_STATE_WAITFORK == drive->getSessionState()
&& -1 != drive->getLabelCmdConnection()) {
close(drive->getLabelCmdConnection());
}
delete drive; delete drive;
} }
} }
......
...@@ -477,7 +477,8 @@ void castor::tape::tapeserver::daemon::DriveCatalogueEntry::receivedLabelJob( ...@@ -477,7 +477,8 @@ void castor::tape::tapeserver::daemon::DriveCatalogueEntry::receivedLabelJob(
m_labelCmdConnection = labelCmdConnection; m_labelCmdConnection = labelCmdConnection;
m_state = DRIVE_STATE_SESSIONRUNNING; m_state = DRIVE_STATE_SESSIONRUNNING;
m_sessionType = SESSION_TYPE_LABEL; m_sessionType = SESSION_TYPE_LABEL;
m_session = new DriveCatalogueLabelSession(castor::tape::tapeserver::daemon::DriveCatalogueSession::SESSION_STATE_WAITFORK, job, labelCmdConnection); m_session = new DriveCatalogueLabelSession(
DriveCatalogueSession::SESSION_STATE_WAITFORK, job, labelCmdConnection);
break; break;
default: default:
{ {
......
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
// constructor // constructor
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::LabelSession::LabelSession( castor::tape::tapeserver::daemon::LabelSession::LabelSession(
const int labelCmdConnection,
legacymsg::RmcProxy &rmc, legacymsg::RmcProxy &rmc,
legacymsg::NsProxy &ns, legacymsg::NsProxy &ns,
const legacymsg::TapeLabelRqstMsgBody &clientRequest, const legacymsg::TapeLabelRqstMsgBody &clientRequest,
...@@ -52,7 +51,6 @@ castor::tape::tapeserver::daemon::LabelSession::LabelSession( ...@@ -52,7 +51,6 @@ castor::tape::tapeserver::daemon::LabelSession::LabelSession(
const utils::DriveConfig &driveConfig, const utils::DriveConfig &driveConfig,
const bool force): const bool force):
m_timeout(1), // 1 second of timeout for the network in the label session. This is not going to be a parameter of the constructor m_timeout(1), // 1 second of timeout for the network in the label session. This is not going to be a parameter of the constructor
m_labelCmdConnection(labelCmdConnection),
m_rmc(rmc), m_rmc(rmc),
m_ns(ns), m_ns(ns),
m_request(clientRequest), m_request(clientRequest),
...@@ -66,7 +64,44 @@ castor::tape::tapeserver::daemon::LabelSession::LabelSession( ...@@ -66,7 +64,44 @@ castor::tape::tapeserver::daemon::LabelSession::LabelSession(
// execute // execute
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::execute() { void castor::tape::tapeserver::daemon::LabelSession::execute() {
executeLabel(); std::ostringstream task;
task << "label tape " << m_request.vid << " for gid=" << m_request.gid <<
" uid=" << m_request.uid << " in drive " << m_request.drive;
log::Param params[] = {
log::Param("uid", m_request.uid),
log::Param("gid", m_request.gid),
log::Param("vid", m_request.vid),
log::Param("drive", m_request.drive),
log::Param("dgn", m_request.dgn)};
performPreMountChecks();
mountTape();
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> drive =
getDriveObject();
waitUntilTapeLoaded(drive.get(), 60); // 60 = 60 seconds
checkTapeIsWritable(drive.get());
labelTheTape(drive.get());
m_log(LOG_INFO, "The tape has been successfully labeled", params);
drive->unloadTape();
m_rmc.unmountTape(m_request.vid, m_driveConfig.librarySlot);
m_log(LOG_INFO, "The tape has been successfully unmounted after labeling", params);
}
//------------------------------------------------------------------------------
// performPreMountChecks
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::performPreMountChecks() {
checkClientIsOwnerOrAdmin();
checkIfVidStillHasSegments();
}
//------------------------------------------------------------------------------
// checkClientIsOwnerOrAdmin
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::
checkClientIsOwnerOrAdmin() {
// TO BE DONE
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
...@@ -88,6 +123,13 @@ void castor::tape::tapeserver::daemon::LabelSession::checkIfVidStillHasSegments( ...@@ -88,6 +123,13 @@ void castor::tape::tapeserver::daemon::LabelSession::checkIfVidStillHasSegments(
throw ex; throw ex;
} }
else {} // rc==castor::legacymsg::NsProxy::NSPROXY_TAPE_EMPTY. Tape is empty, we are good to go.. else {} // rc==castor::legacymsg::NsProxy::NSPROXY_TAPE_EMPTY. Tape is empty, we are good to go..
const log::Param params[] = {
log::Param("vid", m_request.vid),
log::Param("unitName", m_request.drive),
log::Param("librarySlot", m_driveConfig.librarySlot)};
m_log(LOG_INFO,
"Tape to be labeled has no files registered in the name server", params);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
...@@ -122,107 +164,66 @@ std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> ...@@ -122,107 +164,66 @@ std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface>
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// waitUntilDriveReady // mountTape
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::waitUntilDriveReady(castor::tape::tapeserver::drives::DriveInterface *drive) { void castor::tape::tapeserver::daemon::LabelSession::mountTape() {
std::list<log::Param> params; try {
params.push_back(log::Param("uid", m_request.uid)); m_rmc.mountTape(m_request.vid, m_driveConfig.librarySlot,
params.push_back(log::Param("gid", m_request.gid)); castor::legacymsg::RmcProxy::MOUNT_MODE_READWRITE);
params.push_back(log::Param("vid", m_request.vid)); const log::Param params[] = {
params.push_back(log::Param("drive", m_request.drive)); log::Param("vid", m_request.vid),
params.push_back(log::Param("dgn", m_request.dgn)); log::Param("unitName", m_request.drive),
log::Param("librarySlot", m_driveConfig.librarySlot)};
// check that drive is not write protected m_log(LOG_INFO, "Tape successfully mounted for labeling", params);
if(drive->isWriteProtected()) { } catch(castor::exception::Exception &ne) {
m_log(LOG_ERR, "Failed to label the tape: drive is write protected", castor::exception::Exception ex;
params); ex.getMessage() << "Failed to mount tape for labeling: " <<
} ne.getMessage().str();
drive->waitUntilReady(600); throw ex;
}
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// labelTheTape // waitUntilTapeLoaded
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::labelTheTape(castor::tape::tapeserver::drives::DriveInterface *drive) { void castor::tape::tapeserver::daemon::LabelSession::waitUntilTapeLoaded(
drives::DriveInterface *const drive, const int timeoutSecond) {
// We can now start labelling try {
castor::tape::tapeFile::LabelSession ls(*drive, m_request.vid, m_force); drive->waitUntilReady(timeoutSecond);
const log::Param params[] = {
log::Param("vid", m_request.vid),
log::Param("unitName", m_request.drive),
log::Param("librarySlot", m_driveConfig.librarySlot)};
m_log(LOG_INFO, "Tape to be labelled has been mounted", params);
} catch(castor::exception::Exception &ne) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to wait for tape to be loaded: " <<
ne.getMessage().str();
throw ex;
}
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// executeLabel // checkTapeIsWritable
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::executeLabel() { void castor::tape::tapeserver::daemon::LabelSession::checkTapeIsWritable(
std::ostringstream task; drives::DriveInterface *const drive) {
task << "label tape " << m_request.vid << " for gid=" << m_request.gid << if(drive->isWriteProtected()) {
" uid=" << m_request.uid << " in drive " << m_request.drive; castor::exception::Exception ex;
ex.getMessage() << "Tape to be labeled in write protected";
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> drive; throw ex;
log::Param params[] = {
log::Param("uid", m_request.uid),
log::Param("gid", m_request.gid),
log::Param("vid", m_request.vid),
log::Param("drive", m_request.drive),
log::Param("dgn", m_request.dgn)};
bool tapeMounted=false;
bool configlineSet=false;
bool labellingError=false;
bool clientNotified=false;
try {
checkIfVidStillHasSegments();
m_log(LOG_INFO, "The tape to be labeled has no files registered in the nameserver", params);
drive = getDriveObject();
m_log(LOG_INFO, "The tape drive object has been instantiated", params);
configlineSet=true;
m_rmc.mountTape(m_request.vid, m_driveConfig.librarySlot,
castor::legacymsg::RmcProxy::MOUNT_MODE_READWRITE);
m_log(LOG_INFO, "The tape has been successfully mounted for labeling", params);
tapeMounted=true;
waitUntilDriveReady(drive.get());
m_log(LOG_INFO, "The drive is ready for labeling", params);
try {
labelTheTape(drive.get());
m_log(LOG_INFO, "The tape has been successfully labeled", params);
} catch(castor::tape::tapeFile::TapeNotEmpty & ex) {
// In case of error
log::Param params[] = {log::Param("message", ex.getMessage().str())};
m_log(LOG_ERR, "The tape could not be labeled", params);
try {
legacymsg::writeTapeReplyMsg(m_timeout, m_labelCmdConnection, 1,
ex.getMessage().str());
} catch (...) {}
clientNotified=true;
}
drive->unloadTape();
m_rmc.unmountTape(m_request.vid, m_driveConfig.librarySlot);
m_log(LOG_INFO, "The tape has been successfully unmounted after labeling", params);
tapeMounted=false;
if (!labellingError) {
try {
legacymsg::writeTapeReplyMsg(m_timeout, m_labelCmdConnection, 0, "");
} catch (...) {}
clientNotified=true;
}
} catch(castor::exception::Exception &ex) {
int exitValue = EXIT_SUCCESS;
if(tapeMounted && configlineSet) {
try {
m_rmc.unmountTape(m_request.vid, m_driveConfig.librarySlot);
} catch (...) {
// Iff we fail to unload a tape, we call this a failure of the process
exitValue = EXIT_FAILURE;
}
}
log::Param params[] = {log::Param("message", ex.getMessage().str())};
m_log(LOG_ERR, "Label session caught an exception", params);
if (!clientNotified) {
try {
legacymsg::writeTapeReplyMsg(m_timeout, m_labelCmdConnection, 1, ex.getMessage().str());
} catch (...) {}
}
exit(exitValue);
} }
const log::Param params[] = {
log::Param("vid", m_request.vid),
log::Param("unitName", m_request.drive),
log::Param("librarySlot", m_driveConfig.librarySlot)};
m_log(LOG_INFO, "Tape to be labelled is writable", params);
}
//------------------------------------------------------------------------------
// labelTheTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::labelTheTape(
drives::DriveInterface *const drive) {
tapeFile::LabelSession ls(*drive, m_request.vid, m_force);
} }
...@@ -50,8 +50,6 @@ namespace daemon { ...@@ -50,8 +50,6 @@ namespace daemon {
/** /**
* Constructor * Constructor
* *
* @param labelCmdConnection The file descriptor of the connection with the
* label command.
* @param rmc Proxy object representing the rmcd daemon. * @param rmc Proxy object representing the rmcd daemon.
* @param clientRequest The request to label a tape received from the label * @param clientRequest The request to label a tape received from the label
* tape command. * tape command.
...@@ -63,7 +61,6 @@ namespace daemon { ...@@ -63,7 +61,6 @@ namespace daemon {
* tape. * tape.
*/ */
LabelSession( LabelSession(
const int labelCmdConnection,
legacymsg::RmcProxy &rmc, legacymsg::RmcProxy &rmc,
legacymsg::NsProxy &ns, legacymsg::NsProxy &ns,
const legacymsg::TapeLabelRqstMsgBody &clientRequest, const legacymsg::TapeLabelRqstMsgBody &clientRequest,
...@@ -84,19 +81,28 @@ namespace daemon { ...@@ -84,19 +81,28 @@ namespace daemon {
*/ */
int m_timeout; int m_timeout;
/**
* The file descriptor of the connection with the label command.
*/
int m_labelCmdConnection;
enum TapeNsStatus { enum TapeNsStatus {
LABEL_SESSION_STEP_SUCCEEDED, LABEL_SESSION_STEP_SUCCEEDED,
LABEL_SESSION_STEP_FAILED LABEL_SESSION_STEP_FAILED
}; };
/** /**
* Checks if the VID has still active or disabled segments registered within the name server * Performs some meta-data checks that need to be done before deciding to
* @return * mount the tape for labeling.
*/
void performPreMountChecks();
/**
* A meta-data check that sees if the user of the client is either the
* owner of the tape pool containing the tape to be labelled or is an ADMIN
* user within the CUPV privileges database.
*/
void checkClientIsOwnerOrAdmin();
/**
* A meta-data check that sees if the tape to be labelled contains files
* that are registered in the CASTOR name-server as either active or
* disabled segments.
*/ */
void checkIfVidStillHasSegments(); void checkIfVidStillHasSegments();