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:
template<int numParams> void operator() (
const int priority,
const std::string &msg,
castor::log::Param(&params)[numParams],
const log::Param(&params)[numParams],
const struct timeval &timeStamp) throw() {
operator() (priority, msg, numParams, params, timeStamp);
}
......@@ -282,7 +282,7 @@ public:
template<int numParams> void operator() (
const int priority,
const std::string &msg,
castor::log::Param(&params)[numParams]) throw() {
const log::Param(&params)[numParams]) throw() {
operator() (priority, msg, numParams, params);
}
......
......@@ -5,6 +5,7 @@ PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles})
add_library(castormessages SHARED
${ProtoSources}
Constants.cpp
Frame.cpp
messages.cpp
SmartZmqContext.cpp
......
......@@ -21,23 +21,54 @@
* @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::
toString(const Enum value) throw() {
switch(value) {
case MSG_NONE : return "None";
case MSG_EXCEPTION : return "Exception";
case MSG_FORKCLEANER : return "ForkCleaner";
case MSG_FORKDATATRANSFER : return "ForkDataTransfer";
case MSG_FORKLABEL : return "ForkLabel";
case MSG_FORKSUCCEEDED : return "ForkSucceeded";
case MSG_PROCESSCRASHED : return "ProcessCrashed";
case MSG_PROCESSEXITED : return "ProcessExited";
case MSG_STOPPROCESSFORKER: return "StopProcessForker";
default : return "Unknown";
const char *castor::messages::msgTypeToString(const MsgType msgType) throw() {
switch(msgType) {
case MSG_TYPE_NONE:
return "None";
case MSG_TYPE_EXCEPTION:
return "Exception";
case MSG_TYPE_FORKCLEANER:
return "ForkCleaner";
case MSG_TYPE_FORKDATATRANSFER:
return "ForkDataTransfer";
case MSG_TYPE_FORKLABEL:
return "ForkLabel";
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 @@
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
#pragma once
namespace castor {
namespace messages {
enum ProtocolType {
PROTOCOL_TYPE_NONE,
PROTOCOL_TYPE_TAPE
};
enum MsgType {
MSG_TYPE_NONE,
MSG_TYPE_EXCEPTION,
MSG_TYPE_FORKCLEANER,
MSG_TYPE_FORKDATATRANSFER,
MSG_TYPE_FORKLABEL,
MSG_TYPE_FORKSUCCEEDED,
MSG_TYPE_HEARTBEAT,
MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY,
MSG_TYPE_MIGRATIONJOBFROMWRITETP,
MSG_TYPE_NBFILESONTAPE,
MSG_TYPE_PROCESSCRASHED,
MSG_TYPE_PROCESSEXITED,
MSG_TYPE_RECALLJOBFROMREADTP,
MSG_TYPE_RECALLJOBFROMTAPEGATEWAY,
MSG_TYPE_RETURNVALUE,
MSG_TYPE_STOPPROCESSFORKER,
MSG_TYPE_TAPEMOUNTEDFORMIGRATION,
MSG_TYPE_TAPEMOUNTEDFORRECALL,
MSG_TYPE_TAPEUNMOUNTSTARTED,
......@@ -45,8 +55,21 @@ enum MsgType {
};
enum ProtocolVersion {
PROTOCOL_VERSION_NONE,
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 castor
......@@ -20,11 +20,6 @@
*
* @author Castor Dev team, castor-dev@cern.ch
*****************************************************************************/
/*
* Author: dcome
*
* Created on March 26, 2014, 9:38 AM
*/
#pragma once
......
......@@ -26,7 +26,6 @@ add_library(castorTapeServerDaemon
ProcessForker.cpp
ProcessForkerConnectionHandler.cpp
ProcessForkerProxy.cpp
ProcessForkerMsgType.cpp
ProcessForkerProxySocket.cpp
ProcessForkerUtils.cpp
RecallMemoryManager.cpp
......
......@@ -38,11 +38,6 @@ castor::tape::tapeserver::daemon::DriveCatalogue::~DriveCatalogue() throw() {
itor++) {
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;
}
}
......
......@@ -477,7 +477,8 @@ void castor::tape::tapeserver::daemon::DriveCatalogueEntry::receivedLabelJob(
m_labelCmdConnection = labelCmdConnection;
m_state = DRIVE_STATE_SESSIONRUNNING;
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;
default:
{
......
......@@ -43,7 +43,6 @@
// constructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::LabelSession::LabelSession(
const int labelCmdConnection,
legacymsg::RmcProxy &rmc,
legacymsg::NsProxy &ns,
const legacymsg::TapeLabelRqstMsgBody &clientRequest,
......@@ -52,7 +51,6 @@ castor::tape::tapeserver::daemon::LabelSession::LabelSession(
const utils::DriveConfig &driveConfig,
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_labelCmdConnection(labelCmdConnection),
m_rmc(rmc),
m_ns(ns),
m_request(clientRequest),
......@@ -66,7 +64,44 @@ castor::tape::tapeserver::daemon::LabelSession::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(
throw ex;
}
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>
}
//------------------------------------------------------------------------------
// waitUntilDriveReady
// mountTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::waitUntilDriveReady(castor::tape::tapeserver::drives::DriveInterface *drive) {
std::list<log::Param> params;
params.push_back(log::Param("uid", m_request.uid));
params.push_back(log::Param("gid", m_request.gid));
params.push_back(log::Param("vid", m_request.vid));
params.push_back(log::Param("drive", m_request.drive));
params.push_back(log::Param("dgn", m_request.dgn));
// check that drive is not write protected
if(drive->isWriteProtected()) {
m_log(LOG_ERR, "Failed to label the tape: drive is write protected",
params);
void castor::tape::tapeserver::daemon::LabelSession::mountTape() {
try {
m_rmc.mountTape(m_request.vid, m_driveConfig.librarySlot,
castor::legacymsg::RmcProxy::MOUNT_MODE_READWRITE);
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 successfully mounted for labeling", params);
} catch(castor::exception::Exception &ne) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to mount tape for labeling: " <<
ne.getMessage().str();
throw ex;
}
drive->waitUntilReady(600);
}
//------------------------------------------------------------------------------
// labelTheTape
// waitUntilTapeLoaded
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::labelTheTape(castor::tape::tapeserver::drives::DriveInterface *drive) {
// We can now start labelling
castor::tape::tapeFile::LabelSession ls(*drive, m_request.vid, m_force);
void castor::tape::tapeserver::daemon::LabelSession::waitUntilTapeLoaded(
drives::DriveInterface *const drive, const int timeoutSecond) {
try {
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() {
std::ostringstream task;
task << "label tape " << m_request.vid << " for gid=" << m_request.gid <<
" uid=" << m_request.uid << " in drive " << m_request.drive;
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> drive;
log::Param params[] = {
log::Param("uid", m_request.uid),
log::Param("gid", m_request.gid),
void castor::tape::tapeserver::daemon::LabelSession::checkTapeIsWritable(
drives::DriveInterface *const drive) {
if(drive->isWriteProtected()) {
castor::exception::Exception ex;
ex.getMessage() << "Tape to be labeled in write protected";
throw ex;
}
const log::Param params[] = {
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;
log::Param("unitName", m_request.drive),
log::Param("librarySlot", m_driveConfig.librarySlot)};
m_log(LOG_INFO, "Tape to be labelled is writable", params);
}
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);
}
//------------------------------------------------------------------------------
// 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 {
/**
* Constructor
*
* @param labelCmdConnection The file descriptor of the connection with the
* label command.
* @param rmc Proxy object representing the rmcd daemon.
* @param clientRequest The request to label a tape received from the label
* tape command.
......@@ -63,7 +61,6 @@ namespace daemon {
* tape.
*/
LabelSession(
const int labelCmdConnection,
legacymsg::RmcProxy &rmc,
legacymsg::NsProxy &ns,
const legacymsg::TapeLabelRqstMsgBody &clientRequest,
......@@ -84,19 +81,28 @@ namespace daemon {
*/
int m_timeout;
/**
* The file descriptor of the connection with the label command.
*/
int m_labelCmdConnection;
enum TapeNsStatus {
LABEL_SESSION_STEP_SUCCEEDED,
LABEL_SESSION_STEP_FAILED
};
/**
* Checks if the VID has still active or disabled segments registered within the name server
* @return
* Performs some meta-data checks that need to be done before deciding to
* 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();
......@@ -109,19 +115,33 @@ namespace daemon {
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> getDriveObject();
/**
* Check the tape drive write-ability and waits for it to become ready
* (tape needs to be loaded)
* @param drive The drive object pointer
* @return
* Mounts the tap eto be labelled.
*/
void waitUntilDriveReady(castor::tape::tapeserver::drives::DriveInterface *drive);
void mountTape();
/**
* Waits for the tape to be loaded into the tape drive.
*
* @param drive Object representing the drive hardware.
* @param timeoutSecond The number of seconds to wait for the tape to be
* loaded into the tape drive.
*/
void waitUntilTapeLoaded(drives::DriveInterface *const drive,
const int timeoutSecond);
/**
* Checks that the now loaded tape is writable.
*
* @param drive Object representing the drive hardware.
*/
void checkTapeIsWritable(drives::DriveInterface *const drive);
/**
* The function carrying out the actual labeling
* @param drive The drive object pointer
* @return
*/
void labelTheTape(castor::tape::tapeserver::drives::DriveInterface *drive);
void labelTheTape(drives::DriveInterface *const drive);
/**
* The object representing the rmcd daemon.
......@@ -158,13 +178,6 @@ namespace daemon {
*/
const bool m_force;
/**
* This is the function performing the actual labeling work (it calls the castor::tape::drive:LabelSession to do so)
*
* @param lc the log context
*/
void executeLabel();
}; // class LabelSession
} // namespace daemon
......
......@@ -24,18 +24,19 @@
#include "castor/exception/Exception.hpp"
#include "castor/legacymsg/NsProxy_TapeAlwaysEmpty.hpp"
#include "castor/legacymsg/RmcProxyTcpIp.hpp"
#include "castor/messages/Constants.hpp"
#include "castor/messages/ForkCleaner.pb.h"
#include "castor/messages/ForkDataTransfer.pb.h"
#include "castor/messages/ForkLabel.pb.h"
#include "castor/messages/ForkSucceeded.pb.h"
#include "castor/messages/ProcessCrashed.pb.h"
#include "castor/messages/ProcessExited.pb.h"
#include "castor/messages/ReturnValue.pb.h"
#include "castor/messages/StopProcessForker.pb.h"
#include "castor/messages/TapeserverProxyZmq.hpp"
#include "castor/tape/tapeserver/daemon/Constants.hpp"
#include "castor/tape/tapeserver/daemon/LabelSession.hpp"
#include "castor/tape/tapeserver/daemon/ProcessForker.hpp"
#include "castor/tape/tapeserver/daemon/ProcessForkerMsgType.hpp"
#include "castor/tape/tapeserver/daemon/ProcessForkerUtils.hpp"
#include "castor/tape/utils/DriveConfig.hpp"
#include "castor/messages/SmartZmqContext.hpp"
......@@ -50,35 +51,6 @@
#include <sys/types.h>
#include <sys/wait.h>
//------------------------------------------------------------------------------
// constructAnException
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
castor::tape::tapeserver::daemon::ProcessForker::
constructAnException(const std::string& message,bool continueMainEventLoop) {
castor::messages::Exception reply;
reply.set_code(SEINTERNAL);
reply.set_message(message);
MsgHandlerResult result;
result.continueMainEventLoop = continueMainEventLoop;
ProcessForkerUtils::serializePayload(result.reply, reply);
return result;
}
//------------------------------------------------------------------------------
// returnAnPidOfForkedSession
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
castor::tape::tapeserver::daemon::ProcessForker::
returnAnPidOfForkedSession(pid_t forkRc,bool continueMainEventLoop) {
// Create and return the result of handling the incomming request
castor::messages::ForkSucceeded reply;
reply.set_pid(forkRc);
MsgHandlerResult result;
result.continueMainEventLoop = continueMainEventLoop;
ProcessForkerUtils::serializePayload(result.reply, reply);
return result;
}
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
......@@ -231,7 +203,7 @@ bool castor::tape::tapeserver::daemon::ProcessForker::handleMsg() {
}
log::Param params[] = {
log::Param("type", ProcessForkerMsgType::toString(frame.type)),