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

DebugMountSessionForVdqmProtocol now mounts and unmounts a SCSI tape

The old rmd daemon is now used to mount and unmount tapes in SCSI
libraries.
parent 63400e9b
......@@ -32,6 +32,7 @@ set (TAPE_LEGACYMSG_LIB_SRC_FILES
RmcAcsMntMsgBody.cpp
RmcMarshal.cpp
RmcMountMsgBody.cpp
RmcUnmountMsgBody.cpp
RtcpDumpTapeRqstMsgBody.cpp
RtcpErrorAppendix.cpp
RtcpFileRqst.cpp
......
......@@ -42,7 +42,7 @@ struct RmcAcsMntMsgBody {
uint32_t lsm;
uint32_t panel;
uint32_t transport;
char vid[CA_MAXVIDLEN];
char vid[CA_MAXVIDLEN + 1];
/**
* Constructor.
......
......@@ -120,8 +120,11 @@ size_t castor::tape::legacymsg::marshal(char *const dst, const size_t dstLen, co
throw ex;
}
// Calculate the length of the message body
const uint32_t len =
// Calculate the total length of the message (header + body)
const uint32_t totalLen =
sizeof(uint32_t) + // magic
sizeof(uint32_t) + // reqType
sizeof(uint32_t) + // len
sizeof(src.uid) +
sizeof(src.gid) +
strlen(src.unusedLoader) + 1 +
......@@ -129,10 +132,6 @@ size_t castor::tape::legacymsg::marshal(char *const dst, const size_t dstLen, co
sizeof(src.side) +
sizeof(src.drvOrd);
// Calculate the total length of the message (header + body)
// Message header = magic + reqType + len = 3 * sizeof(uint32_t)
const size_t totalLen = 3 * sizeof(uint32_t) + len;
// Check that the message buffer is big enough
if(totalLen > dstLen) {
castor::exception::Internal ex;
......@@ -145,7 +144,7 @@ size_t castor::tape::legacymsg::marshal(char *const dst, const size_t dstLen, co
char *p = dst;
io::marshalUint32(RMC_MAGIC , p); // Magic number
io::marshalUint32(RMC_MOUNT, p); // Request type
io::marshalUint32(len, p); // Length of message body
io::marshalUint32(totalLen, p); // Length of message header + body
// Marshall message body
io::marshalUint32(src.uid, p);
......@@ -181,3 +180,76 @@ void castor::tape::legacymsg::unmarshal(const char * &src, size_t &srcLen, RmcMo
io::unmarshalUint16(src, srcLen, dst.side);
io::unmarshalUint16(src, srcLen, dst.drvOrd);
}
//-----------------------------------------------------------------------------
// marshal
//-----------------------------------------------------------------------------
size_t castor::tape::legacymsg::marshal(char *const dst, const size_t dstLen, const RmcUnmountMsgBody &src) throw(castor::exception::Exception) {
if(dst == NULL) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to marshal RmcUnmountMsgBody"
": Pointer to destination buffer is NULL";
throw ex;
}
// Calculate the total length of the message (header + body)
const uint32_t totalLen =
sizeof(uint32_t) + // magic
sizeof(uint32_t) + // reqType
sizeof(uint32_t) + // len
sizeof(src.uid) +
sizeof(src.gid) +
strlen(src.unusedLoader) + 1 +
strlen(src.vid) + 1 +
sizeof(src.drvOrd) +
sizeof(src.force);
// Check that the message buffer is big enough
if(totalLen > dstLen) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to marshal RmcUnmountMsgBody"
": Buffer too small: required=" << totalLen << " actual=" << dstLen;
throw ex;
}
// Marshall message header
char *p = dst;
io::marshalUint32(RMC_MAGIC , p); // Magic number
io::marshalUint32(RMC_UNMOUNT, p); // Request type
io::marshalUint32(totalLen, p); // Length of message header + body
// Marshall message body
io::marshalUint32(src.uid, p);
io::marshalUint32(src.gid, p);
io::marshalString(src.unusedLoader, p);
io::marshalString(src.vid, p);
io::marshalUint16(src.drvOrd, p);
io::marshalUint16(src.force, p);
// Calculate the number of bytes actually marshalled
const size_t nbBytesMarshalled = p - dst;
// Check that the number of bytes marshalled was what was expected
if(totalLen != nbBytesMarshalled) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to marshal RmcUnmountMsgBody"
": Mismatch between expected total length and actual"
": expected=" << totalLen << "actual=" << nbBytesMarshalled;
throw ex;
}
return totalLen;
}
//-----------------------------------------------------------------------------
// unmarshal
//-----------------------------------------------------------------------------
void castor::tape::legacymsg::unmarshal(const char * &src, size_t &srcLen, RmcUnmountMsgBody &dst) throw(castor::exception::Exception) {
io::unmarshalUint32(src, srcLen, dst.uid);
io::unmarshalUint32(src, srcLen, dst.gid);
io::unmarshalString(src, srcLen, dst.unusedLoader);
io::unmarshalString(src, srcLen, dst.vid);
io::unmarshalUint16(src, srcLen, dst.drvOrd);
io::unmarshalUint16(src, srcLen, dst.force);
}
......@@ -29,6 +29,7 @@
#include "castor/tape/legacymsg/MessageHeader.hpp"
#include "castor/tape/legacymsg/RmcAcsMntMsgBody.hpp"
#include "castor/tape/legacymsg/RmcMountMsgBody.hpp"
#include "castor/tape/legacymsg/RmcUnmountMsgBody.hpp"
namespace castor {
namespace tape {
......@@ -110,6 +111,44 @@ template<int n> size_t marshal(char (&dst)[n], const RmcMountMsgBody &src) throw
*/
void unmarshal(const char * &src, size_t &srcLen, RmcMountMsgBody &dst) throw(castor::exception::Exception);
/**
* Marshals the specified source message body structure and its implicit
* header into the specified destination buffer.
*
* @param dst The destination message buffer.
* @param dstLen The length of the destination buffer.
* @param src The source structure.
* @return The total length of the message (header + body).
*/
size_t marshal(char *const dst, const size_t dstLen, const RmcUnmountMsgBody &src) throw(castor::exception::Exception);
/**
* Marshals the specified source message body structure and its implicit
* header into the specified destination buffer.
*
* @param dst The destination message buffer.
* @param src The source structure.
* @return The total length of the message (header + body).
*/
template<int n> size_t marshal(char (&dst)[n], const RmcUnmountMsgBody &src) throw(castor::exception::Exception) {
return marshal(dst, n, src);
}
/**
* Unmarshals a message body with the specified destination structure type
* from the specified source buffer.
*
* @param src In/out parameter, before invocation points to the source
* buffer where the message body should be unmarshalled from and on return
* points to the byte in the source buffer immediately after the
* unmarshalled message body.
* @param srcLen In/out parameter, before invocation is the length of the
* source buffer from where the message body should be unmarshalled and on
* return is the number of bytes remaining in the source buffer.
* @param dst The destination message body structure.
*/
void unmarshal(const char * &src, size_t &srcLen, RmcUnmountMsgBody &dst) throw(castor::exception::Exception);
} // namespace legacymsg
} // namespace tape
} // namespace castor
......
......@@ -132,7 +132,7 @@ TEST_F(castor_server_RmcMarshalTest, marshalRmcMountMsgBody) {
ASSERT_EQ((uint32_t)RMC_MAGIC, dstHeader.magic);
ASSERT_EQ((uint32_t)RMC_MOUNT, dstHeader.reqType);
ASSERT_EQ((uint32_t)17, dstHeader.lenOrStatus);
ASSERT_EQ((uint32_t)29, dstHeader.lenOrStatus);
}
// Unmarshall message body
......
......@@ -39,7 +39,7 @@ struct RmcMountMsgBody {
uint32_t uid;
uint32_t gid;
char unusedLoader[1]; // Should always be set to the emtpy string
char vid[CA_MAXVIDLEN];
char vid[CA_MAXVIDLEN + 1];
uint16_t side;
uint16_t drvOrd;
......
/******************************************************************************
* castor/tape/legacymsg/RmcUnmountMsgBody.cpp
*
* 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 Steven.Murray@cern.ch
*****************************************************************************/
#include "castor/tape/legacymsg/RmcUnmountMsgBody.hpp"
#include <string.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::tape::legacymsg::RmcUnmountMsgBody::RmcUnmountMsgBody() throw():
uid(0),
gid(0),
drvOrd(0),
force(0) {
memset(unusedLoader, '\0', sizeof(unusedLoader));
memset(vid, '\0', sizeof(vid));
}
/******************************************************************************
* castor/tape/legacymsg/RmcUnmountMsgBody.hpp
*
* 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 Steven.Murray@cern.ch
*****************************************************************************/
#pragma once
#include "h/Castor_limits.h"
#include <stdint.h>
namespace castor {
namespace tape {
namespace legacymsg {
/**
* The body of an RMC_UNMOUNT message.
*/
struct RmcUnmountMsgBody {
uint32_t uid;
uint32_t gid;
char unusedLoader[1]; // Should always be set to the emtpy string
char vid[CA_MAXVIDLEN + 1];
uint16_t drvOrd;
uint16_t force;
/**
* Constructor.
*
* Sets all integer member-variables to 0 and all string member-variables to
* the empty string.
*/
RmcUnmountMsgBody() throw();
}; // struct RmcUnmountMsgBody
} // namespace legacymsg
} // namespace tape
} // namespace castor
......@@ -75,8 +75,16 @@ void castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::execute
std::auto_ptr<castor::tape::tapegateway::Volume> volume(getVolume(clientMsgSeqNb++));
if(NULL != volume.get()) {
log::Param params[] = {
log::Param("TPVID", volume->vid()),
log::Param("density", volume->density()),
log::Param("label", volume->label()),
log::Param("mode", volume->mode())};
m_log(LOG_INFO, "Got VID from client", params);
mountTape(volume->vid());
transferFiles(*(volume.get()), clientMsgSeqNb);
} else {
m_log(LOG_WARNING, "Could not get VID from client");
}
const bool forceUnmount = true;
......@@ -296,8 +304,8 @@ void castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::throwEn
// mountTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::mountTape(const std::string &vid) throw (castor::exception::Exception) {
// Emulate tape mount by sleeping
::sleep(1);
const std::string drive = getPositionInLibrary(m_job.driveUnit);
m_rmc.mountTape(vid, drive);
log::Param params[] = {
log::Param("unitName", m_job.driveUnit),
......@@ -306,6 +314,22 @@ void castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::mountTa
m_vdqm.tapeMounted(m_hostName, m_job.driveUnit, m_job.dgn, vid, m_sessionPid);
}
//------------------------------------------------------------------------------
// getPositionInLibrary
//------------------------------------------------------------------------------
std::string castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::getPositionInLibrary(const std::string &unitName)
throw (castor::exception::Exception) {
for(utils::TpconfigLines::const_iterator itor = m_tpConfig.begin(); itor != m_tpConfig.end(); itor++) {
if(unitName == itor->unitName) {
return itor->positionInLibrary;
}
}
castor::exception::Internal ex;
ex.getMessage() << "Failed to find library position of drive " << unitName;
throw ex;
}
//------------------------------------------------------------------------------
// transferFiles
//------------------------------------------------------------------------------
......@@ -417,8 +441,8 @@ void castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::release
// unmountTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::DebugMountSessionForVdqmProtocol::unmountTape(const std::string &vid) throw (castor::exception::Exception) {
// Emulate tape unmount by sleeping
::sleep(1);
const std::string drive = getPositionInLibrary(m_job.driveUnit);
m_rmc.unmountTape(vid, drive);
log::Param params[] = {
log::Param("unitName", m_job.driveUnit),
......
......@@ -155,6 +155,12 @@ private:
*/
void mountTape(const std::string &vid) throw (castor::exception::Exception);
/**
* Searches the parsed contents of /etc/castor/TPCONFIG for the position of
* the sepecified drive within its library.
*/
std::string getPositionInLibrary(const std::string &unitName) throw (castor::exception::Exception);
/**
* Transfer files. This means either recalling files from tape to disk,
* migrating files from disk to tape or dumping tape files.
......
......@@ -22,6 +22,7 @@
#include "castor/exception/Internal.hpp"
#include "castor/io/io.hpp"
#include "castor/tape/legacymsg/CommonMarshal.hpp"
#include "castor/tape/legacymsg/RmcMarshal.hpp"
#include "castor/tape/tapeserver/daemon/RmcImpl.hpp"
#include "castor/tape/tapeserver/daemon/ScsiLibraryDriveName.hpp"
......@@ -121,22 +122,59 @@ void castor::tape::tapeserver::daemon::RmcImpl::mountTapeManual(const std::strin
// mountTapeScsi
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::RmcImpl::mountTapeScsi(const std::string &vid, const std::string &drive) throw(castor::exception::Exception) {
ScsiLibraryDriveName parsedDrive;
std::ostringstream task;
task << "mount tape " << vid << " in " << drive;
try {
parsedDrive = ScsiLibraryDriveName(drive);
const ScsiLibraryDriveName libraryDriveName(drive);
castor::utils::SmartFd fd(connectToRmc(libraryDriveName.rmcHostName));
legacymsg::RmcMountMsgBody body;
body.uid = m_uid;
body.gid = m_gid;
castor::utils::copyString(body.vid, vid.c_str());
body.drvOrd = libraryDriveName.drvOrd;
writeRmcMountMsg(fd.get(), body);
const legacymsg::MessageHeader header = readRmcMsgHeader(fd.get());
switch(header.reqType) {
case RMC_RC:
if(0 != header.lenOrStatus) {
castor::exception::Internal ex;
ex.getMessage() << "Received error code from rmc running on " <<
libraryDriveName.rmcHostName << ": code=" << header.lenOrStatus;
throw ex;
}
break;
case MSG_ERR:
{
char errorBuf[1024];
const int nbBytesToRead = header.lenOrStatus > sizeof(errorBuf) ?
sizeof(errorBuf) : header.lenOrStatus;
castor::io::readBytes(fd.get(), m_netTimeout, nbBytesToRead, errorBuf);
errorBuf[sizeof(errorBuf) - 1] = '\0';
castor::exception::Internal ex;
ex.getMessage() << "Received error message from rmc running on " <<
libraryDriveName.rmcHostName << ": " << errorBuf;
throw ex;
}
break;
default:
{
castor::exception::Internal ex;
ex.getMessage() <<
"Reply message from rmc running on " << libraryDriveName.rmcHostName <<
" has an unexpected request type"
": reqType=0x" << header.reqType;
throw ex;
}
}
} catch(castor::exception::Exception &ne) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to mount tape in SCSI library: " << ne.getMessage().str();
ex.getMessage() << "Failed to " << task.str() << ": " << ne.getMessage().str();
throw ex;
}
castor::utils::SmartFd fd(connectToRmc(parsedDrive.rmcHostName));
legacymsg::RmcMountMsgBody body;
body.uid = m_uid;
body.gid = m_gid;
castor::utils::copyString(body.vid, vid.c_str());
body.drvOrd = parsedDrive.drvOrd;
writeRmcMountMsg(fd.get(), body);
}
//------------------------------------------------------------------------------
......@@ -199,6 +237,60 @@ void castor::tape::tapeserver::daemon::RmcImpl::unmountTapeManual(const std::str
// unmountTapeScsi
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::RmcImpl::unmountTapeScsi(const std::string &vid, const std::string &drive) throw(castor::exception::Exception) {
std::ostringstream task;
task << "unmount tape " << vid << " from " << drive;
try {
const ScsiLibraryDriveName libraryDriveName(drive);
castor::utils::SmartFd fd(connectToRmc(libraryDriveName.rmcHostName));
legacymsg::RmcUnmountMsgBody body;
body.uid = m_uid;
body.gid = m_gid;
castor::utils::copyString(body.vid, vid.c_str());
body.drvOrd = libraryDriveName.drvOrd;
body.force = 0;
writeRmcUnmountMsg(fd.get(), body);
const legacymsg::MessageHeader header = readRmcMsgHeader(fd.get());
switch(header.reqType) {
case RMC_RC:
if(0 != header.lenOrStatus) {
castor::exception::Internal ex;
ex.getMessage() << "Received error code from rmc running on " <<
libraryDriveName.rmcHostName << ": code=" << header.lenOrStatus;
throw ex;
}
break;
case MSG_ERR:
{
char errorBuf[1024];
const int nbBytesToRead = header.lenOrStatus > sizeof(errorBuf) ?
sizeof(errorBuf) : header.lenOrStatus;
castor::io::readBytes(fd.get(), m_netTimeout, nbBytesToRead, errorBuf);
errorBuf[sizeof(errorBuf) - 1] = '\0';
castor::exception::Internal ex;
ex.getMessage() << "Received error message from rmc running on " <<
libraryDriveName.rmcHostName << ": " << errorBuf;
throw ex;
}
break;
default:
{
castor::exception::Internal ex;
ex.getMessage() <<
"Reply message from rmc running on " << libraryDriveName.rmcHostName <<
" has an unexpected request type"
": reqType=0x" << header.reqType;
throw ex;
}
}
} catch(castor::exception::Exception &ne) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to " << task.str() << ": " << ne.getMessage().str();
throw ex;
}
}
//-----------------------------------------------------------------------------
......@@ -221,7 +313,8 @@ int castor::tape::tapeserver::daemon::RmcImpl::connectToRmc(const std::string &h
//-----------------------------------------------------------------------------
// writeRmcMountMsg
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::RmcImpl::writeRmcMountMsg(const int fd, const legacymsg::RmcMountMsgBody &body) throw(castor::exception::Exception) {
void castor::tape::tapeserver::daemon::RmcImpl::writeRmcMountMsg(const int fd, const legacymsg::RmcMountMsgBody &body)
throw(castor::exception::Exception) {
char buf[RMC_MSGBUFSIZ];
const size_t len = legacymsg::marshal(buf, body);
......@@ -234,3 +327,52 @@ void castor::tape::tapeserver::daemon::RmcImpl::writeRmcMountMsg(const int fd, c
throw ex;
}
}
//-----------------------------------------------------------------------------
// readRmcMsgHeader
//-----------------------------------------------------------------------------
castor::tape::legacymsg::MessageHeader castor::tape::tapeserver::daemon::RmcImpl::readRmcMsgHeader(const int fd) throw(castor::exception::Exception) {
char buf[12]; // Magic + type + len
legacymsg::MessageHeader header;
try {
io::readBytes(fd, m_netTimeout, sizeof(buf), buf);
} catch(castor::exception::Exception &ne) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to read message header: "
<< ne.getMessage().str();
throw ex;
}
const char *bufPtr = buf;
size_t bufLen = sizeof(buf);
legacymsg::unmarshal(bufPtr, bufLen, header);
if(RMC_MAGIC != header.magic) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to read message header: "
" Header contains an invalid magic number: expected=0x" << std::hex <<
RMC_MAGIC << " actual=0x" << header.magic;
throw ex;
}
return header;
}
//-----------------------------------------------------------------------------
// writeRmcUnmountMsg
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::RmcImpl::writeRmcUnmountMsg(const int fd, const legacymsg::RmcUnmountMsgBody &body)
throw(castor::exception::Exception) {
char buf[RMC_MSGBUFSIZ];
const size_t len = legacymsg::marshal(buf, body);
try {
io::writeBytes(fd, m_netTimeout, len, buf);
} catch(castor::exception::Exception &ne) {
castor::exception::Internal ex;
ex.getMessage() << "Failed to write RMC_UNMOUNT message: "
<< ne.getMessage().str();
throw ex;
}
}
......@@ -23,7 +23,9 @@
#pragma once
#include "castor/log/Logger.hpp"
#include "castor/tape/legacymsg/MessageHeader.hpp"
#include "castor/tape/legacymsg/RmcMountMsgBody.hpp"
#include "castor/tape/legacymsg/RmcUnmountMsgBody.hpp"
#include "castor/tape/tapeserver/daemon/Rmc.hpp"
#include <unistd.h>
......@@ -192,10 +194,28 @@ protected:
* Writes an RMC_MOUNT message with the specifed body to the specified
* connection.
*
* @param body The body of the RMC_MOUNT message.