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

ProbeSession is now called when a drive is transitioned from DOWN to UP (idle)

parent 4ab1576b
......@@ -35,31 +35,30 @@ enum MsgType {
/* 0 */ MSG_TYPE_NONE,
/* 1 */ MSG_TYPE_EXCEPTION,
/* 2 */ MSG_TYPE_FORKCLEANER,
/* 3 */ MSG_TYPE_FORKPROBE,
/* 4 */ MSG_TYPE_FORKDATATRANSFER,
/* 5 */ MSG_TYPE_FORKLABEL,
/* 6 */ MSG_TYPE_FORKSUCCEEDED,
/* 7 */ MSG_TYPE_HEARTBEAT,
/* 8 */ MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY,
/* 9 */ MSG_TYPE_MIGRATIONJOBFROMWRITETP,
/* 10 */ MSG_TYPE_NBFILESONTAPE,
/* 11 */ MSG_TYPE_PROCESSCRASHED,
/* 12 */ MSG_TYPE_PROCESSEXITED,
/* 13 */ MSG_TYPE_RECALLJOBFROMREADTP,
/* 14 */ MSG_TYPE_RECALLJOBFROMTAPEGATEWAY,
/* 15 */ MSG_TYPE_RETURNVALUE,
/* 16 */ MSG_TYPE_STOPPROCESSFORKER,
/* 17 */ MSG_TYPE_TAPEMOUNTEDFORMIGRATION,
/* 18 */ MSG_TYPE_TAPEMOUNTEDFORRECALL,
/* 19 */ MSG_TYPE_TAPEUNMOUNTSTARTED,
/* 20 */ MSG_TYPE_TAPEUNMOUNTED,
/* 21 */ MSG_TYPE_LABELERROR,
/* 22 */ MSG_TYPE_ACSMOUNTTAPEREADONLY,
/* 23 */ MSG_TYPE_ACSMOUNTTAPEREADWRITE,
/* 24 */ MSG_TYPE_ACSDISMOUNTTAPE,
/* 25 */ MSG_TYPE_ACSFORCEDISMOUNTTAPE,
/* 26 */ MSG_TYPE_ADDLOGPARAMS,
/* 27 */ MSG_TYPE_DELETELOGPARAMS
/* 3 */ MSG_TYPE_FORKDATATRANSFER,
/* 4 */ MSG_TYPE_FORKLABEL,
/* 5 */ MSG_TYPE_FORKSUCCEEDED,
/* 6 */ MSG_TYPE_HEARTBEAT,
/* 7 */ MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY,
/* 8 */ MSG_TYPE_MIGRATIONJOBFROMWRITETP,
/* 9 */ MSG_TYPE_NBFILESONTAPE,
/* 10 */ MSG_TYPE_PROCESSCRASHED,
/* 11 */ MSG_TYPE_PROCESSEXITED,
/* 12 */ MSG_TYPE_RECALLJOBFROMREADTP,
/* 13 */ MSG_TYPE_RECALLJOBFROMTAPEGATEWAY,
/* 14 */ MSG_TYPE_RETURNVALUE,
/* 15 */ MSG_TYPE_STOPPROCESSFORKER,
/* 16 */ MSG_TYPE_TAPEMOUNTEDFORMIGRATION,
/* 17 */ MSG_TYPE_TAPEMOUNTEDFORRECALL,
/* 18 */ MSG_TYPE_TAPEUNMOUNTSTARTED,
/* 19 */ MSG_TYPE_TAPEUNMOUNTED,
/* 20 */ MSG_TYPE_LABELERROR,
/* 21 */ MSG_TYPE_ACSMOUNTTAPEREADONLY,
/* 22 */ MSG_TYPE_ACSMOUNTTAPEREADWRITE,
/* 23 */ MSG_TYPE_ACSDISMOUNTTAPE,
/* 24 */ MSG_TYPE_ACSFORCEDISMOUNTTAPE,
/* 25 */ MSG_TYPE_ADDLOGPARAMS,
/* 26 */ MSG_TYPE_DELETELOGPARAMS
};
enum ProtocolVersion {
......
// This file is part of the Castor project.
// See http://castor.web.cern.ch/castor
//
// Copyright (C) 2003 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
//
//
// @author Castor Dev team, castor-dev@cern.ch
package castor.messages;
message ForkProbe {
// Description of the tape drive
required string unitname = 1;
required string dgn = 2;
required string devfilename = 3;
required string libraryslot = 4;
}
\ No newline at end of file
......@@ -24,6 +24,7 @@
#include "castor/exception/Exception.hpp"
#include "castor/tape/tapeserver/daemon/CatalogueDrive.hpp"
#include "castor/tape/tapeserver/daemon/Constants.hpp"
#include "castor/tape/tapeserver/daemon/ProbeSession.hpp"
#include "castor/utils/utils.hpp"
#include "h/Ctape_constants.h"
#include "h/rmc_constants.h"
......@@ -357,22 +358,17 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::
// configureUp
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::configureUp() {
bool vdqmNeedsUpdate = false;
switch(m_state) {
case DRIVE_STATE_UP:
// It is safe to refresh the status of the vdqm to up, so let's to it.
vdqmNeedsUpdate = true;
break;
case DRIVE_STATE_RUNNING:
// We are in RUNNING in the VDQM: leave it like that.
// This state transition is idempotent
break;
case DRIVE_STATE_DOWN:
changeState(DRIVE_STATE_UP);
vdqmNeedsUpdate = true;
transitionFromDownToUp();
break;
case DRIVE_STATE_WAITDOWN:
// We are in RUNNING in the VDQM: leave it like that.
// We just cancel the WAIT DOWN internally.
// Leave state in vdqm as RUNNING, just update internally state to reflect
// the future intention of transitioning to DOWN
changeState(DRIVE_STATE_RUNNING);
break;
default:
......@@ -384,8 +380,32 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::configureUp() {
throw ex;
}
}
if (vdqmNeedsUpdate)
m_vdqm.setDriveUp(m_hostName, m_config.getUnitName(), m_config.getDgn());
}
//-----------------------------------------------------------------------------
// transitionFromDownToUp
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::
transitionFromDownToUp() {
checkDriveIsEmpty();
changeState(DRIVE_STATE_UP);
m_vdqm.setDriveUp(m_hostName, m_config.getUnitName(), m_config.getDgn());
}
//-----------------------------------------------------------------------------
// checkDriveIsEmpty
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::checkDriveIsEmpty() {
castor::tape::System::realWrapper sWrapper;
ProbeSession probeSession(m_log, m_config, sWrapper);
const int probeSessionExitCode = probeSession.execute();
if(Session::MARK_DRIVE_AS_UP != probeSessionExitCode) {
castor::exception::Exception ex;
ex.getMessage() << "Drive " << m_config.getUnitName() << " is not empty";
throw ex;
}
}
//-----------------------------------------------------------------------------
......
......@@ -322,6 +322,16 @@ private:
*/
CatalogueDrive& operator=(const CatalogueDrive&);
/**
* Transition from DRIVE_STATE_DOWN to DRIVE_STATE_UP.
*/
void transitionFromDownToUp();
/**
* Throws an exception if the physical tape drive is not empty.
*/
void checkDriveIsEmpty();
/**
* Timeout in seconds to be used when performing network I/O.
*/
......
......@@ -27,11 +27,9 @@
// constructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::ProbeSession::ProbeSession(
server::ProcessCap &capUtils,
castor::log::Logger &log,
const DriveConfig &driveConfig,
System::virtualWrapper &sysWrapper):
m_capUtils(capUtils),
m_log(log),
m_driveConfig(driveConfig),
m_sysWrapper(sysWrapper) {
......@@ -70,30 +68,15 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction
std::list<log::Param> params;
params.push_back(log::Param("unitName", m_driveConfig.getUnitName()));
setProcessCapabilities("cap_sys_rawio+ep");
std::auto_ptr<drive::DriveInterface> drivePtr = createDrive();
drive::DriveInterface &drive = *drivePtr.get();
if(drive.hasTapeInPlace()) {
m_log(LOG_INFO, "Probe found tape drive with a tape inside", params);
return MARK_DRIVE_AS_DOWN;
}
return MARK_DRIVE_AS_UP;
}
//------------------------------------------------------------------------------
// setProcessCapabilities
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::ProbeSession::setProcessCapabilities(
const std::string &capabilities) {
m_capUtils.setProcText(capabilities);
{
log::Param params[] = {
log::Param("capabilities", m_capUtils.getProcText())};
m_log(LOG_INFO, "Probe set process capabilities for using tape",
params);
} else {
m_log(LOG_INFO, "Probe found tape drive is empty", params);
return MARK_DRIVE_AS_UP;
}
}
......
......@@ -26,7 +26,6 @@
#include "castor/log/LogContext.hpp"
#include "castor/log/Logger.hpp"
#include "castor/mediachanger/MediaChangerFacade.hpp"
#include "castor/server/ProcessCap.hpp"
#include "castor/tape/tapeserver/daemon/DriveConfig.hpp"
#include "castor/tape/tapeserver/daemon/Session.hpp"
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
......@@ -40,21 +39,22 @@ namespace tape {
namespace tapeserver {
namespace daemon {
/**
* Class responsible for probing a tape drive.
* Class responsible for probing a tape drive to see if it empty and
* accessible. If the drive satisfies both of these criteria then the probe
* will recommend that the state of the drive should be marked as UP, else
* it will recommend DOWN.
*/
class ProbeSession : public Session {
public:
/**
* Constructor
*
* @param capUtils Object providing support for UNIX capabilities.
* @param log Object representing the API to the CASTOR logging system.
* @param driveConfig Configuration of the tape drive to be probed.
* @param sysWrapper Object representing the operating system.
*/
ProbeSession(
server::ProcessCap &capUtils,
castor::log::Logger &log,
const DriveConfig &driveConfig,
System::virtualWrapper &sysWrapper);
......@@ -70,15 +70,10 @@ namespace daemon {
private:
/**
* Object providing support for UNIX capabilities.
*/
server::ProcessCap &m_capUtils;
/**
* The logging object
*/
castor::log::Logger & m_log;
castor::log::Logger &m_log;
/**
* The configuration of the tape drive to be probed.
......@@ -88,7 +83,7 @@ namespace daemon {
/**
* The system wrapper used to find the device and instantiate the drive object
*/
System::virtualWrapper & m_sysWrapper;
System::virtualWrapper &m_sysWrapper;
/**
* Execute the session and return the type of action to be performed
......@@ -99,13 +94,6 @@ namespace daemon {
*/
EndOfSessionAction exceptionThrowingExecute();
/**
* Sets the capabilities of the process and logs the result.
*
* @param capabilities The string representation of the capabilities.
*/
void setProcessCapabilities(const std::string &capabilities);
/**
* Creates and returns the object that represents the tape drive to be
* probed.
......
......@@ -258,8 +258,6 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
switch(frame.type) {
case messages::MSG_TYPE_FORKCLEANER:
return handleForkCleanerMsg(frame);
case messages::MSG_TYPE_FORKPROBE:
return handleForkProbeMsg(frame);
case messages::MSG_TYPE_FORKDATATRANSFER:
return handleForkDataTransferMsg(frame);
case messages::MSG_TYPE_FORKLABEL:
......@@ -335,60 +333,6 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
}
}
//------------------------------------------------------------------------------
// handleForkProbeMsg
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
castor::tape::tapeserver::daemon::ProcessForker::handleForkProbeMsg(
const ProcessForkerFrame &frame) {
// Parse the incoming request
messages::ForkProbe rqst;
ProcessForkerUtils::parsePayload(frame, rqst);
// Log the contents of the incomming request
std::list<log::Param> params;
params.push_back(log::Param("unitName", rqst.unitname()));
m_log(LOG_INFO, "ProcessForker handling ForkProbe message", params);
// Fork a label session
const pid_t forkRc = fork();
// If fork failed
if(0 > forkRc) {
return createExceptionResult(SEINTERNAL,
"Failed to fork probe session for tape drive", true);
// Else if this is the parent process
} else if(0 < forkRc) {
log::Param params[] = {log::Param("pid", forkRc)};
m_log(LOG_INFO, "ProcessForker forked probe session", params);
return createForkSucceededResult(forkRc, true);
// Else this is the child process
} else {
closeCmdReceiverSocket();
castor::utils::setProcessNameAndCmdLine(m_argv0, "probe");
try {
exit(runProbeSession(rqst));
} catch(castor::exception::Exception &ne) {
log::Param params[] = {log::Param("message", ne.getMessage().str())};
m_log(LOG_ERR, "Probe session failed", params);
} catch(std::exception &ne) {
log::Param params[] = {log::Param("message", ne.what())};
m_log(LOG_ERR, "Probe session failed", params);
} catch(...) {
log::Param params[] = {log::Param("message",
"Caught an unknown exception")};
m_log(LOG_ERR, "Probe session failed", params);
}
exit(Session::MARK_DRIVE_AS_DOWN);
}
}
//------------------------------------------------------------------------------
// handleForkDataTransferMsg
//------------------------------------------------------------------------------
......@@ -572,46 +516,6 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction
}
}
//------------------------------------------------------------------------------
// runProbeSession
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::ProcessForker::runProbeSession(
const messages::ForkProbe &rqst) {
try {
server::ProcessCap capUtils;
const DriveConfig driveConfig = getDriveConfig(rqst);
std::list<log::Param> params;
params.push_back(log::Param("unitName", driveConfig.getUnitName()));
m_log(LOG_INFO, "Probe-session child-process started", params);
const int sizeOfIOThreadPoolForZMQ = 1;
messages::SmartZmqContext
zmqContext(instantiateZmqContext(sizeOfIOThreadPoolForZMQ));
messages::AcsProxyZmq acs(acs::ACS_PORT, zmqContext.get());
castor::tape::System::realWrapper sWrapper;
ProbeSession probeSession(
capUtils,
m_log,
driveConfig,
sWrapper);
return probeSession.execute();
} catch(castor::exception::Exception &ex) {
throw ex;
} catch(std::exception &se) {
castor::exception::Exception ex;
ex.getMessage() << se.what();
throw ex;
} catch(...) {
castor::exception::Exception ex;
ex.getMessage() << "Caught an unknown exception";
throw ex;
}
}
//------------------------------------------------------------------------------
// runDataTransferSession
//------------------------------------------------------------------------------
......
......@@ -28,7 +28,6 @@
#include "castor/messages/ForkCleaner.pb.h"
#include "castor/messages/ForkDataTransfer.pb.h"
#include "castor/messages/ForkLabel.pb.h"
#include "castor/messages/ForkProbe.pb.h"
#include "castor/tape/tapeserver/daemon/DataTransferSession.hpp"
#include "castor/tape/tapeserver/daemon/ProcessForkerFrame.hpp"
#include "castor/tape/tapeserver/daemon/TapeDaemonConfig.hpp"
......@@ -221,14 +220,6 @@ private:
*/
MsgHandlerResult handleForkCleanerMsg(const ProcessForkerFrame &frame);
/**
* Handles a ForkProbe message.
*
* @param frame The frame containing the message.
* @return The result of the message handler.
*/
MsgHandlerResult handleForkProbeMsg(const ProcessForkerFrame &frame);
/**
* Runs a cleaner session. This method is to be called within the child
* process responsible for running the cleaner session.
......@@ -238,15 +229,6 @@ private:
*/
Session::EndOfSessionAction runCleanerSession(const messages::ForkCleaner &rqst);
/**
* Runs a probe session. This method is to be called within the child
* process responsible for running the probe session.
*
* @param rqst The ForkProbe message.
* @return The value to be used when exiting the child process.
*/
Session::EndOfSessionAction runProbeSession(const messages::ForkProbe &rqst);
/**
* Runs a data-transfer session. This method is to be called within the
* child process responsible for running the data-transfer session.
......
......@@ -91,14 +91,6 @@ public:
const std::string &vid, const bool waitMediaInDrive,
const uint32_t waitMediaInDriveTimeout) = 0;
/**
* Forks a probe session for the specified tape drive.
*
* @param driveConfig The configuration of the tape drive.
* @return The process identifier of the newly forked session.
*/
virtual pid_t forkProbe(const DriveConfig &driveConfig) = 0;
}; // class ProcessForkerProxy
} // namespace daemon
......
......@@ -60,12 +60,3 @@ pid_t castor::tape::tapeserver::daemon::ProcessForkerProxyDummy::
// This is a dummy method and so intentionally does nothing
return 0;
}
//------------------------------------------------------------------------------
// forkProbe
//------------------------------------------------------------------------------
pid_t castor::tape::tapeserver::daemon::ProcessForkerProxyDummy::
forkProbe(const DriveConfig &driveConfig) {
// This is a dummy method and so intentionally does nothing
return 0;
}
......@@ -74,7 +74,6 @@ public:
* @param labelJob The job received from the tape-labeling command-line tool.
* @return The process identifier of the newly forked session which will
* always be 0 because this is a dummy method.
*/
pid_t forkLabel(const DriveConfig &driveConfig,
const legacymsg::TapeLabelRqstMsgBody &labelJob);
......@@ -97,15 +96,7 @@ public:
const std::string &vid, const bool waitMediaInDrive,
const uint32_t waitMediaInDriveTimeout);
/**
* Forks a probe session for the specified tape drive.
*
* @param driveConfig The configuration of the tape drive.
* @return The process identifier of the newly forked session.
*/
virtual pid_t forkProbe(const DriveConfig &driveConfig);
}; // class ProcessForkerProxySocket
}; // class ProcessForkerProxyDummy
} // namespace daemon
} // namespace tapeserver
......
......@@ -226,38 +226,3 @@ castor::messages::ForkCleaner castor::tape::tapeserver::daemon::
return msg;
}
//------------------------------------------------------------------------------
// forkProbe
//------------------------------------------------------------------------------
pid_t castor::tape::tapeserver::daemon::ProcessForkerProxySocket::
forkProbe(const DriveConfig &driveConfig) {
// Request the process forker to fork a probe session
const messages::ForkProbe rqst = createForkProbeMsg(driveConfig);
ProcessForkerUtils::writeFrame(m_socketFd, rqst);
// Read back the reply
const int timeout = 10; // Timeout in seconds
messages::ForkSucceeded reply;
ProcessForkerUtils::readReplyOrEx(m_socketFd, timeout, reply);
log::Param params[] = {log::Param("pid", reply.pid())};
m_log(LOG_INFO,
"Got process ID of the probe session from the ProcessForker", params);
return reply.pid();
}
//------------------------------------------------------------------------------
// createForkProbeMsg
//------------------------------------------------------------------------------
castor::messages::ForkProbe castor::tape::tapeserver::daemon::
ProcessForkerProxySocket::createForkProbeMsg(
const DriveConfig &driveConfig) {
messages::ForkProbe msg;
// Description of the tape drive
fillMsgWithDriveConfig(msg, driveConfig);
return msg;
}
......@@ -110,14 +110,6 @@ public:
*/
pid_t forkCleaner(const DriveConfig &driveConfig,
const std::string &vid, const bool waitMediaInDrive, const uint32_t waitMediaInDriveTimeout);
/**
* Forks a probe session for the specified tape drive.
*
* @param driveConfig The configuration of the tape drive.
* @return The process identifier of the newly forked session.
*/
virtual pid_t forkProbe(const DriveConfig &driveConfig);
private:
......@@ -216,16 +208,6 @@ private:
const bool waitMediaInDrive,
const uint32_t waitMediaInDriveTimeout);
/**
* Creates a ForkProbe message from the specified tape-drive
* configuration and probe job.
*
* @param driveConfig The configuration of the tape drive.
* @return The message.
*/
messages::ForkProbe createForkProbeMsg(
const DriveConfig &driveConfig);
}; // class ProcessForkerProxySocket
} // namespace daemon
......
......@@ -44,20 +44,6 @@ void castor::tape::tapeserver::daemon::ProcessForkerUtils::serializePayload(
}
}
//------------------------------------------------------------------------------
// serializePayload
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::ProcessForkerUtils::serializePayload(
ProcessForkerFrame &frame, const messages::ForkProbe &msg) {
frame.type = messages::MSG_TYPE_FORKPROBE;
if(!msg.SerializeToString(&frame.payload)) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to serialize ForkProbe payload"
": SerializeToString() returned false";
throw ex;
}
}
//------------------------------------------------------------------------------
// serializePayload
//------------------------------------------------------------------------------
......@@ -178,14 +164,6 @@ void castor::tape::tapeserver::daemon::ProcessForkerUtils::writeFrame(
writeFrame(fd, messages::MSG_TYPE_FORKCLEANER, msg, log);
}
//------------------------------------------------------------------------------
// writeFrame
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::ProcessForkerUtils::writeFrame(
const int fd, const messages::ForkProbe &msg, log::Logger *const log) {