Commit 07e7ab5d authored by Eric Cano's avatar Eric Cano
Browse files

Created the embryo of the new cta-taped daemon, importing many daemon utilities

from castor in the exercise.
parent 35d0282d
......@@ -11,6 +11,12 @@ set(CMAKE_C_FLAGS "-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter")
#
# ClientSimulator.hpp:65: error: ISO C++ prohibits anonymous structs
set(CMAKE_CXX_FLAGS "-fPIC -pedantic -Wall -Wextra -Werror -Wno-unused-parameter -Wno-long-long -std=c++0x -fms-extensions -fstack-protector-all")
#
# A maximalist error checking parameter combo has been suggested by S. Ponce and D. Come:
# to be tested once we have a stable compilation on CC7:
#-Wno-unused-parameter -Wlogical-op -Wfloat-equal -Wdeclaration-after- statement -Wundef -Wno-endif-labels -Wshadow -Wunsafe-loop- optimizations -Wpointer-arith -Wbad-function-cast -Wcast-align -Wwrite- strings -Wconversion -Wmissing-field-initializers -Wredundant-decls -Wnested-externs -Wunreachable-code -Winline -Wvariadic-macros -Wtraditional -Wmissing-prototypes -Wmissing-declarations -Wold-style- definition -Wc++-compat -Wstrict-prototypes -Wpadded -Wcast-qual -Wnon-virtual-dtor -Wlogical-op -Wmissing-declarations -Wsign-conversion -Wredundant-decls -Wold-style-cast -Wshadow
# Explicitly setting the C and C++ compiler flags for the RelWithDebInfo build
......@@ -77,6 +83,10 @@ ELSE(DEFINED PackageOnly)
add_subdirectory(tapeserver)
add_subdirectory(tests)
add_subdirectory(xroot_plugins)
#Generate version information
configure_file(${PROJECT_SOURCE_DIR}/version.hpp.in
${CMAKE_BINARY_DIR}/version.h)
ENDIF(DEFINED PackageOnly)
################################################################################
......
......@@ -45,30 +45,41 @@ set (COMMON_LIB_SRC_FILES
archiveNS/StorageClass.cpp
archiveNS/Tape.cpp
archiveNS/TapeFileLocation.cpp
ArchiveRequest.cpp
CreationLog.cpp
checksum/Checksum.cpp
exception/Backtrace.cpp
exception/DiskException.hpp
exception/Errnum.cpp
exception/Exception.cpp
exception/Serrnum.cpp
exception/TapeException.cpp
log/DummyLogger.cpp
log/LogContext.cpp
log/Logger.cpp
log/Message.cpp
log/Param.cpp
log/StringLogger.cpp
log/SyslogLogger.cpp
priorities/DriveQuota.cpp
priorities/MountCriteria.cpp
priorities/UserGroup.cpp
processCap/ProcessCap.cpp
processCap/SmartCap.cpp
remoteFS/RemoteFileStatus.cpp
remoteFS/RemotePath.cpp
remoteFS/RemotePathAndStatus.cpp
SecurityIdentity.cpp
strerror_r_wrapper.cpp
TapePool.cpp
Timer.cpp
threading/ChildProcess.cpp
threading/Daemon.cpp
threading/Mutex.cpp
threading/System.cpp
threading/Threading.cpp
utils/Utils.cpp
utils/strerror_r_wrapper.cpp
ArchiveRequest.cpp
CreationLog.cpp
Configuration.cpp
SecurityIdentity.cpp
TapePool.cpp
Timer.cpp
UserIdentity.cpp
Utils.cpp
VO.cpp)
add_library (ctacommon SHARED
......@@ -81,13 +92,18 @@ target_link_libraries (ctacommon
${SQLITE3_LIBRARY_RELEASE}
uuid
z
Utils)
Utils
cap)
set (COMMON_UNIT_TESTS_LIB_SRC_FILES
checksum/ChecksumTest.cpp
log/LogContextTest.cpp
log/ParamTest.cpp
log/SyslogLoggerTest.cpp
remoteFS/RemotePathTest.cpp
UserIdentityTest.cpp
UtilsTest.cpp)
threading/DaemonTest.cpp
utils/UtilsTest.cpp
UserIdentityTest.cpp)
add_library (ctacommonunittests SHARED
${COMMON_UNIT_TESTS_LIB_SRC_FILES})
/*
* 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 "Configuration.hpp"
#include "common/exception/Errnum.hpp"
#include <algorithm>
#include <fstream>
#include <errno.h>
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
cta::common::Configuration::Configuration(std::string fileName)
: m_fileName(fileName),
m_lastUpdateTime(0) {
// create internal r/w lock
int rc = pthread_rwlock_init(&m_lock, NULL);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "CastorConfiguration constructor Failed"
": Failed to create internal r/w lock";
throw e;
}
}
//------------------------------------------------------------------------------
// copy constructor
//------------------------------------------------------------------------------
cta::common::Configuration::Configuration(
const Configuration & other) :
m_fileName(other.m_fileName), m_lastUpdateTime(other.m_lastUpdateTime),
m_config(other.m_config) {
// create a new internal r/w lock
int rc = pthread_rwlock_init(&m_lock, NULL);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "CastorConfiguration copy constructor failed"
": Failed to create a new internal r/w lock";
throw e;
}
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
cta::common::Configuration::~Configuration() {
// relase read write lock
pthread_rwlock_destroy(&m_lock);
}
//------------------------------------------------------------------------------
// assignment operator
//------------------------------------------------------------------------------
cta::common::Configuration &
cta::common::Configuration::operator=(
const cta::common::Configuration & other)
{
m_fileName = other.m_fileName;
m_lastUpdateTime = other.m_lastUpdateTime;
m_config = other.m_config;
// create a new internal r/w lock
int rc = pthread_rwlock_init(&m_lock, NULL);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "Assignment operator of CastorConfiguration object failed"
": Failed to create a new internal r/w lock";
throw e;
}
return *this;
}
//------------------------------------------------------------------------------
// getConfEntString
//------------------------------------------------------------------------------
const std::string& cta::common::Configuration::getConfEntString(
const std::string &category, const std::string &key,
const std::string &defaultValue, log::Logger *const log) {
try {
if (isStale()) {
tryToRenewConfig();
}
// get read lock
int rc = pthread_rwlock_rdlock(&m_lock);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "Failed to get configuration entry " << category << ":"
<< key << ": Failed to get read lock";
throw e;
}
// get the entry
std::map<std::string, ConfCategory>::const_iterator catIt = m_config.find(category);
if (m_config.end() != catIt) {
// get the entry
ConfCategory::const_iterator entIt = catIt->second.find(key);
if (catIt->second.end() != entIt) {
// release the lock
pthread_rwlock_unlock(&m_lock);
if(NULL != log) {
log::Param params[] = {
log::Param("category", category),
log::Param("key", key),
log::Param("value", entIt->second),
log::Param("source", m_fileName)};
(*log)(LOG_INFO, "Configuration entry", params);
}
return entIt->second;
}
}
// no entry found
if(NULL != log) {
log::Param params[] = {
log::Param("category", category),
log::Param("key", key),
log::Param("value", defaultValue),
log::Param("source", "DEFAULT")};
(*log)(LOG_INFO, "Configuration entry", params);
}
// Unlock and return default
pthread_rwlock_unlock(&m_lock);
} catch (cta::exception::Exception ex) {
// exception caught : Unlock and return default
pthread_rwlock_unlock(&m_lock);
// log the exception
if(NULL != log) {
log::Param params[] = {
log::Param("category", category),
log::Param("key", key),
log::Param("value", defaultValue),
log::Param("source", "DEFAULT")};
(*log)(LOG_INFO, "Configuration entry", params);
}
} catch (...) {
// release the lock
pthread_rwlock_unlock(&m_lock);
throw;
}
return defaultValue;
}
//------------------------------------------------------------------------------
// getConfEntString
//------------------------------------------------------------------------------
const std::string& cta::common::Configuration::getConfEntString(
const std::string &category, const std::string &key, log::Logger *const log) {
// check whether we need to reload the configuration
if (isStale()) {
tryToRenewConfig();
}
// get read lock
int rc = pthread_rwlock_rdlock(&m_lock);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "Failed to get configuration entry " << category << ":"
<< key << ": Failed to get read lock";
throw e;
}
// get the entry
try {
std::map<std::string, ConfCategory>::const_iterator catIt =
m_config.find(category);
if (m_config.end() == catIt) {
NoEntry e;
e.getMessage() << "Failed to get configuration entry " << category << ":"
<< key << ": Failed to find " << category << " category";
throw e;
}
// get the entry
ConfCategory::const_iterator entIt = catIt->second.find(key);
if (catIt->second.end() == entIt) {
NoEntry e;
e.getMessage() << "Failed to get configuration entry " << category << ":"
<< key << ": Failed to find " << key << " key";
throw e;
}
if(NULL != log) {
log::Param params[] = {
log::Param("category", category),
log::Param("key", key),
log::Param("value", entIt->second),
log::Param("source", m_fileName)};
(*log)(LOG_INFO, "Configuration entry", params);
}
// release the lock
pthread_rwlock_unlock(&m_lock);
return entIt->second;
} catch (...) {
// release the lock
pthread_rwlock_unlock(&m_lock);
throw;
}
}
//------------------------------------------------------------------------------
// isStale
//------------------------------------------------------------------------------
bool cta::common::Configuration::isStale()
{
// get read lock
int rc = pthread_rwlock_rdlock(&m_lock);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "Failed to determine if CASTOR configuration is stale"
": Failed to get read lock";
throw e;
}
try {
// get the timeout
int timeout = getTimeoutNolock();
// release the lock
pthread_rwlock_unlock(&m_lock);
// return whether we should renew
return time(0) > m_lastUpdateTime + timeout;
} catch (...) {
// release the lock
pthread_rwlock_unlock(&m_lock);
throw;
}
}
//------------------------------------------------------------------------------
// tryToRenewConfig
//------------------------------------------------------------------------------
void cta::common::Configuration::tryToRenewConfig()
{
// we should probably renew. First take the write lock.
int rc = pthread_rwlock_wrlock(&m_lock);
if (0 != rc) {
cta::exception::Errnum e(rc);
e.getMessage() << "Failed to renew configuration cache"
": Failed to take write lock";
throw e;
}
// now check that we should really renew, because someone may have done it
// while we waited for the lock
try {
if (time(0) > m_lastUpdateTime + getTimeoutNolock()) {
// now we should really renew
renewConfigNolock();
}
} catch (...) {
// release the lock
pthread_rwlock_unlock(&m_lock);
throw;
}
// release the lock
pthread_rwlock_unlock(&m_lock);
return;
}
//------------------------------------------------------------------------------
// getTimeoutNolock
//------------------------------------------------------------------------------
int cta::common::Configuration::getTimeoutNolock()
{
// start with the default (300s = 5mn)
int timeout = 300;
// get value from config
std::map<std::string, ConfCategory>::const_iterator catIt =
m_config.find("Config");
if (m_config.end() != catIt) {
ConfCategory::const_iterator entIt = catIt->second.find("ExpirationDelay");
if (catIt->second.end() != entIt) {
// parse the timeout into an integer
timeout = atoi(entIt->second.c_str());
}
}
// return timeout
return timeout;
}
//------------------------------------------------------------------------------
// renewConfigNolock
//------------------------------------------------------------------------------
void cta::common::Configuration::renewConfigNolock()
{
// reset the config
m_config.clear();
// try to open the configuration file, throwing an exception if there is a
// failure
std::ifstream file(m_fileName.c_str());
if(file.fail()) {
cta::exception::Errnum ex(EIO);
ex.getMessage() << __FUNCTION__ << " failed"
": Failed to open file"
": m_fileName=" << m_fileName;
throw ex;
}
std::string line;
while(std::getline(file, line)) {
// get rid of potential tabs
std::replace(line.begin(),line.end(),'\t',' ');
// get the category
std::istringstream sline(line);
std::string category;
if (!(sline >> category)) continue; // empty line
if (category[0] == '#') continue; // comment
// get the key
std::string key;
if (!(sline >> key)) continue; // no key on line
if (key[0] == '#') continue; // key commented
// get and store value
while (sline.get() == ' '){}; sline.unget(); // skip spaces
std::string value;
std::getline(sline, value, '#');
value.erase(value.find_last_not_of(" \n\r\t")+1); // right trim
m_config[category][key] = value;
}
m_lastUpdateTime = time(0);
}
/*
* 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 "common/exception/Exception.hpp"
#include "common/log/Logger.hpp"
#include "common/utils/Utils.hpp"
#include <string>
#include <map>
namespace cta { namespace common {
/**
* represents a category from the CTA configuration file
*/
typedef std::map<std::string, std::string> ConfCategory;
/**
* a class representing the configuration of castor.
* This configurations is obtained from the local file given in the
* constructor and will be updated regularly. The time between two
* updates is taken from the Config/ExpirationDelay entry of the
* configuration itself and defaults to 5mn if no such entry is found
*/
class Configuration {
public:
/**
* Private exceptions for this
*/
CTA_GENERATE_EXCEPTION_CLASS(InvalidConfigEntry);
CTA_GENERATE_EXCEPTION_CLASS(NoEntry);
public:
/**
* constructor
* @param fileName the file that should be used to build the configuration
*/
Configuration(std::string fileName = "/etc/cta/cta.conf");
/**
* copy constructor
* @param other instance of CastorConfiguration class
*/
Configuration(const Configuration & other);
/**
* destructor
*/
virtual ~Configuration();
/**
* assignment operator
* @param other instance of CastorConfiguration class
*/
Configuration & operator=(const Configuration & other);
/**
* Retrieves a configuration entry.
*
* If this method is passed a logger object then it will log the value
* of the configuration entry together with an indication of whether the
* value was found in the castor configuration file or whether the
* specified default value was used instead.
*
* @param category the category of the entry
* @param key the key of the entry
* @param defaultValue the value to be returned if the configuration entry
* is not in the configuration file
* @param log pointer to NULL or an optional logger object
*/
const std::string& getConfEntString(const std::string &category,
const std::string &key, const std::string &defaultValue,
log::Logger *const log = NULL);
/**
* Retrieves a configuration entry.
*
* Besides other possible exceptions, this method throws a
* castor::exception::NoEntry exception if the specified configuration
* entry is not in the configuration file.
*
* If this method is passed a logger object then this method will log the
* the value of the configuration entry.
*
* @param category the category of the entry
* @param key the key of the entry
* @param log pointer to NULL or an optional logger object
*/
const std::string& getConfEntString(const std::string &category,
const std::string &key, log::Logger *const log = NULL);
/**
* Retrieves a configuration entry as an integer.
*
* If this method is passed a logger object then it will log the value
* of the configuration entry together with an indication of whether the
* value was found in the castor configuration file or whether the
* specified default value was used instead.
*
* @param category category of the configuration parameter
* @param name category of the configuration parameter
* @param defaultValue the value to be returned if the configuration entry
* is not in the configuration file
* @param log pointer to NULL or an optional logger object
* @return the integer value
*/
template<typename T> T getConfEntInt(const std::string &category,
const std::string &key, const T defaultValue,
log::Logger *const log = NULL) {
std::string strValue;
try {
strValue = getConfEntString(category, key);
} catch(cta::exception::Exception &ex) {
if(NULL != log) {
log::Param params[] = {
log::Param("category", category),
log::Param("key", key),
log::Param("value", defaultValue),
log::Param("source", "DEFAULT")};
(*log)(LOG_INFO, "Configuration entry", params);
}
return defaultValue;
}
if (!Utils::isValidUInt(strValue.c_str())) {
InvalidConfigEntry ex(category.c_str(),
key.c_str(), strValue.c_str());
ex.getMessage() << "Failed to get configuration entry " << category <<
":" << key << ": Value is not a valid unsigned integer: value=" <<
strValue;
throw ex;
}
T value;
std::stringstream ss;
ss << strValue.c_str();
ss >> value;
if(NULL != log) {
log::Param params[] = {
log::Param("category", category),
log::Param("key", key),
log::Param("value", value),
log::Param("source", m_fileName)};
(*log)(LOG_INFO, "Configuration entry", params);
}
return value;
}
/**
* Retrieves a configuration entry as an integer.
*
* Besides other possible exceptions, this method throws a
* castor::exception::NoEntry exception if the specified configuration
* entry is not in the configuration file.
*
* @param category category of the configuration parameter
* @param name category of the configuration parameter
* @param log pointer to NULL or an optional logger object
* @return the integer value
*/
template<typename T> T getConfEntInt(const std::string &category,
const std::string &key, log::Logger *const log = NULL) {
const std::string strValue = getConfEntString(category, key);
if (!Utils::isValidUInt(strValue.c_str())) {
InvalidConfigEntry ex(category.c_str(),
key.c_str(), strValue.c_str());
ex.getMessage() << "Failed to get configuration entry " << category <<
":" << key << ": Value is not a valid unsigned integer: value=" <<
strValue;
throw ex;
}