Commit edc85cbc authored by Eric Cano's avatar Eric Cano
Browse files

CASTOR-4739: tapeserverd should support localfile, rfio, xroot and rados...

CASTOR-4739: tapeserverd should support localfile, rfio, xroot and rados striper access for disk files

Changed the behaviour in case of non-URL paths(*): if we get Ceph non-URL path, we open
the path (which always points to localhost) via the castor2fs xroot extension. In this
case, we add the castor2fs.pool parameter to the path. We also force to port number
to castor2fs's 1095. This will allow access to ceph via  local xroot translation deamon
running on the tape server's host.

The code has been factored out to allow also bare Xroot accesses with full URLs.

(*) Non-URL path is the current path description exchanged between tape gateway and
tape server, in the form <server>:<pool>/<object name> for ceph objects and
<server>:/path/to/the/file for xroot files.
parent 01428a4e
......@@ -43,22 +43,22 @@ DiskFileFactory::DiskFileFactory(const std::string & remoteFileProtocol,
const std::string & xrootPrivateKeyFile):
m_NoURLLocalFile("^(localhost:|)(/.*)$"),
m_NoURLRemoteFile("^(.*:)(/.*)$"),
m_NoURLRadosStriperFile("^localhost:([^/].*)$"),
m_NoURLRadosStriperFile("^localhost:([^/]+)/(.*)$"),
m_URLLocalFile("^file://(.*)$"),
m_URLRfioFile("^rfio://(.*)$"),
m_URLXrootFile("^(root://.*)$"),
m_URLCephFile("^radosStriper://(.*)$"),
m_remoteFileProtocol(remoteFileProtocol),
m_xrootPrivateKeyFile(xrootPrivateKeyFile),
m_xrootCryptoPPPrivateKeyLoaded(false)
m_xrootPrivateKeyLoaded(false)
{
// Lowercase the protocol string
std::transform(m_remoteFileProtocol.begin(), m_remoteFileProtocol.end(),
m_remoteFileProtocol.begin(), ::tolower);
}
const CryptoPP::RSA::PrivateKey & DiskFileFactory::xrootCryptoPPPrivateKey() {
if(!m_xrootCryptoPPPrivateKeyLoaded) {
const CryptoPP::RSA::PrivateKey & DiskFileFactory::xrootPrivateKey() {
if(!m_xrootPrivateKeyLoaded) {
// The loading of a PEM-style key is described in
// http://www.cryptopp.com/wiki/Keys_and_Formats#PEM_Encoded_Keys
std::string key;
......@@ -95,7 +95,7 @@ const CryptoPP::RSA::PrivateKey & DiskFileFactory::xrootCryptoPPPrivateKey() {
decoder.Put((const byte*)keystr.data(), keystr.length());
decoder.MessageEnd();
m_xrootCryptoPPPrivateKey.BERDecodePrivateKey(queue, false /*paramsPresent*/, queue.MaxRetrievable());
m_xrootPrivateKey.BERDecodePrivateKey(queue, false /*paramsPresent*/, queue.MaxRetrievable());
// BERDecodePrivateKey is a void function. Here's the only check
// we have regarding the DER bytes consumed.
......@@ -104,14 +104,14 @@ const CryptoPP::RSA::PrivateKey & DiskFileFactory::xrootCryptoPPPrivateKey() {
"In DiskFileFactory::xrootCryptoPPPrivateKey, garbage at end of key");
CryptoPP::AutoSeededRandomPool prng;
bool valid = m_xrootCryptoPPPrivateKey.Validate(prng, 3);
bool valid = m_xrootPrivateKey.Validate(prng, 3);
if(!valid)
throw castor::exception::Exception(
"In DiskFileFactory::xrootCryptoPPPrivateKey, RSA private key is not valid");
m_xrootCryptoPPPrivateKeyLoaded = true;
m_xrootPrivateKeyLoaded = true;
}
return m_xrootCryptoPPPrivateKey;
return m_xrootPrivateKey;
}
ReadFile * DiskFileFactory::createReadFile(const std::string& path) {
......@@ -130,7 +130,7 @@ ReadFile * DiskFileFactory::createReadFile(const std::string& path) {
// Xroot URL?
regexResult = m_URLXrootFile.exec(path);
if (regexResult.size()) {
return new XrootReadFile(regexResult[1],xrootCryptoPPPrivateKey());
return new XrootReadFile(regexResult[1]);
}
// radosStriper URL?
regexResult = m_URLCephFile.exec(path);
......@@ -148,8 +148,8 @@ ReadFile * DiskFileFactory::createReadFile(const std::string& path) {
if (regexResult.size()) {
if (m_remoteFileProtocol == "xroot") {
// In the current CASTOR implementation, the xrootd port is hard coded to 1095
return new XrootReadFile(std::string("root://") + regexResult[1] + "1095/"
+ regexResult[2],xrootCryptoPPPrivateKey());
return new XrootC2FSReadFile(std::string("root://") + regexResult[1] + "1095/"
+ regexResult[2],xrootPrivateKey());
} else {
return new RfioReadFile(regexResult[1]+regexResult[2]);
}
......@@ -157,7 +157,9 @@ ReadFile * DiskFileFactory::createReadFile(const std::string& path) {
// Do we have a radosStriper file?
regexResult = m_NoURLRadosStriperFile.exec(path);
if (regexResult.size()) {
return new RadosStriperReadFile(regexResult[1]);
return new XrootC2FSReadFile(
std::string("root://localhost:1095/")+regexResult[1]+"/"+regexResult[2],xrootPrivateKey(),
regexResult[1]);
}
throw castor::exception::Exception(
std::string("In DiskFileFactory::createReadFile failed to parse URL: ")+path);
......@@ -179,7 +181,7 @@ WriteFile * DiskFileFactory::createWriteFile(const std::string& path) {
// Xroot URL?
regexResult = m_URLXrootFile.exec(path);
if (regexResult.size()) {
return new XrootWriteFile(regexResult[1],xrootCryptoPPPrivateKey());
return new XrootWriteFile(regexResult[1]);
}
// radosStriper URL?
regexResult = m_URLCephFile.exec(path);
......@@ -197,16 +199,18 @@ WriteFile * DiskFileFactory::createWriteFile(const std::string& path) {
if (regexResult.size()) {
if (m_remoteFileProtocol == "xroot") {
// In the current CASTOR implementation, the xrootd port is hard coded to 1095
return new XrootWriteFile(std::string("root://") + regexResult[1] + "1095/"
+ regexResult[2],xrootCryptoPPPrivateKey());
return new XrootC2FSWriteFile(std::string("root://") + regexResult[1] + "1095/"
+ regexResult[2],xrootPrivateKey());
} else {
return new XrootWriteFile(regexResult[1]+regexResult[2],xrootCryptoPPPrivateKey());
return new XrootC2FSWriteFile(regexResult[1]+regexResult[2],xrootPrivateKey());
}
}
// Do we have a radosStriper file?
regexResult = m_NoURLRadosStriperFile.exec(path);
if (regexResult.size()) {
return new RadosStriperWriteFile(regexResult[0]);
return new XrootC2FSWriteFile(
std::string("root://localhost:1095/")+regexResult[1]+"/"+regexResult[2],xrootPrivateKey(),
regexResult[1]);
}
throw castor::exception::Exception(
std::string("In DiskFileFactory::createWriteFile failed to parse URL: ")+path);
......@@ -369,14 +373,18 @@ std::string CryptoPPSigner::sign(const std::string msg,
//==============================================================================
// XROOT READ FILE
//==============================================================================
XrootReadFile::XrootReadFile(const std::string &url,
const CryptoPP::RSA::PrivateKey & xrootPrivateKey):
m_readPosition(0){
using XrdCl::OpenFlags;
XrootC2FSReadFile::XrootC2FSReadFile(const std::string &url,
const CryptoPP::RSA::PrivateKey & xrootPrivateKey,
const std::string & pool) {
// Setup parent's members
m_readPosition = 0;
m_URL = url;
// And start opening
using XrdCl::OpenFlags;
m_signedURL = m_URL;
// Turn the bare URL into a Castor URL, by adding opaque tags:
// ?castor2fs.pfn1=/srv/castor/... (duplication of the path in practice)
// ?castor2fs.pool=xxx optional ceph pool
// ?castor2fs.exptime=(unix time)
// ?castor2fs.signature=
//Find the path part of the url. It is the first occurence of "//"
......@@ -385,12 +393,12 @@ m_readPosition(0){
size_t schemePos = url.find(scheme);
if (std::string::npos == schemePos)
throw castor::exception::Exception(
std::string("In XrootReadFile::XrootReadFile could not find the scheme[x]root:// in URL "+
std::string("In XrootC2FSReadFile::XrootC2FSReadFile could not find the scheme[x]root:// in URL "+
url));
size_t pathPos = url.find("//", schemePos + scheme.size());
size_t pathPos = url.find("/", schemePos + scheme.size());
if (std::string::npos == pathPos)
throw castor::exception::Exception(
std::string("In XrootReadFile::XrootReadFile could not path in URL "+
std::string("In XrootC2FSReadFile::XrootC2FSReadFile could not path in URL "+
url));
std::string path = url.substr(pathPos + 1);
// Build signature block
......@@ -403,17 +411,29 @@ m_readPosition(0){
std::stringstream opaqueBloc;
opaqueBloc << "?castor2fs.pfn1=" << path;
if (pool.size())
opaqueBloc << "&castor2fs.pool=" << pool;
opaqueBloc << "&castor2fs.exptime=" << expTime;
opaqueBloc << "&castor2fs.signature=" << signature;
m_signedURL = m_URL + opaqueBloc.str();
// ... and finally open the file
XrootClEx::throwOnError(m_xrootFile.Open(m_signedURL, OpenFlags::Read),
std::string("In XrootReadFile::XrootReadFile failed XrdCl::File::Open() on ")
std::string("In XrootC2FSReadFile::XrootC2FSReadFile failed XrdCl::File::Open() on ")
+m_URL+" opaqueBlock="+opaqueBloc.str());
}
size_t XrootReadFile::read(void *data, const size_t size) const {
XrootReadFile::XrootReadFile(const std::string &xrootUrl) {
// Setup parent's variables
m_readPosition = 0;
m_URL = xrootUrl;
// and simply open
using XrdCl::OpenFlags;
XrootClEx::throwOnError(m_xrootFile.Open(m_URL, OpenFlags::Read),
std::string("In XrootC2FSReadFile::XrootC2FSReadFile failed XrdCl::File::Open() on ")+m_URL);
}
size_t XrootBaseReadFile::read(void *data, const size_t size) const {
uint32_t ret;
XrootClEx::throwOnError(m_xrootFile.Read(m_readPosition, size, data, ret),
std::string("In XrootReadFile::read failed XrdCl::File::Read() on ")+m_URL);
......@@ -421,7 +441,7 @@ size_t XrootReadFile::read(void *data, const size_t size) const {
return ret;
}
size_t XrootReadFile::size() const {
size_t XrootBaseReadFile::size() const {
const bool forceStat=true;
XrdCl::StatInfo *statInfo(NULL);
size_t ret;
......@@ -432,7 +452,7 @@ size_t XrootReadFile::size() const {
return ret;
}
XrootReadFile::~XrootReadFile() throw() {
XrootBaseReadFile::~XrootBaseReadFile() throw() {
try{
m_xrootFile.Close();
} catch (...) {}
......@@ -441,14 +461,19 @@ XrootReadFile::~XrootReadFile() throw() {
//==============================================================================
// XROOT WRITE FILE
//==============================================================================
XrootWriteFile::XrootWriteFile(const std::string &url,
const CryptoPP::RSA::PrivateKey & xrootPrivateKey):
m_writePosition(0),m_closeTried(false){
XrootC2FSWriteFile::XrootC2FSWriteFile(const std::string &url,
const CryptoPP::RSA::PrivateKey & xrootPrivateKey,
const std::string & pool){
// Setup parent's members
m_writePosition = 0;
m_closeTried = false;
// and start opening
using XrdCl::OpenFlags;
m_URL=url;
m_signedURL = m_URL;
// Turn the bare URL into a Castor URL, by adding opaque tags:
// ?castor2fs.pfn1=/srv/castor/... (duplication of the path in practice)
// ?castor2fs.pool=xxx optional ceph pool
// ?castor2fs.exptime=(unix time)
// ?castor2fs.signature=
//Find the path part of the url. It is the first occurence of "//"
......@@ -457,12 +482,12 @@ m_writePosition(0),m_closeTried(false){
size_t schemePos = url.find(scheme);
if (std::string::npos == schemePos)
throw castor::exception::Exception(
std::string("In XrootReadFile::XrootReadFile could not find the scheme[x]root:// in URL "+
std::string("In XrootC2FSWriteFile::XrootC2FSWriteFile could not find the scheme[x]root:// in URL "+
url));
size_t pathPos = url.find("//", schemePos + scheme.size());
if (std::string::npos == pathPos)
throw castor::exception::Exception(
std::string("In XrootReadFile::XrootReadFile could not path in URL "+
std::string("In XrootC2FSWriteFile::XrootC2FSWriteFile could not path in URL "+
url));
std::string path = url.substr(pathPos + 1);
// Build signature block
......@@ -475,24 +500,37 @@ m_writePosition(0),m_closeTried(false){
std::stringstream opaqueBloc;
opaqueBloc << "?castor2fs.pfn1=" << path;
if (pool.size())
opaqueBloc << "&castor2fs.pool=" << pool;
opaqueBloc << "&castor2fs.exptime=" << expTime;
opaqueBloc << "&castor2fs.signature=" << signature;
m_signedURL = m_URL + opaqueBloc.str();
XrootClEx::throwOnError(m_xrootFile.Open(m_signedURL, OpenFlags::Delete),
std::string("In XrootWriteFile::XrootWriteFile failed XrdCl::File::Open() on ")
std::string("In XrootC2FSWriteFile::XrootC2FSWriteFile failed XrdCl::File::Open() on ")
+m_URL);
}
void XrootWriteFile::write(const void *data, const size_t size) {
XrootWriteFile::XrootWriteFile(const std::string& xrootUrl) {
// Setup parent's variables
m_writePosition = 0;
m_URL = xrootUrl;
// and simply open
using XrdCl::OpenFlags;
XrootClEx::throwOnError(m_xrootFile.Open(m_URL, OpenFlags::Delete),
std::string("In XrootWriteFile::XrootWriteFile failed XrdCl::File::Open() on ")+m_URL);
}
void XrootBaseWriteFile::write(const void *data, const size_t size) {
XrootClEx::throwOnError(m_xrootFile.Write(m_writePosition, size, data),
std::string("In XrootWriteFile::write failed XrdCl::File::Write() on ")
+m_URL);
m_writePosition += size;
}
void XrootWriteFile::close() {
void XrootBaseWriteFile::close() {
// Multiple close protection
if (m_closeTried) return;
m_closeTried=true;
......@@ -500,7 +538,7 @@ void XrootWriteFile::close() {
std::string("In XrootWriteFile::close failed XrdCl::File::Stat() on ")+m_URL);
}
XrootWriteFile::~XrootWriteFile() throw() {
XrootBaseWriteFile::~XrootBaseWriteFile() throw() {
if(!m_closeTried){
m_xrootFile.Close();
}
......
......@@ -65,11 +65,11 @@ namespace castor {
Regex m_URLCephFile;
std::string m_remoteFileProtocol;
std::string m_xrootPrivateKeyFile;
CryptoPP::RSA::PrivateKey m_xrootCryptoPPPrivateKey;
bool m_xrootCryptoPPPrivateKeyLoaded;
CryptoPP::RSA::PrivateKey m_xrootPrivateKey;
bool m_xrootPrivateKeyLoaded;
/** Return the private key. Read it from the file if necessary. */
const CryptoPP::RSA::PrivateKey & xrootCryptoPPPrivateKey();
const CryptoPP::RSA::PrivateKey & xrootPrivateKey();
};
class ReadFile {
......
......@@ -40,6 +40,9 @@ namespace castor {
* Namespace managing the reading and writing of files to and from disk.
*/
namespace diskFile {
//==============================================================================
// LOCAL FILES
//==============================================================================
class LocalReadFile: public ReadFile {
public:
LocalReadFile(const std::string &path);
......@@ -49,7 +52,7 @@ namespace castor {
private:
int m_fd;
};
class LocalWriteFile: public WriteFile {
public:
LocalWriteFile(const std::string &path);
......@@ -61,6 +64,9 @@ namespace castor {
bool m_closeTried;
};
//==============================================================================
// RFIO FILES
//==============================================================================
class RfioReadFile: public ReadFile {
public:
RfioReadFile(const std::string &rfioUrl);
......@@ -70,7 +76,7 @@ namespace castor {
private:
int m_fd;
};
class RfioWriteFile: public WriteFile {
public:
RfioWriteFile(const std::string &rfioUrl);
......@@ -82,42 +88,79 @@ namespace castor {
bool m_closeTried;
};
//==============================================================================
// CRYPTOPP SIGNER
//==============================================================================
struct CryptoPPSigner {
static std::string sign(const std::string msg,
const CryptoPP::RSA::PrivateKey & privateKey);
static castor::server::Mutex s_mutex;
};
class XrootReadFile: public ReadFile {
//==============================================================================
// XROOT FILES
//==============================================================================
class XrootBaseReadFile: public ReadFile {
public:
XrootReadFile(const std::string &xrootUrl,
const CryptoPP::RSA::PrivateKey & privateKey);
virtual size_t size() const;
virtual size_t read(void *data, const size_t size) const;
virtual ~XrootReadFile() throw();
private:
virtual ~XrootBaseReadFile() throw();
protected:
// Access to parent's protected member...
void setURL(const std::string & v) { m_URL = v; }
// There is no const-correctness with XrdCl...
mutable XrdCl::File m_xrootFile;
mutable uint64_t m_readPosition;
typedef castor::tape::server::exception::XrootCl XrootClEx;
};
class XrootReadFile: public XrootBaseReadFile {
public:
XrootReadFile(const std::string &xrootUrl);
};
class XrootC2FSReadFile: public XrootBaseReadFile {
public:
XrootC2FSReadFile(const std::string &xrootUrl,
const CryptoPP::RSA::PrivateKey & privateKey,
const std::string & cephPool = "");
virtual ~XrootC2FSReadFile() throw () {}
private:
std::string m_signedURL;
};
class XrootWriteFile: public WriteFile {
class XrootBaseWriteFile: public WriteFile {
public:
XrootWriteFile(const std::string &xrootUrl,
const CryptoPP::RSA::PrivateKey & privateKey);
virtual void write(const void *data, const size_t size);
virtual void close();
virtual ~XrootWriteFile() throw();
private:
virtual ~XrootBaseWriteFile() throw();
protected:
// Access to parent's protected member...
void setURL(const std::string & v) { m_URL = v; }
XrdCl::File m_xrootFile;
uint64_t m_writePosition;
typedef castor::tape::server::exception::XrootCl XrootClEx;
bool m_closeTried;
bool m_closeTried;
};
class XrootWriteFile: public XrootBaseWriteFile {
public:
XrootWriteFile(const std::string &xrootUrl);
};
class XrootC2FSWriteFile: public XrootBaseWriteFile {
public:
XrootC2FSWriteFile(const std::string &xrootUrl,
const CryptoPP::RSA::PrivateKey & privateKey,
const std::string & cephPool = "");
virtual ~XrootC2FSWriteFile() throw () {}
private:
std::string m_signedURL;
};
//==============================================================================
// RADOS STRIPER FILES
//==============================================================================
class RadosStriperReadFile: public ReadFile {
public:
RadosStriperReadFile(const std::string &xrootUrl);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment