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

All 3 tapeserverd sessions now inherit from tapeserver::daemon::Session

parent 0e229281
......@@ -32,6 +32,7 @@ add_library(castorTapeServerDaemon
RecallMemoryManager.cpp
RecallTaskInjector.cpp
RecallReportPacker.cpp
Session.cpp
TapeMessageHandler.cpp
TapeDaemonMain.cpp
TapeReadSingleThread.cpp
......
......@@ -42,7 +42,8 @@ castor::tape::tapeserver::daemon::CleanerSession::CleanerSession(
//------------------------------------------------------------------------------
// execute
//------------------------------------------------------------------------------
int castor::tape::tapeserver::daemon::CleanerSession::execute() {
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::CleanerSession::execute() {
castor::tape::SCSI::DeviceVector dv(m_sysWrapper);
castor::tape::SCSI::DeviceInfo driveInfo = dv.findBySymlink(m_driveConfig.devFilename);
......@@ -89,7 +90,7 @@ int castor::tape::tapeserver::daemon::CleanerSession::execute() {
castor::exception::Exception ex;
ex.getMessage() << "Cleaner session could not rewind the tape or read its label. Giving up now. Reason: " << ne.getMessage().str();
m_log(LOG_ERR, ex.getMessage().str());
return 1; //Tells caller to put the drive down
return MARK_DRIVE_AS_DOWN;
}
try {
// We implement the same policy as with the tape sessions:
......@@ -113,11 +114,11 @@ int castor::tape::tapeserver::daemon::CleanerSession::execute() {
castor::exception::Exception ex;
ex.getMessage() << "Cleaner session could not unmount the tape. Giving up now. Reason: " << ne.getMessage().str();
m_log(LOG_ERR, ex.getMessage().str());
return 1; //Tells caller to put the drive down
return MARK_DRIVE_AS_DOWN;
}
return 0; //Tells caller the drive can stay up
return MARK_DRIVE_AS_UP;
}
else { //the drive is empty here we don't care about the drive being ready or not
return 0; //Tells caller the drive can stay up
return MARK_DRIVE_AS_UP;
}
}
......@@ -26,6 +26,7 @@
#include "castor/legacymsg/RmcProxy.hpp"
#include "castor/log/LogContext.hpp"
#include "castor/log/Logger.hpp"
#include "castor/tape/tapeserver/daemon/Session.hpp"
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
#include "castor/tape/tapeserver/file/Structures.hpp"
#include "castor/tape/tapeserver/SCSI/Device.hpp"
......@@ -40,7 +41,7 @@ namespace daemon {
/**
* Class responsible for cleaning up a tape drive left in a (possibly) dirty state.
*/
class CleanerSession {
class CleanerSession : public Session {
public:
/**
......@@ -60,14 +61,27 @@ namespace daemon {
System::virtualWrapper &sysWrapper,
const std::string &vid);
/**
* Executes the cleaner session which unloads and unmounts any tape that is
* present in the drive.
*
* @return 0 in case of success (drive can stay UP) or 1 in case of failure
* (drive needs to be put down by the caller)
/**
* Execute the session and return the type of action to be performed
* immediately after the session has completed.
*
* The session is responsible for mounting a tape into the tape drive,
* working with that tape, unloading the tape from the drive and then
* dismounting the tape from the drive and storing it back in its home slot
* within the tape library.
*
* If this method throws an exception and the session is not a cleaner
* session then it assumed that the post session action is
* EndOfSessionAction::CLEAN_DRIVE.
*
* If this method throws an exception and the session is a cleaner
* session then it assumed that the post session action is
* EndOfSessionAction::MARK_DRIVE_AS_DOWN.
*
* @return Returns the type of action to be performed after the session has
* completed.
*/
int execute();
EndOfSessionAction execute();
private:
......
......@@ -79,8 +79,8 @@ castor::tape::tapeserver::daemon::DataTransferSession::DataTransferSession(
* 2b) Log The result
* Then branch to the right execution
*/
int castor::tape::tapeserver::daemon::DataTransferSession::execute()
{
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::DataTransferSession::execute() {
// 1) Prepare the logging environment
log::LogContext lc(m_log);
// Create a sticky thread name, which will be overridden by the other threads
......@@ -106,7 +106,7 @@ int castor::tape::tapeserver::daemon::DataTransferSession::execute()
log::LogContext::ScopedParam sp09(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
lc.log(LOG_ERR, "Notified client of end session with error");
return 0;
return MARK_DRIVE_AS_UP;
} catch (client::ClientProxy::UnexpectedResponse & unexp) {
std::stringstream fullError;
fullError << "Received unexpected response from client when requesting Volume"
......@@ -118,7 +118,7 @@ int castor::tape::tapeserver::daemon::DataTransferSession::execute()
log::LogContext::ScopedParam sp09(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
lc.log(LOG_ERR, "Notified client of end session with error");
return 0;
return MARK_DRIVE_AS_UP;
} catch (castor::exception::Exception & ex) {
std::stringstream fullError;
fullError << "When requesting Volume, "
......@@ -132,7 +132,7 @@ int castor::tape::tapeserver::daemon::DataTransferSession::execute()
log::LogContext::ScopedParam sp07(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
lc.log(LOG_ERR, "Could not contact client for Volume (client notification was attempted).");
return 0;
return MARK_DRIVE_AS_UP;
}
// 2b) ... and log.
// Make the TPVID parameter permanent.
......@@ -157,15 +157,16 @@ int castor::tape::tapeserver::daemon::DataTransferSession::execute()
return executeWrite(lc);
case tapegateway::DUMP:
executeDump(lc);
return 0;
return MARK_DRIVE_AS_UP;
default:
return 0;
return MARK_DRIVE_AS_UP;
}
}
//------------------------------------------------------------------------------
//DataTransferSession::executeRead
//------------------------------------------------------------------------------
int castor::tape::tapeserver::daemon::DataTransferSession::executeRead(log::LogContext & lc) {
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::DataTransferSession::executeRead(log::LogContext & lc) {
// We are ready to start the session. We need to create the whole machinery
// in order to get the task injector ready to check if we actually have a
// file to recall.
......@@ -173,7 +174,7 @@ int castor::tape::tapeserver::daemon::DataTransferSession::executeRead(log::LogC
// A NULL pointer is returned on failure
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> drive(findDrive(m_driveConfig,lc));
if(!drive.get()) return 0;
if(!drive.get()) return MARK_DRIVE_AS_UP;
// We can now start instantiating all the components of the data path
{
// Allocate all the elements of the memory management (in proper order
......@@ -248,21 +249,23 @@ int castor::tape::tapeserver::daemon::DataTransferSession::executeRead(log::LogC
log::LogContext::ScopedParam sp1(lc, log::Param("notificationError", ex.getMessageValue()));
lc.log(LOG_ERR, "Failed to notified client of end session with error");
}
//empty mount, hardware is OK, returns 0
return 0;
// Empty mount, hardware is OK
return MARK_DRIVE_AS_UP;
}
}
}
//------------------------------------------------------------------------------
//DataTransferSession::executeWrite
//------------------------------------------------------------------------------
int castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(log::LogContext & lc) {
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(
log::LogContext & lc) {
// We are ready to start the session. We need to create the whole machinery
// in order to get the task injector ready to check if we actually have a
// file to migrate.
// 1) Get hold of the drive error logs are done inside the findDrive function
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> drive(findDrive(m_driveConfig,lc));
if (!drive.get()) return 0;
if (!drive.get()) return MARK_DRIVE_AS_UP;
// Once we got hold of the drive, we can run the session
{
......@@ -307,7 +310,7 @@ int castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(log::Log
lc.log(LOG_ERR, "First file to write's fseq and number of files on "
"the tape according to the VMGR dont match");
//no mount at all, drive to be kept up = return 0
return 0;
return MARK_DRIVE_AS_UP;
}
// We have something to do: start the session by starting all the
// threads.
......@@ -345,8 +348,8 @@ int castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(log::Log
log::LogContext::ScopedParam sp1(lc, log::Param("notificationError", ex.getMessageValue()));
lc.log(LOG_ERR, "Failed to notified client of end session with error");
}
//empty mount, hardware safe, return 0
return 0;
// Empty mount, hardware safe
return MARK_DRIVE_AS_UP;
}
}
}
......
......@@ -23,15 +23,16 @@
#pragma once
#include "castor/legacymsg/RtcpJobRqstMsgBody.hpp"
#include "castor/messages/TapeserverProxy.hpp"
#include "castor/log/Logger.hpp"
#include "castor/legacymsg/RtcpJobRqstMsgBody.hpp"
#include "castor/log/LogContext.hpp"
#include "castor/log/Logger.hpp"
#include "castor/server/ProcessCap.hpp"
#include "castor/tape/tapeserver/system/Wrapper.hpp"
#include "castor/tape/utils/utils.hpp"
#include "castor/tape/tapeserver/client/ClientProxy.hpp"
#include "castor/tape/tapeserver/daemon/Session.hpp"
#include "castor/tape/tapeserver/daemon/TapeSingleThreadInterface.hpp"
#include "castor/tape/tapeserver/system/Wrapper.hpp"
#include "castor/tape/utils/utils.hpp"
namespace castor {
namespace legacymsg {
......@@ -47,7 +48,7 @@ namespace daemon {
* by the master process. It will drive a separate process. Only the sub
* process interface is not included here to allow testability.
*/
class DataTransferSession {
class DataTransferSession: public Session {
public:
/** Subclass holding all the contents from castor.conf file. The pre-
* extraction of the contents by the caller instead of direct getconfent
......@@ -107,8 +108,29 @@ namespace daemon {
castor::messages::TapeserverProxy & initialProcess,
castor::server::ProcessCap &capUtils,
const CastorConf & castorConf);
/** The only method. It will execute (like a task, that it is) */
int execute() ;
/**
* Execute the session and return the type of action to be performed
* immediately after the session has completed.
*
* The session is responsible for mounting a tape into the tape drive,
* working with that tape, unloading the tape from the drive and then
* dismounting the tape from the drive and storing it back in its home slot
* within the tape library.
*
* If this method throws an exception and the session is not a cleaner
* session then it assumed that the post session action is
* EndOfSessionAction::CLEAN_DRIVE.
*
* If this method throws an exception and the session is a cleaner
* session then it assumed that the post session action is
* EndOfSessionAction::MARK_DRIVE_AS_DOWN.
*
* @return Returns the type of action to be performed after the session has
* completed.
*/
EndOfSessionAction execute();
/** Temporary method used for debugging while building the session class */
std::string getVid() { return m_volInfo.vid; }
......@@ -141,9 +163,9 @@ namespace daemon {
const utils::DriveConfig &driveConfig,log::LogContext & lc);
/** sub-part of execute for the read sessions */
int executeRead(log::LogContext & lc);
EndOfSessionAction executeRead(log::LogContext & lc);
/** sub-part of execute for a write session */
int executeWrite(log::LogContext & lc);
EndOfSessionAction executeWrite(log::LogContext & lc);
/** sub-part of execute for a dump session */
void executeDump(log::LogContext & lc);
/** Reference to the RmcProxy, allowing the mounting of the tape by the
......
......@@ -61,7 +61,8 @@ castor::tape::tapeserver::daemon::LabelSession::LabelSession(
//------------------------------------------------------------------------------
// execute
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::execute() {
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::LabelSession::execute() {
std::ostringstream task;
task << "label tape " << m_request.vid << " for gid=" << m_request.gid <<
" uid=" << m_request.uid << " in drive " << m_request.drive;
......@@ -84,6 +85,8 @@ void castor::tape::tapeserver::daemon::LabelSession::execute() {
drive->unloadTape();
m_rmc.unmountTape(m_request.vid, m_driveConfig.librarySlot);
m_log(LOG_INFO, "The tape has been successfully unmounted after labeling", params);
return MARK_DRIVE_AS_UP;
}
//------------------------------------------------------------------------------
......
......@@ -32,8 +32,9 @@
#include "castor/tape/utils/utils.hpp"
#include "castor/tape/tapeserver/client/ClientProxy.hpp"
#include "castor/legacymsg/NsProxy.hpp"
#include "castor/tape/tapeserver/SCSI/Device.hpp"
#include "castor/tape/tapeserver/daemon/Session.hpp"
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
#include "castor/tape/tapeserver/SCSI/Device.hpp"
#include <memory>
......@@ -41,129 +42,147 @@ namespace castor {
namespace tape {
namespace tapeserver {
namespace daemon {
/**
* Class responsible for handling a tape label session.
*/
class LabelSession: public Session {
public:
/**
* Class responsible for handling a tape label session.
* Constructor
*
* @param rmc Proxy object representing the rmcd daemon.
* @param clientRequest The request to label a tape received from the label
* tape command.
* @param log Object representing the API to the CASTOR logging system.
* @param sysWrapper Object representing the operating system.
* @param driveConfig the configuration of the tape-drive to be used to
* label a tape.
* @param force The flag that, if set to true, allows labeling a non-blank
* tape.
*/
class LabelSession {
public:
/**
* Constructor
*
* @param rmc Proxy object representing the rmcd daemon.
* @param clientRequest The request to label a tape received from the label
* tape command.
* @param log Object representing the API to the CASTOR logging system.
* @param sysWrapper Object representing the operating system.
* @param driveConfig the configuration of the tape-drive to be used to
* label a tape.
* @param force The flag that, if set to true, allows labeling a non-blank
* tape.
*/
LabelSession(
legacymsg::RmcProxy &rmc,
const legacymsg::TapeLabelRqstMsgBody &clientRequest,
castor::log::Logger &log,
System::virtualWrapper &sysWrapper,
const utils::DriveConfig &driveConfig,
const bool force);
/**
* The only method. It will call executeLabel to do the actual job
*/
void execute() ;
LabelSession(
legacymsg::RmcProxy &rmc,
const legacymsg::TapeLabelRqstMsgBody &clientRequest,
castor::log::Logger &log,
System::virtualWrapper &sysWrapper,
const utils::DriveConfig &driveConfig,
const bool force);
/**
* Execute the session and return the type of action to be performed
* immediately after the session has completed.
*
* The session is responsible for mounting a tape into the tape drive, working
* with that tape, unloading the tape from the drive and then dismounting the
* tape from the drive and storing it back in its home slot within the tape
* library.
*
* If this method throws an exception and the session is not a cleaner
* session then it assumed that the post session action is
* EndOfSessionAction::CLEAN_DRIVE.
*
* If this method throws an exception and the session is a cleaner
* session then it assumed that the post session action is
* EndOfSessionAction::MARK_DRIVE_AS_DOWN.
*
* @return Returns the type of action to be performed after the session has
* completed.
*/
EndOfSessionAction execute();
private:
private:
/**
* The network timeout in seconds
*/
int m_timeout;
/**
* The network timeout in seconds
*/
const int m_timeout;
enum TapeNsStatus {
LABEL_SESSION_STEP_SUCCEEDED,
LABEL_SESSION_STEP_FAILED
};
enum TapeNsStatus {
LABEL_SESSION_STEP_SUCCEEDED,
LABEL_SESSION_STEP_FAILED
};
/**
* Performs some meta-data checks that need to be done before deciding to
* mount the tape for labeling.
*/
void performPreMountChecks();
/**
* 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 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();
/**
* Returns a Drive object representing the tape drive to be used to label
* a tape.
*
* @return The drive object.
*/
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> getDriveObject();
/**
* Returns a Drive object representing the tape drive to be used to label
* a tape.
*
* @return The drive object.
*/
std::auto_ptr<castor::tape::tapeserver::drives::DriveInterface> getDriveObject();
/**
* Mounts the tap eto be labelled.
*/
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);
/**
* Mounts the tape to be labelled.
*/
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(drives::DriveInterface *const drive);
/**
* 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(drives::DriveInterface *const drive);
/**
* The object representing the rmcd daemon.
*/
legacymsg::RmcProxy &m_rmc;
/**
* The object representing the rmcd daemon.
*/
legacymsg::RmcProxy &m_rmc;
/**
* The label request message body
*/
legacymsg::TapeLabelRqstMsgBody m_request;
/**
* The logging object
*/
castor::log::Logger & m_log;
/**
* The system wrapper used to find the device and instantiate the drive object
*/
System::virtualWrapper & m_sysWrapper;
/**
* The configuration of the tape drive to be used to label a tape.
*/
const utils::DriveConfig m_driveConfig;
/**
* The label request message body
*/
legacymsg::TapeLabelRqstMsgBody m_request;
/**
* The logging object
*/
castor::log::Logger & m_log;
/**
* The flag that, if set to true, allows labeling a non-blank tape
*/
const bool m_force;
/**
* The system wrapper used to find the device and instantiate the drive object
*/
System::virtualWrapper &m_sysWrapper;
/**
* The configuration of the tape drive to be used to label a tape.
*/
const utils::DriveConfig m_driveConfig;
/**
* The flag that, if set to true, allows labeling a non-blank tape
*/
const bool m_force;
}; // class LabelSession
......
......@@ -320,7 +320,7 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
"Caught an unknown exception")};
m_log(LOG_ERR, "Failed to run cleaner session", params);
}
exit(1);
exit(Session::MARK_DRIVE_AS_DOWN);
}
}
......@@ -374,7 +374,7 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
"Caught an unknown exception")};
m_log(LOG_ERR, "Failed to run data-transfer session", params);
}
exit(1);
exit(Session::CLEAN_DRIVE);
}
}
......@@ -429,7 +429,7 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
"Caught an unknown exception")};
m_log(LOG_ERR, "Failed to run label session", params);
}
exit(1);
exit(Session::CLEAN_DRIVE);
}
}
......@@ -454,7 +454,8 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
//------------------------------------------------------------------------------
// runCleanerSession
//------------------------------------------------------------------------------
int castor::tape::tapeserver::daemon::ProcessForker::runCleanerSession(
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
castor::tape::tapeserver::daemon::ProcessForker::runCleanerSession(
const messages::ForkCleaner &rqst) {
try {
const utils::DriveConfig driveConfig = getDriveConfig(rqst);
......@@ -475,7 +476,6 @@ int castor::tape::tapeserver::daemon::ProcessForker::runCleanerSession(
driveConfig,
sWrapper,
rqst.vid());
// execute() returns 0 if drive should be put up or 1 if it should be put down