Commit e0b8f264 authored by Daniele Kruse's avatar Daniele Kruse
Browse files

Improved cmdline and frontend error reporting and added timeout of cmdline in case CTA is down

parent 9381253d
......@@ -21,7 +21,7 @@ find_package (cryptopp REQUIRED)
find_package (xrootd REQUIRED)
include_directories (${XROOTD_INCLUDE_DIR} ${XROOTD_PRIVATE_INCLUDE_DIR} ${CMAKE_SOURCE_DIR})
add_executable (cta CTACmdMain.cpp CTACmd.cpp)
add_executable (cta CTACmdMain.cpp)
target_link_libraries (cta ${XROOTD_XRDCL_LIB} ctacommon cryptopp ctautils)
install (TARGETS cta DESTINATION usr/bin)
......
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "castor/common/CastorConfiguration.hpp"
#include "cmdline/CTACmd.hpp"
#include "common/Configuration.hpp"
#include "common/exception/Exception.hpp"
#include "XrdCl/XrdClCopyProcess.hh"
#include <cryptopp/base64.h>
#include <cryptopp/osrng.h>
#include <iostream>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
cta::cmdline::CTACmd::CTACmd() throw() {
}
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int cta::cmdline::CTACmd::main(const int argc, const char **argv) const throw() {
try {
return sendCommand(argc, argv);
} catch(cta::exception::Exception &ex) {
std::cerr << "Failed to execute the command. Reason: " << ex.getMessageValue() << std::endl;
return 1;
} catch (std::exception &ex) {
std::cerr << "Failed to execute the command. Reason: " << ex.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "Failed to execute the command for an unknown reason" << std::endl;
return 1;
}
}
//------------------------------------------------------------------------------
// sendCommand
//------------------------------------------------------------------------------
int cta::cmdline::CTACmd::sendCommand(const int argc, const char **argv) const {
XrdCl::PropertyList properties;
properties.Set("source", formatCommandPath(argc, argv));
properties.Set("target", "-"); //destination is stdout
XrdCl::PropertyList results;
XrdCl::CopyProcess copyProcess;
XrdCl::XRootDStatus status = copyProcess.AddJob(properties, &results);
if(!status.IsOK())
{
throw cta::exception::Exception(status.ToStr());
}
status = copyProcess.Prepare();
if(!status.IsOK())
{
throw cta::exception::Exception(status.ToStr());
}
XrdCl::CopyProgressHandler copyProgressHandler;
status = copyProcess.Run(&copyProgressHandler);
if(!status.IsOK())
{
throw cta::exception::Exception(status.ToStr());
}
return 0;
}
//------------------------------------------------------------------------------
// formatCommandPath
//------------------------------------------------------------------------------
std::string cta::cmdline::CTACmd::formatCommandPath(const int argc, const char **argv) const {
cta::common::Configuration ctaConf("/etc/cta/cta-frontend.conf");
std::string cmdPath = "root://"+ctaConf.getConfEntString("Frontend", "HostAndPort", NULL)+"//";
for(int i=0; i<argc; i++) {
if(i) cmdPath += "&";
cmdPath += encode(std::string(argv[i]));
}
return cmdPath;
}
//------------------------------------------------------------------------------
// replaceAll
//------------------------------------------------------------------------------
void cta::cmdline::CTACmd::replaceAll(std::string& str, const std::string& from, const std::string& to) const {
if(from.empty() || str.empty())
return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
}
//------------------------------------------------------------------------------
// encode
//------------------------------------------------------------------------------
std::string cta::cmdline::CTACmd::encode(const std::string msg) const {
std::string ret;
const bool noNewLineInBase64Output = false;
CryptoPP::StringSource ss1(msg, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(ret), noNewLineInBase64Output));
// need to replace slashes ('/') with underscores ('_') because xroot removes
// consecutive slashes, and the cryptopp base64 algorithm may produce
// consecutive slashes. This is solved in cryptopp-5.6.3 (using
// Base64URLEncoder instead of Base64Encoder) but we currently have
// cryptopp-5.6.2. To be changed in the future...
replaceAll(ret, "/", "_");
return ret;
}
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace cta { namespace cmdline {
/**
* Class implementing the business logic of the archive command-line tool.
*/
class CTACmd {
public:
/**
* Constructor.
*/
CTACmd() throw();
/**
* The entry function of the command.
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
*/
int main(const int argc, const char **argv) const throw();
private:
/**
* Sends the command and waits for the reply
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
* @return the return code
*/
int sendCommand(const int argc, const char **argv) const;
/**
* Formats the command path string
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
* @return the command string
*/
std::string formatCommandPath(const int argc, const char **argv) const;
/**
* Replaces all occurrences in a string "str" of a substring "from" with the string "to"
*
* @param str The original string
* @param from The substring to replace
* @param to The replacement string
*/
void replaceAll(std::string& str, const std::string& from, const std::string& to) const;
/**
* Encodes a string in base 64 and replaces slatches ('/') in the result
* with underscores ('_').
*
* Need to replace slashes ('/') with underscores ('_') because xroot removes
* consecutive slashes, and the cryptopp base64 algorithm may produce
* consecutive slashes. This is solved in cryptopp-5.6.3 (using
* Base64URLEncoder instead of Base64Encoder) but we currently have
* cryptopp-5.6.2. To be changed in the future...
*
* @param msg string to encode
* @return encoded string
*/
std::string encode(const std::string msg) const;
}; // class CTACmd
}}
......@@ -16,14 +16,141 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CTACmd.hpp"
#include "common/Configuration.hpp"
#include "common/exception/Exception.hpp"
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(const int argc, const char **argv) {
#include "XrdCl/XrdClCopyProcess.hh"
#include <cryptopp/base64.h>
#include <cryptopp/osrng.h>
cta::cmdline::CTACmd command;
#include <iostream>
#include <future>
#include <chrono>
/**
* Replaces all occurrences in a string "str" of a substring "from" with the string "to"
*
* @param str The original string
* @param from The substring to replace
* @param to The replacement string
*/
void replaceAll(std::string& str, const std::string& from, const std::string& to){
if(from.empty() || str.empty())
return;
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length();
}
}
/**
* Encodes a string in base 64 and replaces slatches ('/') in the result
* with underscores ('_').
*
* Need to replace slashes ('/') with underscores ('_') because xroot removes
* consecutive slashes, and the cryptopp base64 algorithm may produce
* consecutive slashes. This is solved in cryptopp-5.6.3 (using
* Base64URLEncoder instead of Base64Encoder) but we currently have
* cryptopp-5.6.2. To be changed in the future...
*
* @param msg string to encode
* @return encoded string
*/
std::string encode(const std::string msg) {
std::string ret;
const bool noNewLineInBase64Output = false;
CryptoPP::StringSource ss1(msg, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(ret), noNewLineInBase64Output));
// need to replace slashes ('/') with underscores ('_') because xroot removes
// consecutive slashes, and the cryptopp base64 algorithm may produce
// consecutive slashes. This is solved in cryptopp-5.6.3 (using
// Base64URLEncoder instead of Base64Encoder) but we currently have
// cryptopp-5.6.2. To be changed in the future...
replaceAll(ret, "/", "_");
return ret;
}
/**
* Formats the command path string
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
* @return the command string
*/
std::string formatCommandPath(const int argc, const char **argv) {
cta::common::Configuration ctaConf("/etc/cta/cta-frontend.conf");
std::string cmdPath = "root://"+ctaConf.getConfEntString("Frontend", "HostAndPort", NULL)+"//";
for(int i=0; i<argc; i++) {
if(i) cmdPath += "&";
cmdPath += encode(std::string(argv[i]));
}
return cmdPath;
}
/**
* Sends the command and waits for the reply
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
* @return the return code
*/
int sendCommand(const int argc, const char **argv) {
XrdCl::PropertyList properties;
properties.Set("source", formatCommandPath(argc, argv));
properties.Set("target", "-"); //destination is stdout
XrdCl::PropertyList results;
XrdCl::CopyProcess copyProcess;
XrdCl::XRootDStatus status = copyProcess.AddJob(properties, &results);
if(!status.IsOK())
{
throw cta::exception::Exception(status.ToStr());
}
return command.main(argc, argv);
status = copyProcess.Prepare();
if(!status.IsOK())
{
throw cta::exception::Exception(status.ToStr());
}
XrdCl::CopyProgressHandler copyProgressHandler;
status = copyProcess.Run(&copyProgressHandler);
if(!status.IsOK())
{
throw cta::exception::Exception(status.ToStr());
}
return 0;
}
/**
* The entry function of the command.
*
* @param argc The number of command-line arguments.
* @param argv The command-line arguments.
*/
int main(const int argc, const char **argv) {
try {
std::chrono::system_clock::time_point five_secs_passed = std::chrono::system_clock::now() + std::chrono::seconds(5);
// call function asynchronously:
std::future<int> fut = std::async(std::launch::async, sendCommand, argc, argv);
if(std::future_status::ready == fut.wait_until(five_secs_passed)) {
return fut.get();
}
else {
std::cout<<"Timeout!\n";
exit(1);
}
} catch(cta::exception::Exception &ex) {
std::cerr << "Failed to execute the command. Reason: " << ex.getMessageValue() << std::endl;
return 1;
} catch (std::exception &ex) {
std::cerr << "Failed to execute the command. Reason: " << ex.what() << std::endl;
return 1;
} catch (...) {
std::cerr << "Failed to execute the command for an unknown reason" << std::endl;
return 1;
}
}
......@@ -38,6 +38,7 @@ set (COMMON_LIB_SRC_FILES
dataStructures/DriveState.cpp
dataStructures/DriveStatus.cpp
dataStructures/EntryLog.cpp
dataStructures/FrontendReturnCode.cpp
dataStructures/ListStorageClassRequest.cpp
dataStructures/LogicalLibrary.cpp
dataStructures/MountType.cpp
......
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "FrontendReturnCode.hpp"
namespace cta {
namespace common {
namespace dataStructures {
std::string toString(FrontendReturnCode rc) {
switch(rc) {
case FrontendReturnCode::ok:
return "ok";
case FrontendReturnCode::userErrorNoRetry:
return "userErrorNoRetry";
case FrontendReturnCode::ctaErrorNoRetry:
return "ctaErrorNoRetry";
case FrontendReturnCode::ctaErrorRetry:
return "ctaErrorRetry";
case FrontendReturnCode::ctaFrontendTimeout:
return "ctaFrontendTimeout";
default:
return "UNKNOWN";
}
}
} // namespace dataStructures
} // namespace common
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
namespace cta {
namespace common {
namespace dataStructures {
enum FrontendReturnCode {
ok,
userErrorNoRetry,
ctaErrorNoRetry,
ctaErrorRetry,
ctaFrontendTimeout
};
std::string toString(FrontendReturnCode code);
} // namespace dataStructures
} // namespace common
} // namespace cta
This diff is collapsed.
......@@ -19,6 +19,7 @@
#pragma once
#include "catalogue/Catalogue.hpp"
#include "common/dataStructures/FrontendReturnCode.hpp"
#include "scheduler/Scheduler.hpp"
#include "XrdSfs/XrdSfsInterface.hh"
......@@ -74,6 +75,11 @@ protected:
*/
std::string m_data;
/**
* This is the return code to be passed to the client
*/
cta::common::dataStructures::FrontendReturnCode m_rc;
/**
* Decodes a string in base 64
*
......
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