diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4a07ba380338fcfa07491fb665dfa166485f98e1..f6d4197d4a87b936be48dba94238c9d54bcfa2a6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -60,6 +60,33 @@ cta_rpm: tags: - docker +cta_rpm: + except: + - tags + stage: build:rpm + retry: 1 + image: gitlab-registry.cern.ch/linuxsupport/cc7-base + script: + - cp -f continuousintegration/docker/ctafrontend/cc7/etc/yum.repos.d/*.repo /etc/yum.repos.d/ + - yum install -y gcc-c++ cmake make rpm-build + - yum -y install yum-plugin-priorities yum-plugin-versionlock + - yum install -y git + - git submodule update --init --recursive + - cp -f continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list /etc/yum/pluginconf.d/ + - yum-builddep --nogpgcheck -y build_srpm/RPM/SRPMS/* + - mkdir build_rpm + - cd build_rpm + - cmake -DVCS_VERSION=${CTA_BUILD_ID} .. + - make cta_rpm + + artifacts: + expire_in: 30 days + paths: + - build_rpm/RPM/RPMS + + tags: + - docker + cta_tagged_rpm: only: - tags diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 61c68ce0ac1aeef96db89c970022d73f577d814f..078c2eaf7e631febd89ede318c4d15b33c1bc081 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -81,6 +81,7 @@ set (COMMON_LIB_SRC_FILES exception/DatabaseConstraintError.cpp exception/DatabasePrimaryKeyError.cpp exception/DismountFailed.cpp + exception/ForceDismountFailed.cpp exception/Errnum.cpp exception/Exception.cpp exception/InvalidArgument.cpp diff --git a/common/exception/ForceDismountFailed.cpp b/common/exception/ForceDismountFailed.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bbec96aafcfbe9d96ce5aacfbe41ecfa1abc3b3 --- /dev/null +++ b/common/exception/ForceDismountFailed.cpp @@ -0,0 +1,34 @@ +/****************************************************************************** + * + * 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 Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#include "ForceDismountFailed.hpp" +//#include "serrno.h" + + +// ----------------------------------------------------------------------------- +// Constructor +// ----------------------------------------------------------------------------- +cta::exception::ForceDismountFailed::ForceDismountFailed(): + cta::exception::Exception() { + //cta::exception::Exception(ETFDISMOUNTFAILED) { +} diff --git a/common/exception/ForceDismountFailed.hpp b/common/exception/ForceDismountFailed.hpp new file mode 100644 index 0000000000000000000000000000000000000000..2a05c62c12a23a50d9da5eef1106e57b2cd31aaf --- /dev/null +++ b/common/exception/ForceDismountFailed.hpp @@ -0,0 +1,47 @@ +/****************************************************************************** + * + * 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 Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#pragma once + +#include "Exception.hpp" + +namespace cta { +namespace exception { + +/** + * Failed to dismount volume. + */ +class ForceDismountFailed : public cta::exception::Exception { + +public: + + /** + * Constructor + */ + ForceDismountFailed(); + +}; // class ForceDismountFailed + +} // namespace exception +} // namespace cta + diff --git a/common/exception/QueryVolumeFailed.hpp b/common/exception/QueryVolumeFailed.hpp index 09236633356079b1dfc309f5e340e37d8b6a8502..0143eb78083137ebf5d7c5bbe72f87c5882ed3ab 100644 --- a/common/exception/QueryVolumeFailed.hpp +++ b/common/exception/QueryVolumeFailed.hpp @@ -41,5 +41,5 @@ namespace cta { namespace exception { }; // class QueryVolumeFailed -} } // namespace castor exception +} } // namespace cta exception diff --git a/common/log/IPAddress.hpp b/common/log/IPAddress.hpp new file mode 100644 index 0000000000000000000000000000000000000000..1beccda1fdcdaeb9db7267aaea0efcf36782b30d --- /dev/null +++ b/common/log/IPAddress.hpp @@ -0,0 +1,65 @@ +/****************************************************************************** + * + * 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. + * + * + * A simple object around an IP address + * + * @author Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#pragma once + +// Include Files +#include <ostream> + +namespace cta { + + namespace log { + + /** + * A simple object around an IP address + */ + class IPAddress { + + public: + + /** + * Constructor + */ + IPAddress(int ip) : m_ip(ip) {}; + + /** + * Accessor + */ + int ip() const { return m_ip; } + + private: + + /// the IP address, as an int + int m_ip; + + }; + + } // end of namespace log + +} // end of namespace cta + +/** + * non-member operator to stream an IpAdress + */ +std::ostream& operator<<(std::ostream& out, const cta::log::IPAddress& ip); diff --git a/common/log/TimeStamp.hpp b/common/log/TimeStamp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..3f13b957dc852936e646bf82b230072a184703b4 --- /dev/null +++ b/common/log/TimeStamp.hpp @@ -0,0 +1,67 @@ +/****************************************************************************** + * + * 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. + * + * + * A simple object around a time stamp + * + * @author Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#pragma once + +// Include Files +#include <time.h> +#include <ostream> + +namespace cta { + + namespace log { + + /** + * A simple object around a time stamp + */ + class TimeStamp { + + public: + + /** + * Constructor + */ + TimeStamp(time_t time) : m_time(time) {}; + + /** + * Accessor + */ + int time() const { return m_time; } + + private: + + /// the IP address, as an int + int m_time; + + }; + + } // end of namespace log + +} // end of namespace cta + + +/** + * non-member operator to stream an IpAdress + */ +std::ostream& operator<<(std::ostream& out, const cta::log::TimeStamp& ts); diff --git a/common/log/log.cpp b/common/log/log.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8f470019541d803626dd53ab8a007a46c332b1e --- /dev/null +++ b/common/log/log.cpp @@ -0,0 +1,122 @@ +/****************************************************************************** + * + * 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. + * + * + * Interface to the CASTOR logging system + * + * @author Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#include "castor/exception/Exception.hpp" +#include "castor/log/log.hpp" + +/** + * The logger to be used by the CASTOR logging systsem. + */ +static cta::log::Logger *s_logger = NULL; + +//------------------------------------------------------------------------------ +// init +//------------------------------------------------------------------------------ +void cta::log::init(cta::log::Logger *logger) { + if(s_logger) { + throw cta::exception::Exception("Failed to initialise logging system" + ": Logging system already initialised"); + } + + s_logger = logger; +} + +//------------------------------------------------------------------------------ +// shutdown +//------------------------------------------------------------------------------ +void cta::log::shutdown() { + delete s_logger; + s_logger = NULL; +} + +//------------------------------------------------------------------------------ +// instance +//------------------------------------------------------------------------------ +cta::log::Logger &cta::log::instance() { + if(NULL == s_logger) { + throw cta::exception::Exception("Failed to get CASTOR logger" + ": Logger does not exist"); + } + return *s_logger; +} + +//------------------------------------------------------------------------------ +// prepareForFork +//------------------------------------------------------------------------------ +void cta::log::prepareForFork() { + try { + instance().prepareForFork(); + } catch(cta::exception::Exception &ex) { + throw cta::exception::Exception( + std::string("Failed to prepare logger for call to fork(): ") + + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// write +//------------------------------------------------------------------------------ +void cta::log::write( + const int priority, + const std::string &msg, + const std::list<cta::log::Param> ¶ms) { + if(s_logger) (*s_logger)(priority, msg, params); +} + +//------------------------------------------------------------------------------ +// write +//------------------------------------------------------------------------------ +void cta::log::write( + const int priority, + const std::string &msg, + const std::string &rawParams, + const struct timeval &timeStamp, + const std::string &progName, + const int pid) { + const std::list<Param> params; + if(s_logger) (*s_logger)(priority, msg, params, rawParams, timeStamp, + progName, pid); +} + +//------------------------------------------------------------------------------ +// getProgramName +//------------------------------------------------------------------------------ +std::string cta::log::getProgramName() { + if(s_logger) { + return (*s_logger).getProgramName(); + } else { + return ""; + } +} + +//------------------------------------------------------------------------------ +// operator<< +//------------------------------------------------------------------------------ +std::ostream& operator<<(std::ostream& out, const Cuuid_t& uuid) { + char uuidstr[CUUID_STRING_LEN + 1]; + memset(uuidstr, '\0', CUUID_STRING_LEN + 1); + Cuuid2string(uuidstr, CUUID_STRING_LEN + 1, &uuid); + out << uuidstr; + return out; +} diff --git a/common/log/log.hpp b/common/log/log.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a5d57987bdd20df47a9aa2a8a71e25975401d90f --- /dev/null +++ b/common/log/log.hpp @@ -0,0 +1,129 @@ +/****************************************************************************** + * + * 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. + * + * + * Interface to the CASTOR logging system + * + * @author Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#pragma once + +#include "Logger.hpp" +#include "common/log/Param.hpp" +#include "common/log/IPAddress.hpp" +#include "common/log/TimeStamp.hpp" +//#include "common/Cuuid.h" + +#include <list> +#include <syslog.h> +#include <sys/time.h> + +// more meaningful alias to NOTICE log level +#define LOG_USER_ERROR LOG_NOTICE + +namespace cta { +namespace log { + + /** + * Initialises the logging system with the specified logger which should be + * allocated on the heap and will be owned by the logging system; + * + * This method is not thread safe. + * + * @logger The logger to be used by the logging system. + */ + void init(cta::log::Logger *logger); + + /** + * Deallocates the logger. + * + * This method is not thread safe. + */ + void shutdown(); + + /** + * Returns a reference to the logger if it exists else throws an exception. + */ + Logger &instance(); + + /** + * Prepares the logger object for a call to fork(). + * + * No further calls to operator() should be made after calling this + * method until the call to fork() has completed. + */ + void prepareForFork(); + + /** + * Writes a message into the CASTOR logging system. Note that no exception + * will ever be thrown in case of failure. Failures will actually be + * silently ignored in order to not impact the processing. + * + * Note that this version of write() implicitly uses the current time as + * the time stamp of the message. + * + * @param priority the priority of the message as defined by the syslog API. + * @param msg the message. + * @param params optionally the parameters of the message. + */ + void write( + const int priority, + const std::string &msg, + const std::list<cta::log::Param> ¶ms = + std::list<cta::log::Param>()); + + /** + * Writes a message into the CASTOR logging system. Note that no exception + * will ever be thrown in case of failure. Failures will actually be + * silently ignored in order to not impact the processing. + * + * Note that this version of write() is very specific and should not be + * used for general purpose. It allows the caller to specify the + * time stamp, the program name and the pid of the log message and + * takes preprocessed param + * + * @param priority the priority of the message as defined by the syslog API. + * @param msg the message. + * @param rawParams preprocessed parameters of the message. + * @param timeStamp the time stamp of the log message. + * @param progName the program name of the log message. + * @param pid the pid of the log message. + */ + void write( + const int priority, + const std::string &msg, + const std::string &rawParams, + const struct timeval &timeStamp, + const std::string &progName, + const int pid); + + /** + * Returns the program name if known or the empty string if not. + * + * @return the program name if known or the empty string if not. + */ + std::string getProgramName(); + +} // namespace log +} // namespace cta + +/** + * non-member operator to stream a Cuuid_t + */ +//////std::ostream& operator<<(std::ostream& out, const Cuuid_t& uuid); diff --git a/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list b/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list index 9e7419eb1244605cf20d156482e2fbdb27ebf3c0..5184943b86b96e5a3f30f9d02fc05eabd9d337a5 100644 --- a/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list +++ b/continuousintegration/docker/ctafrontend/cc7/etc/yum/pluginconf.d/versionlock.list @@ -1,17 +1,17 @@ -0:eos-archive-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-cleanup-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-client-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-debuginfo-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-fuse-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-fuse-core-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-fuse-sysv-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-fusex-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-fusex-core-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-fusex-selinux-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-server-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-srm-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-test-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 -0:eos-testkeytab-4.2.23-20180607211817gitc44922b.el7.cern.x86_64 +0:eos-archive-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-cleanup-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-client-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-debuginfo-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-fuse-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-fuse-core-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-fuse-sysv-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-fusex-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-fusex-core-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-fusex-selinux-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-server-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-srm-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-test-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 +0:eos-testkeytab-4.2.23-20180611183432git48f0e54.el7.cern.x86_64 1:python2-xrootd-4.8.2-1.el7.* 1:python3-xrootd-4.8.2-1.el7.* 1:xrootd-4.8.2-1.el7.* diff --git a/cta.spec.in b/cta.spec.in index 8bd5052bf36479121b2dc105c7dea5c2cb562395..9240065686b1ddb10897ff710557e316ff747ef6 100644 --- a/cta.spec.in +++ b/cta.spec.in @@ -105,16 +105,13 @@ cd build Summary: CERN Tape Archive: tape daemon Group: Application/CTA Requires: logrotate +Requires: cta-common = %{version}-%{release} Requires: cta-lib = %{version}-%{release} -Requires(pre): /usr/bin/getent, /usr/sbin/groupadd, /usr/sbin/useradd %description -n cta-taped CERN Tape Archive: The tape server daemon -%pre -n cta-taped -/usr/bin/getent passwd cta || /usr/sbin/useradd -s /bin/nologin -c "CTA system account" -g tape cta %files -n cta-taped %defattr(-,root,root) -%attr(0755,cta,cta) %dir /var/log/cta %attr(0644,root,root) %config(noreplace) /etc/logrotate.d/cta-taped %attr(0755,root,root) %{_bindir}/cta-taped %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cta/cta-taped.conf.example @@ -138,21 +135,18 @@ The tape server daemon Summary: CERN Tape Archive: Xrootd plugin Group: Application/CTA Requires: logrotate +Requires: cta-common = %{version}-%{release} Requires: cta-lib = %{version}-%{release} Requires: xrootd-server -Requires(pre): /usr/bin/getent, /usr/sbin/groupadd, /usr/sbin/useradd %description -n cta-frontend CERN Tape Archive: The xroot plugin -%pre -n cta-frontend -/usr/bin/getent passwd cta || /usr/sbin/useradd -s /bin/nologin -c "CTA system account" -g tape cta %files -n cta-frontend %defattr(0755,root,root) %{_libdir}/libXrdSsiCta.so* -%attr(0755,cta,cta) %dir /var/log/cta %attr(0644,root,root) %config(noreplace) /etc/logrotate.d/cta-frontend %attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cta/cta-frontend-xrootd.conf -%attr(0644,cta,cta) /etc/systemd/system/cta-frontend.service +%attr(0644,cta,tape) /etc/systemd/system/cta-frontend.service #Frontend installs libraries so we need ldconfig. %post -n cta-frontend @@ -212,6 +206,7 @@ The shared libraries Summary: CERN Tape Archive: unit and system tests with virtual tape drives Group: Application/CTA Requires: valgrind >= 3.8.1 +Requires: cta-lib = %{version}-%{release} Requires: cta-taped = %{ctaVersion}-%{ctaRelease}%{mydist} Requires: make %description -n cta-systemtests @@ -241,6 +236,7 @@ Unit tests and system tests with virtual tape drives %{_libdir}/libctatapeserverscsiunittests.so* %{_libdir}/libctadaemonunittests.so* %{_libdir}/libctamediachangerunittests.so* +%{_libdir}/libctamediachangeracsdaemonunittests.so* %{_bindir}/cta-systemTests %{_libdir}/libctadaemonunittests-multiprocess.so* %attr(0644,root,root) %{_datadir}/%{name}-%{ctaVersion}/unittest/*.suppr @@ -249,6 +245,7 @@ Unit tests and system tests with virtual tape drives %package -n cta-objectstore-tools Summary: CERN Tape Archive: object store tools Group: Application/CTA +Requires: cta-lib = %{version}-%{release} %description -n cta-objectstore-tools CERN Tape Archive: Tools allowing initialization and inspection of the object store. @@ -267,6 +264,7 @@ Tools allowing initialization and inspection of the object store. %package -n cta-catalogueutils Summary: Utilities to faciliate working with the CTA catalogue Group: Application/CTA +Requires: cta-lib = %{version}-%{release} %description -n cta-catalogueutils CERN Tape Archive: Scripts and utilities to faciliate working with the CTA catalogue @@ -285,6 +283,7 @@ Scripts and utilities to faciliate working with the CTA catalogue %package -n cta-mediachangerutils Summary: Utilities to faciliate working with mediachangers Group: Application/CTA +Requires: cta-lib = %{version}-%{release} %description -n cta-mediachangerutils CERN Tape Archive: Utilities to faciliate working with the mediachangers @@ -294,21 +293,45 @@ Utilities to faciliate working with the mediachangers %attr(0644,root,root) %doc /usr/share/man/man1/cta-mediachanger-dismount.1cta.gz %attr(0644,root,root) %doc /usr/share/man/man1/cta-mediachanger-mount.1cta.gz +%package -n cta-acsd +Summary: Tools to faciliate working with acsd in cta +Group: Application/CTA +Requires: logrotate +Requires: cta-common = %{version}-%{release} +Requires: cta-lib = %{version}-%{release} +%description -n cta-acsd +CERN Tape Archive: +Tools to faciliate working with acsd in cta +%files -n cta-acsd +%defattr(-,root,root) +%attr(0644,root,root) %config(noreplace) /etc/logrotate.d/cta-acsd +#%attr(0644,root,root) %doc /usr/share/man/man1/cta-acsd.1cta.gz +%attr(0755,root,root) %{_bindir}/cta-acsd +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/cta/cta-acsd.conf +%attr(0644,root,root) %config(noreplace) /etc/sysconfig/cta-acsd +%attr(0644,root,root) /etc/systemd/system/cta-acsd.service + +%post -n cta-acsd +%systemd_post cta-acsd.service +%systemdDaemonReload + +%preun -n cta-acsd +%systemd_preun cta-acsd.service + +%postun -n cta-acsd +%systemd_postun cta-acsd.service +%systemdDaemonReload %package -n cta-rmcd Summary: Tools to faciliate working with rmcd and smc in cta Group: Application/CTA Requires: logrotate -#Requires: cta-lib = %{version}-%{release} -Requires(pre): /usr/bin/getent, /usr/sbin/groupadd, /usr/sbin/useradd +Requires: cta-common = %{version}-%{release} %description -n cta-rmcd CERN Tape Archive: Tools to faciliate working with rmcd and smc in cta -%pre -n cta-rmcd -/usr/bin/getent passwd cta || /usr/sbin/useradd -s /bin/nologin -c "CTA system account" -g tape cta %files -n cta-rmcd %defattr(-,root,root) -%attr(0755,cta,cta) %dir /var/log/cta %attr(0644,root,root) %config(noreplace) /etc/logrotate.d/cta-rmcd %attr(0644,root,root) %doc /usr/share/man/man1/cta-rmcd.1cta.gz %attr(0755,root,root) %{_bindir}/cta-rmcd @@ -344,6 +367,20 @@ castor (Cern Advanced STORage system) %attr(0755,root,root) /usr/bin/cta-tape-acs-queryvolume %attr(0755,root,root) /usr/bin/cta-tape-acs-dismount %attr(0755,root,root) /usr/bin/cta-tape-acs-mount +%attr(0755,root,root) /usr/bin/cta-tape-acs-querydrive %attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-acs-queryvolume.1cta.gz %attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-acs-mount.1cta.gz %attr(0644,root,root) %doc /usr/share/man/man1/cta-tape-acs-dismount.1cta.gz + +%package -n cta-common +Summary: CERN Tape Archive common items +Group: Application/CTA +Requires(pre): /usr/bin/egrep, /usr/sbin/groupadd, /usr/sbin/luseradd +%description -n cta-common +CERN Tape Archive: +Common items such as the creation of the cta local user and /var/log/cta +%pre -n cta-common +/usr/bin/egrep -q '^cta:' /etc/passwd || /usr/sbin/luseradd -s /bin/nologin -c "CTA system account" -g tape cta +%files -n cta-common +%defattr(-,root,root) +%attr(0755,cta,tape) %dir /var/log/cta diff --git a/mediachanger/AcsProxy.cpp b/mediachanger/AcsProxy.cpp index 0244934662ac47d304fb548b05715e44210969df..cb5ec8cd8a0a10cab51a21a86fbc67b32dfd9ef4 100644 --- a/mediachanger/AcsProxy.cpp +++ b/mediachanger/AcsProxy.cpp @@ -197,7 +197,7 @@ void AcsProxy::mountTapeReadOnly(const std::string &vid, const LibrarySlot &libr } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << - "Failed to request CASTOR ACS daemon to mount tape for read only access: " + "Failed to request CTA ACS daemon to mount tape for read only access: " << librarySlot.str() << ": " << ne.getMessage().str(); throw ex; } @@ -225,7 +225,7 @@ void AcsProxy::mountTapeReadWrite(const std::string &vid, const LibrarySlot &lib } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << - "Failed to request CASTOR ACS daemon to mount tape for read/write " + "Failed to request CTA ACS daemon to mount tape for read/write " "access: " << librarySlot.str() << ": " << ne.getMessage().str(); throw ex; } @@ -253,7 +253,7 @@ void AcsProxy::dismountTape(const std::string &vid, const LibrarySlot &librarySl } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << - "Failed to request CASTOR ACS daemon to dismount tape: " << + "Failed to request CTA ACS daemon to dismount tape: " << librarySlot.str() << ": " << ne.getMessage().str(); throw ex; } @@ -281,7 +281,7 @@ void AcsProxy::forceDismountTape(const std::string &vid, const LibrarySlot &libr } catch(cta::exception::Exception &ne) { cta::exception::Exception ex; ex.getMessage() << - "Failed to request CASTOR ACS daemon to force dismount tape: " << + "Failed to request CTA ACS daemon to force dismount tape: " << librarySlot.str() << ": " << ne.getMessage().str(); throw ex; } diff --git a/mediachanger/CMakeLists.txt b/mediachanger/CMakeLists.txt index 08602fd97f394e85084c5c44eb26462627ae2140..f5f23d67918edabb458d06d250fd055a93066b36 100644 --- a/mediachanger/CMakeLists.txt +++ b/mediachanger/CMakeLists.txt @@ -16,6 +16,7 @@ cmake_minimum_required (VERSION 2.6) add_subdirectory(acs) +add_subdirectory(reactor) add_subdirectory(castorrmc) find_package(openssl REQUIRED) find_package(Protobuf3 REQUIRED) diff --git a/mediachanger/Exception.proto b/mediachanger/Exception.proto new file mode 100644 index 0000000000000000000000000000000000000000..fd88601083069582cf39247d4df76ebee674a35b --- /dev/null +++ b/mediachanger/Exception.proto @@ -0,0 +1,27 @@ +// 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 Castor Dev team, castor-dev@cern.ch +syntax = "proto2"; +package cta.mediachanger; + +message Exception { + // The error code + required uint32 code = 1; + + // The error message + required string message = 2; +} diff --git a/mediachanger/ReturnValue.proto b/mediachanger/ReturnValue.proto new file mode 100644 index 0000000000000000000000000000000000000000..4f34c3ffbaab132f1f81ebc51caf90ccaa1dfd67 --- /dev/null +++ b/mediachanger/ReturnValue.proto @@ -0,0 +1,23 @@ +// 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 Castor Dev team, castor-dev@cern.ch +syntax = "proto2"; +package cta.mediachanger; + +message ReturnValue { + required uint32 value = 1; +} diff --git a/mediachanger/acs/Acs.cpp b/mediachanger/acs/Acs.cpp index d35112c3d43bcfd77324b3adc01521bb7ec2a451..ad7d46ba01c2a441edfdbe919c2badc0acfebae0 100644 --- a/mediachanger/acs/Acs.cpp +++ b/mediachanger/acs/Acs.cpp @@ -27,13 +27,13 @@ //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::Acs::~Acs() throw() { +cta::mediachanger::acs::Acs::~Acs() throw() { } //------------------------------------------------------------------------------ // str2DriveId //------------------------------------------------------------------------------ -DRIVEID cta::acs::Acs::str2DriveId(const std::string &str) { +DRIVEID cta::mediachanger::acs::Acs::str2DriveId(const std::string &str) { std::vector<std::string> components; cta::utils::splitString(str, ':', components); @@ -112,7 +112,7 @@ DRIVEID cta::acs::Acs::str2DriveId(const std::string &str) { //------------------------------------------------------------------------------ // onlyContainsNumerals //------------------------------------------------------------------------------ -bool cta::acs::Acs::onlyContainsNumerals(const std::string &str) throw() { +bool cta::mediachanger::acs::Acs::onlyContainsNumerals(const std::string &str) throw() { for(std::string::const_iterator itor = str.begin(); itor != str.end(); itor++) { if(*itor < '0' || *itor > '9') { @@ -125,7 +125,7 @@ bool cta::acs::Acs::onlyContainsNumerals(const std::string &str) throw() { //------------------------------------------------------------------------------ // alpd2DriveId //------------------------------------------------------------------------------ -DRIVEID cta::acs::Acs::alpd2DriveId(const uint32_t acs, +DRIVEID cta::mediachanger::acs::Acs::alpd2DriveId(const uint32_t acs, const uint32_t lsm, const uint32_t panel, const uint32_t drive) throw () { DRIVEID driveId; @@ -140,7 +140,7 @@ DRIVEID cta::acs::Acs::alpd2DriveId(const uint32_t acs, //------------------------------------------------------------------------------ // str2Volid //------------------------------------------------------------------------------ -VOLID cta::acs::Acs::str2Volid(const std::string &str) { +VOLID cta::mediachanger::acs::Acs::str2Volid(const std::string &str) { if(EXTERNAL_LABEL_SIZE < str.length()) { cta::exception::InvalidArgument ex; ex.getMessage() << "Failed to convert string to volume identifier" @@ -158,7 +158,7 @@ VOLID cta::acs::Acs::str2Volid(const std::string &str) { //------------------------------------------------------------------------------ // driveId2Str //------------------------------------------------------------------------------ -std::string cta::acs::Acs::driveId2Str(const DRIVEID &driveId) throw() { +std::string cta::mediachanger::acs::Acs::driveId2Str(const DRIVEID &driveId) throw() { std::ostringstream oss; oss << std::setfill('0') << std::setw(3) << (int32_t)driveId.panel_id.lsm_id.acs << ":" << diff --git a/mediachanger/acs/Acs.hpp b/mediachanger/acs/Acs.hpp index 33952de09a2eb618f285371592be3e3a4a69cc2b..bdd79bc01cca482b70cfff0f45796620ba851193 100644 --- a/mediachanger/acs/Acs.hpp +++ b/mediachanger/acs/Acs.hpp @@ -28,6 +28,7 @@ extern "C" { #include <stdint.h> namespace cta { +namespace mediachanger { namespace acs { /** @@ -176,4 +177,5 @@ protected: }; // class Acs } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsCmd.cpp b/mediachanger/acs/AcsCmd.cpp index 4841fa2560431714f34efb7fd6da7a8ffa903367..83e1ea28bd83626af88d14bb549f101eabd344f1 100644 --- a/mediachanger/acs/AcsCmd.cpp +++ b/mediachanger/acs/AcsCmd.cpp @@ -23,7 +23,7 @@ //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsCmd::AcsCmd(std::istream &inStream, +cta::mediachanger::acs::AcsCmd::AcsCmd(std::istream &inStream, std::ostream &outStream, std::ostream &errStream, Acs &acs) throw(): CmdLineTool(inStream, outStream, errStream), m_acs(acs) { } @@ -31,13 +31,13 @@ cta::acs::AcsCmd::AcsCmd(std::istream &inStream, //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::AcsCmd::~AcsCmd() throw() { +cta::mediachanger::acs::AcsCmd::~AcsCmd() throw() { } //------------------------------------------------------------------------------ // bool2Str //------------------------------------------------------------------------------ -std::string cta::acs::AcsCmd::bool2Str(const BOOLEAN value) const +std::string cta::mediachanger::acs::AcsCmd::bool2Str(const BOOLEAN value) const throw() { return value ? "TRUE" : "FALSE"; } @@ -45,7 +45,7 @@ std::string cta::acs::AcsCmd::bool2Str(const BOOLEAN value) const //------------------------------------------------------------------------------ // requestResponsesUntilFinal //------------------------------------------------------------------------------ -void cta::acs::AcsCmd::requestResponsesUntilFinal( +void cta::mediachanger::acs::AcsCmd::requestResponsesUntilFinal( const SEQ_NO requestSeqNumber, ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)], const int queryInterval, const int timeout) { @@ -77,7 +77,7 @@ void cta::acs::AcsCmd::requestResponsesUntilFinal( //------------------------------------------------------------------------------ // requestResponse //------------------------------------------------------------------------------ -ACS_RESPONSE_TYPE cta::acs::AcsCmd::requestResponse( +ACS_RESPONSE_TYPE cta::mediachanger::acs::AcsCmd::requestResponse( const int timeout, const SEQ_NO requestSeqNumber, ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) { SEQ_NO responseSeqNumber = 0; @@ -105,7 +105,7 @@ ACS_RESPONSE_TYPE cta::acs::AcsCmd::requestResponse( //------------------------------------------------------------------------------ // checkSeqNumber //------------------------------------------------------------------------------ -void cta::acs::AcsCmd::checkResponseSeqNumber( const SEQ_NO requestSeqNumber, const SEQ_NO responseSeqNumber) { +void cta::mediachanger::acs::AcsCmd::checkResponseSeqNumber( const SEQ_NO requestSeqNumber, const SEQ_NO responseSeqNumber) { if(requestSeqNumber != responseSeqNumber) { cta::exception::Mismatch ex; ex.getMessage() << ": Sequence number mismatch: requestSeqNumber=" diff --git a/mediachanger/acs/AcsCmd.hpp b/mediachanger/acs/AcsCmd.hpp index 744a62bab35af862cd5eace4a7085b50b7d5fcbf..b57be3ab56e6c74b8edf8e76e6a1c7fffeb67b55 100644 --- a/mediachanger/acs/AcsCmd.hpp +++ b/mediachanger/acs/AcsCmd.hpp @@ -36,6 +36,7 @@ extern "C" { } namespace cta { +namespace mediachanger { namespace acs { /** @@ -118,4 +119,5 @@ protected: }; // class AcsCmd } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsCmdLine.cpp b/mediachanger/acs/AcsCmdLine.cpp index 1c4998166d7f12fe864760945b2c6e8f1ae3fb3b..9391a54256e0b286ca55f2ec990e5a400b34f3c1 100644 --- a/mediachanger/acs/AcsCmdLine.cpp +++ b/mediachanger/acs/AcsCmdLine.cpp @@ -26,7 +26,7 @@ //------------------------------------------------------------------------------ // parseQueryInterval //------------------------------------------------------------------------------ -int cta::acs::AcsCmdLine::parseQueryInterval(const std::string &s) { +int cta::mediachanger::acs::AcsCmdLine::parseQueryInterval(const std::string &s) { const int queryInterval = atoi(s.c_str()); if(0 >= queryInterval) { cta::exception::InvalidArgument ex; @@ -41,7 +41,7 @@ int cta::acs::AcsCmdLine::parseQueryInterval(const std::string &s) { //------------------------------------------------------------------------------ // parseTimeout //------------------------------------------------------------------------------ -int cta::acs::AcsCmdLine::parseTimeout(const std::string &s) { +int cta::mediachanger::acs::AcsCmdLine::parseTimeout(const std::string &s) { const int timeout = atoi(s.c_str()); if(0 >= timeout) { cta::exception::InvalidArgument ex; @@ -55,7 +55,7 @@ int cta::acs::AcsCmdLine::parseTimeout(const std::string &s) { //------------------------------------------------------------------------------ // handleMissingParameter //------------------------------------------------------------------------------ -void cta::acs::AcsCmdLine::handleMissingParameter(const int opt) { +void cta::mediachanger::acs::AcsCmdLine::handleMissingParameter(const int opt) { cta::exception::MissingOperand ex; ex.getMessage() << "The -" << (char)opt << " option requires a parameter"; throw ex; @@ -64,7 +64,7 @@ void cta::acs::AcsCmdLine::handleMissingParameter(const int opt) { //------------------------------------------------------------------------------ // handleUnknownOption //------------------------------------------------------------------------------ -void cta::acs::AcsCmdLine::handleUnknownOption(const int opt) { +void cta::mediachanger::acs::AcsCmdLine::handleUnknownOption(const int opt) { cta::exception::InvalidArgument ex; if(0 == optopt) { ex.getMessage() << "Unknown command-line option"; diff --git a/mediachanger/acs/AcsCmdLine.hpp b/mediachanger/acs/AcsCmdLine.hpp index 26455c6c02eabc3088e1a5731d729f50f106dac0..6fc41f90a62b6e7eea0ee619e18001edce3f237f 100644 --- a/mediachanger/acs/AcsCmdLine.hpp +++ b/mediachanger/acs/AcsCmdLine.hpp @@ -21,6 +21,7 @@ #include <string> namespace cta { +namespace mediachanger { namespace acs { /** @@ -61,4 +62,5 @@ protected: }; // class AcsCmdLine } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsDebugBuf.cpp b/mediachanger/acs/AcsDebugBuf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..850c0426bbd6b29d74ace92778524d1cb1f28c46 --- /dev/null +++ b/mediachanger/acs/AcsDebugBuf.cpp @@ -0,0 +1,69 @@ +/* + * 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 "mediachanger/acs/AcsDebugBuf.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::DebugBuf::DebugBuf(std::ostream &os): + m_debug(false), m_os(os), m_writePreamble(true) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::DebugBuf::~DebugBuf() { +} + +//------------------------------------------------------------------------------ +// setDebug +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::DebugBuf::setDebug(const bool value) throw() { + m_debug = value; +} + +//------------------------------------------------------------------------------ +// overflow +//------------------------------------------------------------------------------ +std::streambuf::int_type cta::mediachanger::acs::DebugBuf::overflow( + const int_type c) { + // Only write something if debug mode is on + if(m_debug) { + if(m_writePreamble) { + writePreamble(); + m_writePreamble = false; + } + m_os << (char)c; + } + + // If an end of line was encountered then the next write should be preceeded + // with a preamble + if('\n' == (char)c) { + m_writePreamble = true; + } + + return c; +} + +//------------------------------------------------------------------------------ +// writePreamble +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::DebugBuf::writePreamble() throw() { + m_os << "DEBUG: "; +} diff --git a/mediachanger/acs/AcsDebugBuf.hpp b/mediachanger/acs/AcsDebugBuf.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c219337c093ec2b102f01bc79d109c8b1354f1b0 --- /dev/null +++ b/mediachanger/acs/AcsDebugBuf.hpp @@ -0,0 +1,95 @@ +/* + * 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 <ostream> +#include <streambuf> + +namespace cta { +namespace mediachanger { +namespace acs { + +/** + * Stream buffer class used to prepend a standard preamble to debug + * message-lines. + * + * This stream buffer does not write any output if debug mode has not been + * turned on by calling setDebugMode(true). Any debug message written to this + * stream buffer will be discarded if debug mode is off. + */ +class DebugBuf : public std::streambuf { +public: + + /** + * Constructor. + * + * Initialises the the debug mode to be off. + * + * @param os The output stream to which each debug message-line togther with + * its standard preamble shall be written. + */ + DebugBuf(std::ostream &os); + + /** + * Destructor. + */ + ~DebugBuf(); + + /** + * Set the debug mode to be on (true) or off (false). + * + * The default set in the constructor is off (false). + */ + void setDebug(const bool value) throw(); + +protected: + + /** + * Sends the specified character to the output channnel. + */ + int_type overflow (const int_type c); + + /** + * Writes the standard preamble to the output stream. + */ + void writePreamble() throw(); + +private: + + /** + * True if debug mode is on. + */ + bool m_debug; + + /** + * The output stream to which each debug message-line togther with its + * standard preamble shall be written. + */ + std::ostream &m_os; + + /** + * True is a preamble should be written. + */ + bool m_writePreamble; + +}; // class DebugBuf + +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/AcsDismountCmd.cpp b/mediachanger/acs/AcsDismountCmd.cpp index ede15c6d11c193cb4e2c643484953106a93732e5..209c5ece179cdfa62e5a8daf28c83b1f61364f4c 100644 --- a/mediachanger/acs/AcsDismountCmd.cpp +++ b/mediachanger/acs/AcsDismountCmd.cpp @@ -23,7 +23,7 @@ //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsDismountCmd::AcsDismountCmd( +cta::mediachanger::acs::AcsDismountCmd::AcsDismountCmd( std::istream &inStream, std::ostream &outStream, std::ostream &errStream, Acs &acs) throw(): AcsCmd(inStream, outStream, errStream, acs) { @@ -32,14 +32,14 @@ cta::acs::AcsDismountCmd::AcsDismountCmd( //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::AcsDismountCmd::~AcsDismountCmd() throw() { +cta::mediachanger::acs::AcsDismountCmd::~AcsDismountCmd() throw() { // Do nothing } //------------------------------------------------------------------------------ // exceptionThrowingMain //------------------------------------------------------------------------------ -int cta::acs::AcsDismountCmd::exceptionThrowingMain(const int argc, +int cta::mediachanger::acs::AcsDismountCmd::exceptionThrowingMain(const int argc, char *const *const argv) { try { m_cmdLine = AcsDismountCmdLine(argc, argv); @@ -74,7 +74,7 @@ int cta::acs::AcsDismountCmd::exceptionThrowingMain(const int argc, //------------------------------------------------------------------------------ // syncDismount //------------------------------------------------------------------------------ -void cta::acs::AcsDismountCmd::syncDismount() { +void cta::mediachanger::acs::AcsDismountCmd::syncDismount() { const SEQ_NO requestSeqNumber = 1; ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; @@ -94,7 +94,7 @@ void cta::acs::AcsDismountCmd::syncDismount() { //------------------------------------------------------------------------------ // sendDismountRequest //------------------------------------------------------------------------------ -void cta::acs::AcsDismountCmd::sendDismountRequest( +void cta::mediachanger::acs::AcsDismountCmd::sendDismountRequest( const SEQ_NO seqNumber) { const LOCKID lockId = 0; // No lock @@ -115,7 +115,7 @@ void cta::acs::AcsDismountCmd::sendDismountRequest( //------------------------------------------------------------------------------ // processDismountResponse //------------------------------------------------------------------------------ -void cta::acs::AcsDismountCmd::processDismountResponse( +void cta::mediachanger::acs::AcsDismountCmd::processDismountResponse( ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) { const ACS_DISMOUNT_RESPONSE *const msg = (ACS_DISMOUNT_RESPONSE *)buf; diff --git a/mediachanger/acs/AcsDismountCmd.hpp b/mediachanger/acs/AcsDismountCmd.hpp index 3a9bb88f7e92fd0d4297383ea55b1c584c626831..e0db21b5d9afeb786cc86cdf5c9620f32a2d066b 100644 --- a/mediachanger/acs/AcsDismountCmd.hpp +++ b/mediachanger/acs/AcsDismountCmd.hpp @@ -25,6 +25,7 @@ #include "common/exception/MissingOperand.hpp" namespace cta { +namespace mediachanger { namespace acs { /** @@ -104,4 +105,5 @@ private: }; // class AcsDismountCmd } // namespace acs +} // namepace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsDismountCmdLine.cpp b/mediachanger/acs/AcsDismountCmdLine.cpp index 78668fd819bbf5d7373e391af9f4acdce33a2e98..cd37067422e81186dd7b06911be933d3596b3c68 100644 --- a/mediachanger/acs/AcsDismountCmdLine.cpp +++ b/mediachanger/acs/AcsDismountCmdLine.cpp @@ -30,7 +30,7 @@ //----------------------------------------------------------------------------- // constructor //----------------------------------------------------------------------------- -cta::acs::AcsDismountCmdLine::AcsDismountCmdLine() throw(): +cta::mediachanger::acs::AcsDismountCmdLine::AcsDismountCmdLine() throw(): debug(false), force(FALSE), help(false), @@ -46,7 +46,7 @@ cta::acs::AcsDismountCmdLine::AcsDismountCmdLine() throw(): //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsDismountCmdLine::AcsDismountCmdLine(const int argc, +cta::mediachanger::acs::AcsDismountCmdLine::AcsDismountCmdLine(const int argc, char *const *const argv): debug(false), force(FALSE), @@ -108,7 +108,7 @@ cta::acs::AcsDismountCmdLine::AcsDismountCmdLine(const int argc, //------------------------------------------------------------------------------ // processOption //------------------------------------------------------------------------------ -void cta::acs::AcsDismountCmdLine::processOption(const int opt) { +void cta::mediachanger::acs::AcsDismountCmdLine::processOption(const int opt) { switch (opt) { case 'd': debug = true; @@ -143,7 +143,7 @@ void cta::acs::AcsDismountCmdLine::processOption(const int opt) { //------------------------------------------------------------------------------ // getUsage //------------------------------------------------------------------------------ -std::string cta::acs::AcsDismountCmdLine::getUsage() throw() { +std::string cta::mediachanger::acs::AcsDismountCmdLine::getUsage() throw() { std::ostringstream usage; usage << "Usage:\n" diff --git a/mediachanger/acs/AcsDismountCmdLine.hpp b/mediachanger/acs/AcsDismountCmdLine.hpp index 373955eb64aa007d6a2cce2b8e39f4033d98fdcd..c07f2a35225758e8f72d0c45507dcad2ca61f96b 100644 --- a/mediachanger/acs/AcsDismountCmdLine.hpp +++ b/mediachanger/acs/AcsDismountCmdLine.hpp @@ -28,6 +28,7 @@ extern "C" { #include <string> namespace cta { +namespace mediachanger { namespace acs { /** @@ -109,4 +110,5 @@ private: }; // class AcsDismountCmdLine } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsDismountCmdMain.cpp b/mediachanger/acs/AcsDismountCmdMain.cpp index cacd1534b6d1b92ae2bfba40d53c4489c6224bda..b01f3cf3886a472f4d58dfd09cd715ff78171d3c 100644 --- a/mediachanger/acs/AcsDismountCmdMain.cpp +++ b/mediachanger/acs/AcsDismountCmdMain.cpp @@ -62,8 +62,8 @@ int main(const int argc, char *const *const argv) { static int exceptionThrowingMain(const int argc, char *const *const argv) { using namespace cta; - acs::AcsImpl acs; - acs::AcsDismountCmd cmd(std::cin, std::cout, std::cerr, acs); + mediachanger::acs::AcsImpl acs; + mediachanger::acs::AcsDismountCmd cmd(std::cin, std::cout, std::cerr, acs); return cmd.exceptionThrowingMain(argc, argv); } diff --git a/mediachanger/acs/AcsImpl.cpp b/mediachanger/acs/AcsImpl.cpp index 3aa961b099c3188587e05a82e5f4e8b05a35536b..7ecf0aa8fc0970566f96d12188c6ef060905ed71 100644 --- a/mediachanger/acs/AcsImpl.cpp +++ b/mediachanger/acs/AcsImpl.cpp @@ -25,13 +25,13 @@ //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::AcsImpl::~AcsImpl() throw() { +cta::mediachanger::acs::AcsImpl::~AcsImpl() throw() { } //------------------------------------------------------------------------------ // mount //------------------------------------------------------------------------------ -STATUS cta::acs::AcsImpl::mount( +STATUS cta::mediachanger::acs::AcsImpl::mount( const SEQ_NO seqNumber, const LOCKID lockId, const VOLID &volId, @@ -45,7 +45,7 @@ STATUS cta::acs::AcsImpl::mount( //------------------------------------------------------------------------------ // dismount //------------------------------------------------------------------------------ -STATUS cta::acs::AcsImpl::dismount( +STATUS cta::mediachanger::acs::AcsImpl::dismount( const SEQ_NO seqNumber, const LOCKID lockId, const VOLID &volId, @@ -58,7 +58,7 @@ STATUS cta::acs::AcsImpl::dismount( //------------------------------------------------------------------------------ // response //------------------------------------------------------------------------------ -STATUS cta::acs::AcsImpl::response( +STATUS cta::mediachanger::acs::AcsImpl::response( const int timeout, SEQ_NO &seqNumber, REQ_ID &reqId, @@ -70,7 +70,7 @@ STATUS cta::acs::AcsImpl::response( //------------------------------------------------------------------------------ // queryVolume //------------------------------------------------------------------------------ -STATUS cta::acs::AcsImpl::queryVolume( +STATUS cta::mediachanger::acs::AcsImpl::queryVolume( const SEQ_NO seqNumber, VOLID (&volIds)[MAX_ID], const unsigned short count) throw() { diff --git a/mediachanger/acs/AcsImpl.hpp b/mediachanger/acs/AcsImpl.hpp index 7adcb117a003879dc4e0719618680a83b59e7893..3fd93dcc1a7d7f63eb96fc38c900d840c1abb12c 100644 --- a/mediachanger/acs/AcsImpl.hpp +++ b/mediachanger/acs/AcsImpl.hpp @@ -21,6 +21,7 @@ #include "Acs.hpp" namespace cta { +namespace mediachanger { namespace acs { /** @@ -114,4 +115,5 @@ public: }; // class AcsImpl } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsLibraryInteraction.cpp b/mediachanger/acs/AcsLibraryInteraction.cpp index c311ad9eef824e4e2e6b18eee25808e30da82a65..2cf7377ce89d79369dfc3e26d5669fd749604bac 100644 --- a/mediachanger/acs/AcsLibraryInteraction.cpp +++ b/mediachanger/acs/AcsLibraryInteraction.cpp @@ -18,28 +18,28 @@ */ #include "AcsLibraryInteraction.hpp" -#include "../../log.hpp" +#include "common/log/log.hpp" #include <stdlib.h> //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsLibraryInteraction::AcsLibraryInteraction( - Acs &acs) throw(): m_acs(acs) { +cta::mediachanger::acs::AcsLibraryInteraction::AcsLibraryInteraction( + Acs &acs, cta::log::Logger& log) throw(): m_acs(acs), m_log(log) { } //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::AcsLibraryInteraction::~AcsLibraryInteraction() throw() { +cta::mediachanger::acs::AcsLibraryInteraction::~AcsLibraryInteraction() throw() { } //------------------------------------------------------------------------------ // requestResponsesUntilFinal //------------------------------------------------------------------------------ -void cta::acs::AcsLibraryInteraction::requestResponsesUntilFinal( +void cta::mediachanger::acs::AcsLibraryInteraction::requestResponsesUntilFinal( const SEQ_NO requestSeqNumber, ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)], const int queryInterval, const int timeout) const @@ -56,7 +56,7 @@ void cta::acs::AcsLibraryInteraction::requestResponsesUntilFinal( elapsedTime += time(NULL) - startTime; if(RT_ACKNOWLEDGE == responseType) { - log::write(LOG_DEBUG,"Received RT_ACKNOWLEDGE"); + m_log(LOG_DEBUG,"Received RT_ACKNOWLEDGE"); } if(elapsedTime >= timeout) { @@ -66,13 +66,13 @@ void cta::acs::AcsLibraryInteraction::requestResponsesUntilFinal( } } while(RT_FINAL != responseType); - log::write(LOG_DEBUG,"Received RT_FINAL"); + m_log(LOG_DEBUG,"Received RT_FINAL"); } //------------------------------------------------------------------------------ // requestResponse //------------------------------------------------------------------------------ -ACS_RESPONSE_TYPE cta::acs::AcsLibraryInteraction::requestResponse( +ACS_RESPONSE_TYPE cta::mediachanger::acs::AcsLibraryInteraction::requestResponse( const int timeout, const SEQ_NO requestSeqNumber, ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const { @@ -82,7 +82,7 @@ ACS_RESPONSE_TYPE cta::acs::AcsLibraryInteraction::requestResponse( std::stringstream dbgMsg; dbgMsg << "Calling Acs::response() for requestSeqNumber=" << requestSeqNumber; - log::write(LOG_DEBUG, dbgMsg.str()); + m_log(LOG_DEBUG, dbgMsg.str()); const STATUS s = m_acs.response(timeout, responseSeqNumber, reqId, responseType, buf); @@ -91,7 +91,7 @@ ACS_RESPONSE_TYPE cta::acs::AcsLibraryInteraction::requestResponse( dbgMsg << "Acs::response() for requestSeqNumber=" << requestSeqNumber << " returned responseSeqNumber=" << responseSeqNumber << " and status " << acs_status(s); - log::write(LOG_DEBUG,dbgMsg.str()); + m_log(LOG_DEBUG,dbgMsg.str()); switch(s) { case STATUS_SUCCESS: @@ -109,7 +109,7 @@ ACS_RESPONSE_TYPE cta::acs::AcsLibraryInteraction::requestResponse( //------------------------------------------------------------------------------ // checkSeqNumber //------------------------------------------------------------------------------ -void cta::acs::AcsLibraryInteraction::checkResponseSeqNumber( +void cta::mediachanger::acs::AcsLibraryInteraction::checkResponseSeqNumber( const SEQ_NO requestSeqNumber, const SEQ_NO responseSeqNumber) const { if(requestSeqNumber != responseSeqNumber) { @@ -123,7 +123,7 @@ void cta::acs::AcsLibraryInteraction::checkResponseSeqNumber( //------------------------------------------------------------------------------ // volumeStatusAsString //------------------------------------------------------------------------------ -std::string cta::acs::AcsLibraryInteraction::volumeStatusAsString( +std::string cta::mediachanger::acs::AcsLibraryInteraction::volumeStatusAsString( const QU_VOL_STATUS &s) const throw() { std::ostringstream os; diff --git a/mediachanger/acs/AcsLibraryInteraction.hpp b/mediachanger/acs/AcsLibraryInteraction.hpp index 363516364992a0657ca6d3c3a4540e27680a76a3..8dddcf591907df4e24c37e6f308b5f91d12dfb5f 100644 --- a/mediachanger/acs/AcsLibraryInteraction.hpp +++ b/mediachanger/acs/AcsLibraryInteraction.hpp @@ -20,6 +20,7 @@ #include "common/exception/Mismatch.hpp" #include "common/exception/RequestFailed.hpp" +#include "common/log/log.hpp" #include "Acs.hpp" #include <string> @@ -30,6 +31,7 @@ extern "C" { } namespace cta { +namespace mediachanger { namespace acs { /** @@ -44,7 +46,7 @@ public: * * @param acs Wrapper around the ACSLS C-API. */ - AcsLibraryInteraction(Acs &acs) throw(); + AcsLibraryInteraction(Acs &acs, cta::log::Logger &log) throw(); /** * Pure-virtual destructor to guarantee this class is abstract. @@ -108,10 +110,11 @@ protected: * Wrapper around the ACSLS C-API. */ Acs &m_acs; - + log::Logger &m_log; }; // class AcsLibraryInteraction } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsMountCmd.cpp b/mediachanger/acs/AcsMountCmd.cpp index 5ebf2950c9e4a9ef292a294e8478d145d56d2203..3ffa3a4aa2e8d792b01e11d28f60bc2e45a2f1db 100644 --- a/mediachanger/acs/AcsMountCmd.cpp +++ b/mediachanger/acs/AcsMountCmd.cpp @@ -18,14 +18,12 @@ #include "AcsMountCmd.hpp" #include "AcsMountCmdLine.hpp" - #include <getopt.h> #include <iostream> - //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsMountCmd::AcsMountCmd( +cta::mediachanger::acs::AcsMountCmd::AcsMountCmd( std::istream &inStream, std::ostream &outStream, std::ostream &errStream, Acs &acs) throw(): AcsCmd(inStream, outStream, errStream, acs) { @@ -34,14 +32,14 @@ cta::acs::AcsMountCmd::AcsMountCmd( //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::AcsMountCmd::~AcsMountCmd() throw() { +cta::mediachanger::acs::AcsMountCmd::~AcsMountCmd() throw() { // Do nothing } //------------------------------------------------------------------------------ // exceptionThrowingMain //------------------------------------------------------------------------------ -int cta::acs::AcsMountCmd::exceptionThrowingMain(const int argc, +int cta::mediachanger::acs::AcsMountCmd::exceptionThrowingMain(const int argc, char *const *const argv) { try { m_cmdLine = AcsMountCmdLine(argc, argv); @@ -77,7 +75,7 @@ int cta::acs::AcsMountCmd::exceptionThrowingMain(const int argc, //------------------------------------------------------------------------------ // syncMount //------------------------------------------------------------------------------ -void cta::acs::AcsMountCmd::syncMount() { +void cta::mediachanger::acs::AcsMountCmd::syncMount() { const SEQ_NO requestSeqNumber = 1; ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; @@ -97,7 +95,7 @@ void cta::acs::AcsMountCmd::syncMount() { //------------------------------------------------------------------------------ // sendMountRequest //------------------------------------------------------------------------------ -void cta::acs::AcsMountCmd::sendMountRequest(const SEQ_NO seqNumber) { +void cta::mediachanger::acs::AcsMountCmd::sendMountRequest(const SEQ_NO seqNumber) { const LOCKID lockId = 0; // No lock const BOOLEAN bypass = FALSE; @@ -119,7 +117,7 @@ void cta::acs::AcsMountCmd::sendMountRequest(const SEQ_NO seqNumber) { //------------------------------------------------------------------------------ // processMountResponse //------------------------------------------------------------------------------ -void cta::acs::AcsMountCmd::processMountResponse( +void cta::mediachanger::acs::AcsMountCmd::processMountResponse( ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) { const ACS_MOUNT_RESPONSE *const msg = (ACS_MOUNT_RESPONSE *)buf; diff --git a/mediachanger/acs/AcsMountCmd.hpp b/mediachanger/acs/AcsMountCmd.hpp index 9aa38dec4d68bbab9f32b9a85892ec250c33a06e..46eb90ebf50ca35e0c9443108903c3f969e19ca5 100644 --- a/mediachanger/acs/AcsMountCmd.hpp +++ b/mediachanger/acs/AcsMountCmd.hpp @@ -27,6 +27,7 @@ #include <stdint.h> namespace cta { +namespace mediachanger { namespace acs { /** @@ -100,4 +101,5 @@ private: }; // class AcsMountCmd } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsMountCmdLine.cpp b/mediachanger/acs/AcsMountCmdLine.cpp index c33decac3c1f763ed02491643798a191e4c0b293..aa256c17205386bdb88823b8cd69e5680be4f47a 100644 --- a/mediachanger/acs/AcsMountCmdLine.cpp +++ b/mediachanger/acs/AcsMountCmdLine.cpp @@ -29,7 +29,7 @@ //----------------------------------------------------------------------------- // constructor //----------------------------------------------------------------------------- -cta::acs::AcsMountCmdLine::AcsMountCmdLine() throw(): +cta::mediachanger::acs::AcsMountCmdLine::AcsMountCmdLine() throw(): debug(false), help(false), queryInterval(0), @@ -45,7 +45,7 @@ cta::acs::AcsMountCmdLine::AcsMountCmdLine() throw(): //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsMountCmdLine::AcsMountCmdLine(const int argc, +cta::mediachanger::acs::AcsMountCmdLine::AcsMountCmdLine(const int argc, char *const *const argv): debug(false), help(false), @@ -104,7 +104,7 @@ cta::acs::AcsMountCmdLine::AcsMountCmdLine(const int argc, //------------------------------------------------------------------------------ // processOption //------------------------------------------------------------------------------ -void cta::acs::AcsMountCmdLine::processOption(const int opt) { +void cta::mediachanger::acs::AcsMountCmdLine::processOption(const int opt) { switch(opt) { case 'd': debug = true; @@ -139,7 +139,7 @@ void cta::acs::AcsMountCmdLine::processOption(const int opt) { //------------------------------------------------------------------------------ // getUsage //------------------------------------------------------------------------------ -std::string cta::acs::AcsMountCmdLine::getUsage() throw() { +std::string cta::mediachanger::acs::AcsMountCmdLine::getUsage() throw() { std::ostringstream usage; usage << "Usage:\n" diff --git a/mediachanger/acs/AcsMountCmdLine.hpp b/mediachanger/acs/AcsMountCmdLine.hpp index e9abd303577b937f238d4d9cdab75622fa988ad5..3055432eada3a7e0cdf0b1b33a4fecc15a5c5d43 100644 --- a/mediachanger/acs/AcsMountCmdLine.hpp +++ b/mediachanger/acs/AcsMountCmdLine.hpp @@ -28,6 +28,7 @@ extern "C" { #include <string> namespace cta { +namespace mediachanger { namespace acs { /** @@ -106,4 +107,5 @@ private: }; // class AcsMountCmdLine } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsMountCmdMain.cpp b/mediachanger/acs/AcsMountCmdMain.cpp index 5c73a8e26903abc5df42c75b68f3760253cd456a..b1c4e965c72b2ef124d8a2a9774db947661f9a76 100644 --- a/mediachanger/acs/AcsMountCmdMain.cpp +++ b/mediachanger/acs/AcsMountCmdMain.cpp @@ -62,8 +62,8 @@ int main(const int argc, char *const *const argv) { static int exceptionThrowingMain(const int argc, char *const *const argv) { using namespace cta; - acs::AcsImpl acs; - acs::AcsMountCmd cmd(std::cin, std::cout, std::cerr, acs); + mediachanger::acs::AcsImpl acs; + mediachanger::acs::AcsMountCmd cmd(std::cin, std::cout, std::cerr, acs); return cmd.exceptionThrowingMain(argc, argv); } diff --git a/mediachanger/acs/AcsQueryDriveCmd.cpp b/mediachanger/acs/AcsQueryDriveCmd.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5978b01449241812aab2d955339091cdf5677ad --- /dev/null +++ b/mediachanger/acs/AcsQueryDriveCmd.cpp @@ -0,0 +1,162 @@ +/* + * 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 "AcsQueryDriveCmd.hpp" +#include "AcsQueryDriveCmdLine.hpp" +#include "common/exception/QueryVolumeFailed.hpp" +#include <getopt.h> +#include <iostream> +#include <string.h> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::AcsQueryDriveCmd::AcsQueryDriveCmd( + std::istream &inStream, std::ostream &outStream, std::ostream &errStream, + Acs &acs) throw(): + AcsCmd(inStream, outStream, errStream, acs) { +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::AcsQueryDriveCmd::~AcsQueryDriveCmd() throw() { + // Do nothing +} + +//------------------------------------------------------------------------------ +// exceptionThrowingMain +//------------------------------------------------------------------------------ +int cta::mediachanger::acs::AcsQueryDriveCmd::exceptionThrowingMain(const int argc, + char *const *const argv) { + try { + m_cmdLine = AcsQueryDriveCmdLine(argc, argv); + } catch(cta::exception::Exception &ex) { + m_err << ex.getMessage().str() << std::endl; + m_err << std::endl; + m_err << m_cmdLine.getUsage() << std::endl; + return 1; + } + + // Display the usage message to standard out and exit with success if the + // user requested help + if(m_cmdLine.help) { + m_out << AcsQueryDriveCmdLine::getUsage(); + return 0; + } + + // Setup debug mode to be on or off depending on the command-line arguments + m_debugBuf.setDebug(m_cmdLine.debug); + + m_dbg << "query = " << m_cmdLine.queryInterval << std::endl; + m_dbg << "timeout = " << m_cmdLine.timeout << std::endl; + m_dbg << "DRIVE_SLOT = " << m_acs.driveId2Str(m_cmdLine.libraryDriveSlot); + + syncQueryDrive(); + return 0; +} + +//------------------------------------------------------------------------------ +// syncQueryDrive +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::AcsQueryDriveCmd::syncQueryDrive() { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendQueryDriveRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, m_cmdLine.queryInterval, + m_cmdLine.timeout); + processQueryResponse(m_out, buf); + } catch(cta::exception::Exception &ex) { + cta::exception::QueryVolumeFailed qf; + qf.getMessage() << "Failed to query drive " << + m_acs.driveId2Str(m_cmdLine.libraryDriveSlot) << ": " << ex.getMessage().str(); + throw qf; + } +} + +//------------------------------------------------------------------------------ +// sendQueryDriveRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::AcsQueryDriveCmd::sendQueryDriveRequest( + const SEQ_NO sequence) { + + m_dbg << "Calling Acs::queryDrive()" << std::endl; + const STATUS s = acs_query_drive(sequence, &(m_cmdLine.libraryDriveSlot), 1); + m_dbg << "Acs::queryDrive() returned " << acs_status(s) << std::endl; + + if(STATUS_SUCCESS != s) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Failed to send query request for drive " << + m_acs.driveId2Str(m_cmdLine.libraryDriveSlot)<< ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processQueryResponse +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::AcsQueryDriveCmd::processQueryResponse( + std::ostream &os, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) { + + const ACS_QUERY_DRV_RESPONSE *const msg = (ACS_QUERY_DRV_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->query_drv_status) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Status of query response is not success: " << + acs_status(msg->query_drv_status); + throw ex; + } + + if((unsigned short)1 != msg->count) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Query response does not contain a single drive: count=" + << msg->count; + throw ex; + } + + // count is 1 so it is safe to make a reference to the single drive status + const QU_DRV_STATUS &drvStatus = msg->drv_status[0]; + + if(m_acs.driveId2Str(m_cmdLine.libraryDriveSlot)!= m_acs.driveId2Str(drvStatus.drive_id)) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << + "Drive identifier of query response does not match that of request" + " requestDriveID=" <<m_acs.driveId2Str(m_cmdLine.libraryDriveSlot) << + " responseDriveID=" << m_acs.driveId2Str(drvStatus.drive_id); + throw ex; + } + + writeDriveStatus(os, drvStatus); +} + +//------------------------------------------------------------------------------ +// writeDriveStatus +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::AcsQueryDriveCmd::writeDriveStatus( + std::ostream &os, const QU_DRV_STATUS &s) throw() { + + os << "Drive identifier: " << m_acs.driveId2Str(s.drive_id) << std::endl; + os << "Drive type: " << acs_type((TYPE)s.drive_type) << std::endl; + os << "Drive state: " << acs_state(s.state) << std::endl; + os << "Drive status: " << acs_status(s.status) << std::endl; + os << "Volume identifier: " << s.vol_id.external_label << std::endl; +} diff --git a/mediachanger/acs/AcsQueryDriveCmd.hpp b/mediachanger/acs/AcsQueryDriveCmd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d8d98379dcc511ba6d27cc1b70ac96db1f5eaa8d --- /dev/null +++ b/mediachanger/acs/AcsQueryDriveCmd.hpp @@ -0,0 +1,117 @@ +/* + * 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 "AcsCmd.hpp" +#include "AcsQueryDriveCmdLine.hpp" +#include "common/exception/InvalidArgument.hpp" +#include "common/exception/MissingOperand.hpp" +#include "mediachanger/CmdLineTool.hpp" +#include <stdint.h> + +namespace cta { +namespace mediachanger { +namespace acs { + +/** + * The class implementing the mount command. + */ +class AcsQueryDriveCmd: public AcsCmd { +public: + + /** + * Constructor. + * + * @param inStream Standard input stream. + * @param outStream Standard output stream. + * @param errStream Standard error stream. + * @param acs Wrapper around the ACSLS C-API. + */ + AcsQueryDriveCmd(std::istream &inStream, std::ostream &outStream, + std::ostream &errStream, Acs &acs) throw(); + + /** + * Destructor. + */ + virtual ~AcsQueryDriveCmd() throw(); + + /** + * The entry function of the command. + * + * @param argc The number of command-line arguments. + * @param argv The command-line arguments. + * @return The exit value of the program. + */ + int exceptionThrowingMain(const int argc, char *const *const argv); +protected: + + /** + * Queries ACS for information about the drive identifier specified on the + * command-line. + * + * This method does not return until the information has been successfully + * retrieved, an error has occurred or the specified timeout has been + * reached. + * + * @return The drive status of the drive identifier specified on the + * command-line. + */ + void syncQueryDrive(); + + /** + * Sends the query drive request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendQueryDriveRequest(const SEQ_NO seqNumber); + + /** + * Extracts the drive status from the specified query-response message and + * writes it in human-readable form to the specified output stream. + * + * @param os The output stream. + * @param buf The query-response message. + */ + void processQueryResponse(std::ostream &os, + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]); + + /** + * Writes a human readable representation of the specified drive status to + * the specified output stream. + * + * @param os The output stream. + * @param s The drive status. + */ + void writeDriveStatus(std::ostream &os, const QU_DRV_STATUS &s) throw(); + +private: + + /** + * The parsed command-line. + * + * The value of this member variable is set within the main() method of this + * class. + */ + AcsQueryDriveCmdLine m_cmdLine; + +}; // class AcsQueryDriveCmd + +} // namespace acs +} // namepsace mediachanger +} // namespace cta diff --git a/mediachanger/acs/AcsQueryDriveCmdLine.cpp b/mediachanger/acs/AcsQueryDriveCmdLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b74066efd1b9b04c99e68e949b8e8fd02e344c8f --- /dev/null +++ b/mediachanger/acs/AcsQueryDriveCmdLine.cpp @@ -0,0 +1,157 @@ + +/* + * 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 "Acs.hpp" +#include "AcsQueryDriveCmdLine.hpp" +#include "Constants.hpp" +#include "common/exception/InvalidArgument.hpp" +#include "common/exception/MissingOperand.hpp" +#include <getopt.h> +#include <stdlib.h> +#include <string.h> + + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::AcsQueryDriveCmdLine::AcsQueryDriveCmdLine() throw(): + debug(false), + help(false), + queryInterval(0), + timeout(0) { + libraryDriveSlot.panel_id.lsm_id.acs = (ACS)0; + libraryDriveSlot.panel_id.lsm_id.lsm = (LSM)0; + libraryDriveSlot.panel_id.panel = (PANEL)0; + libraryDriveSlot.drive = (DRIVE)0; + memset(volId.external_label, '\0', sizeof(volId.external_label)); +} + + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::AcsQueryDriveCmdLine::AcsQueryDriveCmdLine(const int argc, + char *const *const argv): + debug(false), + help(false), + queryInterval(ACS_QUERY_INTERVAL), + timeout(ACS_CMD_TIMEOUT) { + libraryDriveSlot.panel_id.lsm_id.acs = (ACS)0; + libraryDriveSlot.panel_id.lsm_id.lsm = (LSM)0; + libraryDriveSlot.panel_id.panel = (PANEL)0; + libraryDriveSlot.drive = (DRIVE)0; + memset(volId.external_label, '\0', sizeof(volId.external_label)); + + static struct option longopts[] = { + {"debug", 0, NULL, 'd'}, + {"help" , 0, NULL, 'h'}, + {"query" , required_argument, NULL, 'q'}, + {"timeout" , required_argument, NULL, 't'}, + {NULL, 0, NULL, 0} + }; + + // Prevent getopt() from printing an error message if it does not recognize + // an option character + opterr = 0; + + int opt = 0; + while((opt = getopt_long(argc, argv, ":dhq:t:", longopts, NULL)) != -1) { + processOption(opt); + } + // There is no need to continue parsing when the help option is set + if(help) { + return; + } + // Check that DRIVE_SLOT has been specified + if(argc < 1) { + cta::exception::MissingOperand ex; + ex.getMessage() << "DRIVE_SLOT must be specified"; + throw ex; + } + // Parse DRIVE_SLOT + libraryDriveSlot = Acs::str2DriveId(argv[1]); + +} +//------------------------------------------------------------------------------ +// processOption +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::AcsQueryDriveCmdLine::processOption(const int opt) { + switch(opt) { + case 'd': + debug = true; + break; + case 'h': + help = true; + break; + case 'q': + queryInterval = parseQueryInterval(optarg); + break; + case 't': + timeout = parseTimeout(optarg); + break; + case ':': + return handleMissingParameter(optopt); + case '?': + return handleUnknownOption(optopt); + default: + { + cta::exception::Exception ex; + ex.getMessage() << + "getopt_long returned the following unknown value: 0x" << + std::hex << (int)opt; + throw ex; + } + } // switch(opt) +} + + +//------------------------------------------------------------------------------ +// getUsage +//------------------------------------------------------------------------------ + std::string cta::mediachanger::acs::AcsQueryDriveCmdLine::getUsage() throw() { + std::ostringstream usage; + usage << + "Usage:\n" + "\n" + << getProgramName() << " [options] DRIVE_SLOT\n" + "\n" + "Where:\n" + "\n" + " DRIVE_SLOT The slot in the tape library where the drive is located.\n" + " DRIVE_SLOT must be in one of the following two forms:\n" + "\n" + " acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER\n" + " smcDRIVE_ORDINAL\n" + "\n" + "Options:\n" + "\n" + " -d|--debug Turn on the printing of debug information.\n" + "\n" + " -h|--help Print this help message and exit.\n" + "\n"; + return usage.str(); +} + +//------------------------------------------------------------------------------ +// getProgramName +//------------------------------------------------------------------------------ +std::string cta::mediachanger::acs::AcsQueryDriveCmdLine::getProgramName() { + return "cta-tape-acs-querydrive"; +} + diff --git a/mediachanger/acs/AcsQueryDriveCmdLine.hpp b/mediachanger/acs/AcsQueryDriveCmdLine.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4d2f086f3320ec3df26466b49543a39745d1f685 --- /dev/null +++ b/mediachanger/acs/AcsQueryDriveCmdLine.hpp @@ -0,0 +1,118 @@ +/* + * 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 "AcsCmdLine.hpp" +#include "mediachanger/AcsLibrarySlot.hpp" +#include "mediachanger/LibrarySlotParser.hpp" + +extern "C" { +#include "acssys.h" +#include "acsapi.h" +} + +#include <string> + +namespace cta { +namespace mediachanger { +namespace acs { + +/** + * Data type used to store the results of parsing the command-line. + */ +struct AcsQueryDriveCmdLine: public AcsCmdLine { + /** + * True if the debug option has been set. + */ + BOOLEAN debug; + + /** + * True if the help option has been set. + */ + BOOLEAN help; + + /** + * Time in seconds to wait between queries to ACS for responses. + */ + int queryInterval; + + /** + * Time in seconds to wait for the dismount to conclude. + */ + int timeout; + + /** + * The volume identifier of the tape to be mounted. + */ + VOLID volId; + + /** + * Constructor. + * + * Initialises all BOOLEAN member-variables to FALSE, all integer + * member-variables to 0 and the volume identifier to an empty string. + */ + AcsQueryDriveCmdLine() throw(); + + /** + * Constructor. + * + * Parses the specified command-line arguments. + * + * @param argc Argument count from the executable's entry function: main(). + * @param argv Argument vector from the executable's entry function: main(). + */ + AcsQueryDriveCmdLine(const int argc, char *const *const argv); + + + /** + * Gets the usage message that describes the command line. + * + * @return The usage message. + */ + static std::string getUsage() throw(); + + /** + * Return sthe program name. + * + * @return sthe program name. + */ + static std::string getProgramName(); + + /** + * The slot in the tape library where the drive is located. + */ + + DRIVEID libraryDriveSlot; + + +private: + + /** + * Processes the specified option that was returned by getopt_long(). + * + * @param opt The option that was returned by getopt_long(). + */ + void processOption(const int opt); + +}; // class AcsQueryDriveCmdLine + +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/AcsQueryDriveCmdMain.cpp b/mediachanger/acs/AcsQueryDriveCmdMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfc8d406ae0a9ffbe052a1c4e08456365be69000 --- /dev/null +++ b/mediachanger/acs/AcsQueryDriveCmdMain.cpp @@ -0,0 +1,60 @@ +/* + * 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 "AcsImpl.hpp" +#include "AcsQueryDriveCmd.hpp" +#include "AcsQueryDriveCmdLine.hpp" + +#include <iostream> + +/** + * An exception throwing version of main(). + * + * @param argc The number of command-line arguments including the program name. + * @param argv The command-line arguments. + * @param The exit value of the program. + */ +static int exceptionThrowingMain(const int argc, char *const *const argv); + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int main(const int argc, char *const *const argv) { + using namespace cta; + std::string errorMessage; + try { + return exceptionThrowingMain(argc, argv); + } catch(cta::exception::Exception &ex) { + errorMessage = ex.getMessage().str(); + } catch(std::exception &se) { + errorMessage = se.what(); + } catch(...) { + errorMessage = "An unknown exception was thrown"; + } + return 1; +} + +//------------------------------------------------------------------------------ +// exceptionThrowingMain +//------------------------------------------------------------------------------ +static int exceptionThrowingMain(const int argc, char *const *const argv) { + using namespace cta; + mediachanger::acs::AcsImpl acs; + mediachanger::acs::AcsQueryDriveCmd cmd(std::cin, std::cout, std::cerr, acs); + return cmd.exceptionThrowingMain(argc, argv); +} diff --git a/mediachanger/acs/AcsQueryVolumeCmd.cpp b/mediachanger/acs/AcsQueryVolumeCmd.cpp index 028a78a3384fc1a44c5f3e220f5f91b983f8b88d..7b3d64c543a51fd1f207042d560ad6e9ca92a119 100644 --- a/mediachanger/acs/AcsQueryVolumeCmd.cpp +++ b/mediachanger/acs/AcsQueryVolumeCmd.cpp @@ -27,7 +27,7 @@ //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsQueryVolumeCmd::AcsQueryVolumeCmd( +cta::mediachanger::acs::AcsQueryVolumeCmd::AcsQueryVolumeCmd( std::istream &inStream, std::ostream &outStream, std::ostream &errStream, Acs &acs) throw(): AcsCmd(inStream, outStream, errStream, acs) { @@ -36,14 +36,14 @@ cta::acs::AcsQueryVolumeCmd::AcsQueryVolumeCmd( //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::AcsQueryVolumeCmd::~AcsQueryVolumeCmd() throw() { +cta::mediachanger::acs::AcsQueryVolumeCmd::~AcsQueryVolumeCmd() throw() { // Do nothing } //------------------------------------------------------------------------------ // exceptionThrowingMain //------------------------------------------------------------------------------ -int cta::acs::AcsQueryVolumeCmd::exceptionThrowingMain(const int argc, +int cta::mediachanger::acs::AcsQueryVolumeCmd::exceptionThrowingMain(const int argc, char *const *const argv) { try { m_cmdLine = AcsQueryVolumeCmdLine(argc, argv); @@ -75,7 +75,7 @@ int cta::acs::AcsQueryVolumeCmd::exceptionThrowingMain(const int argc, //------------------------------------------------------------------------------ // syncQueryVolume //------------------------------------------------------------------------------ -void cta::acs::AcsQueryVolumeCmd::syncQueryVolume() { +void cta::mediachanger::acs::AcsQueryVolumeCmd::syncQueryVolume() { const SEQ_NO requestSeqNumber = 1; ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; @@ -95,7 +95,7 @@ void cta::acs::AcsQueryVolumeCmd::syncQueryVolume() { //------------------------------------------------------------------------------ // sendQueryVolumeRequest //------------------------------------------------------------------------------ -void cta::acs::AcsQueryVolumeCmd::sendQueryVolumeRequest( +void cta::mediachanger::acs::AcsQueryVolumeCmd::sendQueryVolumeRequest( const SEQ_NO seqNumber) { VOLID volIds[MAX_ID]; @@ -119,7 +119,7 @@ void cta::acs::AcsQueryVolumeCmd::sendQueryVolumeRequest( //------------------------------------------------------------------------------ // processQueryResponse //------------------------------------------------------------------------------ -void cta::acs::AcsQueryVolumeCmd::processQueryResponse( +void cta::mediachanger::acs::AcsQueryVolumeCmd::processQueryResponse( std::ostream &os, ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) { @@ -157,7 +157,7 @@ void cta::acs::AcsQueryVolumeCmd::processQueryResponse( //------------------------------------------------------------------------------ // writeVolumeStatus //------------------------------------------------------------------------------ -void cta::acs::AcsQueryVolumeCmd::writeVolumeStatus( +void cta::mediachanger::acs::AcsQueryVolumeCmd::writeVolumeStatus( std::ostream &os, const QU_VOL_STATUS &s) throw() { os << "Volume identifier: " << s.vol_id.external_label << std::endl; os << "Media type (media_types.dat): " << (int)s.media_type << std::endl; diff --git a/mediachanger/acs/AcsQueryVolumeCmd.hpp b/mediachanger/acs/AcsQueryVolumeCmd.hpp index b5078f882bf60ec9084d8c0f093bd74011a444e9..7df2e22abe267f0a11c4eaf8eb090db6991b158b 100644 --- a/mediachanger/acs/AcsQueryVolumeCmd.hpp +++ b/mediachanger/acs/AcsQueryVolumeCmd.hpp @@ -28,6 +28,7 @@ #include <stdint.h> namespace cta { +namespace mediachanger { namespace acs { /** @@ -115,4 +116,5 @@ private: }; // class AcsQueryVolumeCmd } // namespace acs +} // namepsace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsQueryVolumeCmdLine.cpp b/mediachanger/acs/AcsQueryVolumeCmdLine.cpp index 351f5d22fe8c3b51bc70454bb24ba1d9b5e2cd2d..cbc4134d8fa470925e4c9c313517505cb9c9ed5d 100644 --- a/mediachanger/acs/AcsQueryVolumeCmdLine.cpp +++ b/mediachanger/acs/AcsQueryVolumeCmdLine.cpp @@ -30,7 +30,7 @@ //----------------------------------------------------------------------------- // constructor //----------------------------------------------------------------------------- -cta::acs::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine() +cta::mediachanger::acs::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine() throw(): debug(FALSE), help(FALSE), @@ -42,7 +42,7 @@ cta::acs::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine() //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine(const int argc, +cta::mediachanger::acs::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine(const int argc, char *const *const argv): debug(FALSE), help(FALSE), @@ -89,7 +89,7 @@ cta::acs::AcsQueryVolumeCmdLine::AcsQueryVolumeCmdLine(const int argc, //------------------------------------------------------------------------------ // processOption //------------------------------------------------------------------------------ -void cta::acs::AcsQueryVolumeCmdLine::processOption(const int opt) { +void cta::mediachanger::acs::AcsQueryVolumeCmdLine::processOption(const int opt) { switch(opt) { case 'd': debug = true; @@ -121,7 +121,7 @@ void cta::acs::AcsQueryVolumeCmdLine::processOption(const int opt) { //------------------------------------------------------------------------------ // getUsage //------------------------------------------------------------------------------ -std::string cta::acs::AcsQueryVolumeCmdLine::getUsage() throw() { +std::string cta::mediachanger::acs::AcsQueryVolumeCmdLine::getUsage() throw() { std::ostringstream usage; usage << "Usage:\n" diff --git a/mediachanger/acs/AcsQueryVolumeCmdLine.hpp b/mediachanger/acs/AcsQueryVolumeCmdLine.hpp index d327e760399515be826661069184bb9c5aefb8ad..733c64ed1a1f6e9b11796a0c1226a9124ce894cb 100644 --- a/mediachanger/acs/AcsQueryVolumeCmdLine.hpp +++ b/mediachanger/acs/AcsQueryVolumeCmdLine.hpp @@ -28,6 +28,7 @@ extern "C" { #include <string> namespace cta { +namespace mediachanger { namespace acs { /** @@ -96,4 +97,5 @@ private: }; // class AcsQueryVolumeCmdLine } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/AcsQueryVolumeCmdMain.cpp b/mediachanger/acs/AcsQueryVolumeCmdMain.cpp index ca65595934b013109838ae23910f325cd5176dc7..a9472eaf9479f311dacbe2ae1067553304cb31ef 100644 --- a/mediachanger/acs/AcsQueryVolumeCmdMain.cpp +++ b/mediachanger/acs/AcsQueryVolumeCmdMain.cpp @@ -61,8 +61,8 @@ int main(const int argc, char *const *const argv) { static int exceptionThrowingMain(const int argc, char *const *const argv) { using namespace cta; - acs::AcsImpl acs; - acs::AcsQueryVolumeCmd cmd(std::cin, std::cout, std::cerr, acs); + mediachanger::acs::AcsImpl acs; + mediachanger::acs::AcsQueryVolumeCmd cmd(std::cin, std::cout, std::cerr, acs); return cmd.exceptionThrowingMain(argc, argv); } diff --git a/mediachanger/acs/CMakeLists.txt b/mediachanger/acs/CMakeLists.txt index 42406cf47b53c4d52cd2859b9e18c813d04740b1..36438b4da17aec0c1aa114a9a0c0291371a07503 100644 --- a/mediachanger/acs/CMakeLists.txt +++ b/mediachanger/acs/CMakeLists.txt @@ -22,51 +22,24 @@ # Rules to build and install acsd ################################################################################ -##add_library( - #castorAcsDaemon - ## Acs.cpp - #AcsDaemon.cpp - #AcsDaemonConfig.cpp - #AcsDaemonMain.cpp - #AcsDismountTape.cpp - #AcsForceDismountTape.cpp - ## AcsImpl.cpp - #AcsLibraryInteraction.cpp - #AcsMessageHandler.cpp - #AcsMountTapeReadOnly.cpp - #AcsMountTapeReadWrite.cpp - #AcsPendingRequests.cpp - #AcsRequest.cpp - #AcsRequestDismountTape.cpp -##) -#add_dependencies(castorAcsDaemon castormessagesprotobuf) +add_subdirectory(daemon) -#target_link_libraries(castorAcsDaemon castortapereactor) -#set_target_properties (castorAcsDaemon PROPERTIES -# COMPILE_FLAGS -I/usr/include/CDK -# COMPILE_DEFINITIONS LINUX) - - -#add_executable(acsd AcsDaemon.cpp) -#set_target_properties (acsd PROPERTIES -# COMPILE_FLAGS -I/usr/include/CDK -# COMPILE_DEFINITIONS LINUX) +add_library(cta-acs + Acs.cpp + AcsImpl.cpp + AcsDebugBuf.cpp + AcsLibraryInteraction.cpp) -#target_link_libraries( - #acsd - #castorAcsDaemon - #castortapereactor - #castorcommon - #castorserver - # castormessages - #zmq - #${STK_LIBRARIES}) +target_link_libraries(cta-acs + ctamediachanger + ctacommon + ctareactor + zmq + ${STK_LIBRARIES}) -#install (TARGETS acsd DESTINATION /usr/bin}) -#CastorInstallAdmManPage (acsd) -#CastorInstallLogrotate (castor-acs-server) -#CastorInstallSysconfigExample (acsd) -#CastorInstallInitScript (acsd) +set_target_properties (cta-acs PROPERTIES + COMPILE_FLAGS -I/usr/include/CDK + COMPILE_DEFINITIONS LINUX) ################################################################################ # Rules to build and install castor-tape-acs-dismount @@ -80,18 +53,17 @@ set (ACS_DISMOUNT_SRC_FILES AcsDismountCmd.cpp AcsDismountCmdLine.cpp AcsDismountCmdMain.cpp - CmdLineTool.cpp) + CmdLineTool.cpp + AcsDebugBuf.cpp) add_executable (cta-tape-acs-dismount ${ACS_DISMOUNT_SRC_FILES}) set_target_properties (cta-tape-acs-dismount PROPERTIES COMPILE_FLAGS -I/usr/include/CDK COMPILE_DEFINITIONS LINUX) target_link_libraries (cta-tape-acs-dismount - ctamediachanger ctacommon ${STK_LIBRARIES}) install (TARGETS cta-tape-acs-dismount DESTINATION /usr/bin) install (FILES cta-tape-acs-dismount.1cta DESTINATION /usr/share/man/man1) -#CastorInstallExeManPage(cta-tape-acs-dismount) ################################################################################ # Rules to build and install cta-tape-acs-mount @@ -104,18 +76,17 @@ set (ACS_MOUNT_SRC_FILES AcsMountCmd.cpp AcsMountCmdLine.cpp AcsMountCmdMain.cpp - CmdLineTool.cpp) + CmdLineTool.cpp + AcsDebugBuf.cpp) add_executable (cta-tape-acs-mount ${ACS_MOUNT_SRC_FILES}) set_target_properties (cta-tape-acs-mount PROPERTIES COMPILE_FLAGS -I/usr/include/CDK COMPILE_DEFINITIONS LINUX) target_link_libraries (cta-tape-acs-mount -ctamediachanger ctacommon ${STK_LIBRARIES}) install (TARGETS cta-tape-acs-mount DESTINATION /usr/bin) install (FILES cta-tape-acs-mount.1cta DESTINATION /usr/share/man/man1) -#CastorInstallExeManPage(cta-tape-acs-mount) ################################################################################ # Rules to build and install cta-tape-acs-queryvolume @@ -129,18 +100,41 @@ set (ACS_QUERYVOLUME_SRC_FILES AcsQueryVolumeCmd.cpp AcsQueryVolumeCmdLine.cpp AcsQueryVolumeCmdMain.cpp - CmdLineTool.cpp) + CmdLineTool.cpp + AcsDebugBuf.cpp) add_executable (cta-tape-acs-queryvolume ${ACS_QUERYVOLUME_SRC_FILES}) target_link_libraries (cta-tape-acs-queryvolume -ctamediachanger ctacommon ${STK_LIBRARIES}) set_target_properties (cta-tape-acs-queryvolume PROPERTIES COMPILE_FLAGS -I/usr/include/CDK - #COMPILE_FLAGS -I/usr/include/STK_INCLUDE_DIR COMPILE_DEFINITIONS LINUX) install (TARGETS cta-tape-acs-queryvolume DESTINATION /usr/bin) install (FILES cta-tape-acs-queryvolume.1cta DESTINATION /usr/share/man/man1) -#CastorInstallExeManPage(cta-tape-acs-queryvolume) + +################################################################################ +# Rules to build and install cta-tape-acs-querydrive +################################################################################ +message(STATUS "Adding cta-tape-acs-querydrive target") +set (ACS_QUERYDRIVE_SRC_FILES + Acs.cpp + AcsCmd.cpp + AcsCmdLine.cpp + AcsImpl.cpp + AcsQueryDriveCmd.cpp + AcsQueryDriveCmdLine.cpp + AcsQueryDriveCmdMain.cpp + CmdLineTool.cpp + AcsDebugBuf.cpp) + +add_executable (cta-tape-acs-querydrive ${ACS_QUERYDRIVE_SRC_FILES}) +target_link_libraries (cta-tape-acs-querydrive +ctacommon +${STK_LIBRARIES}) +set_target_properties (cta-tape-acs-querydrive PROPERTIES + COMPILE_FLAGS -I/usr/include/CDK + COMPILE_DEFINITIONS LINUX) +install (TARGETS cta-tape-acs-querydrive + DESTINATION /usr/bin) diff --git a/mediachanger/acs/CmdLineTool.cpp b/mediachanger/acs/CmdLineTool.cpp index 71ccd623f441e9180cae78eb44fbdc8b9e9ad363..7dcaa3c46983c5145dcbbfba1349b3660be4744b 100644 --- a/mediachanger/acs/CmdLineTool.cpp +++ b/mediachanger/acs/CmdLineTool.cpp @@ -21,7 +21,7 @@ //------------------------------------------------------------------------------ // constructor //------------------------------------------------------------------------------ -cta::acs::CmdLineTool::CmdLineTool(std::istream &inStream, +cta::mediachanger::acs::CmdLineTool::CmdLineTool(std::istream &inStream, std::ostream &outStream, std::ostream &errStream) throw(): m_in(inStream), m_out(outStream), m_err(errStream), m_debugBuf(outStream), m_dbg(&m_debugBuf) { @@ -30,12 +30,12 @@ cta::acs::CmdLineTool::CmdLineTool(std::istream &inStream, //------------------------------------------------------------------------------ // destructor //------------------------------------------------------------------------------ -cta::acs::CmdLineTool::~CmdLineTool() throw() { +cta::mediachanger::acs::CmdLineTool::~CmdLineTool() throw() { } //------------------------------------------------------------------------------ // bool2Str //------------------------------------------------------------------------------ -std::string cta::acs::CmdLineTool::bool2Str(const bool value) const throw() { +std::string cta::mediachanger::acs::CmdLineTool::bool2Str(const bool value) const throw() { return value ? "TRUE" : "FALSE"; } diff --git a/mediachanger/acs/CmdLineTool.hpp b/mediachanger/acs/CmdLineTool.hpp index 2137e16a7e4944f7ee02cf776980fac5bbd1f7d1..74e473b5fcb1aabda8de46fbe57e3e1b239324ca 100644 --- a/mediachanger/acs/CmdLineTool.hpp +++ b/mediachanger/acs/CmdLineTool.hpp @@ -18,13 +18,14 @@ #pragma once -#include "mediachanger/DebugBuf.hpp" +#include "mediachanger/acs/AcsDebugBuf.hpp" #include <istream> #include <ostream> #include <string> namespace cta { +namespace mediachanger { namespace acs { /** @@ -69,7 +70,7 @@ protected: * Debug stream buffer that inserts a standard debug preamble before each * message-line written to it. */ - cta::mediachanger::DebugBuf m_debugBuf; + cta::mediachanger::acs::DebugBuf m_debugBuf; /** * Stream used to write debug messages. @@ -89,4 +90,5 @@ protected: }; // class CmdLineTool } // namespace acs +} // namespace mediachanger } // namespace cta diff --git a/mediachanger/acs/Constants.hpp b/mediachanger/acs/Constants.hpp index f6c8056962420efe6502a9a23eab426b6fb0ca4e..b6c9cfb970840ca2d955a7afc8d9c677858cdfa2 100644 --- a/mediachanger/acs/Constants.hpp +++ b/mediachanger/acs/Constants.hpp @@ -19,7 +19,7 @@ #pragma once namespace cta { -namespace acs { +//namespace acs { /** * The default TCP/IP port on which the CASTOR ACS daemon listens for incoming Zmq @@ -57,6 +57,6 @@ enum RequestState { ACS_REQUEST_FAILED, ACS_REQUEST_TO_DELETE}; -} // namespace acs +//} // namespace acs } // namespace cta diff --git a/mediachanger/acs/daemon/AcsDaemon.cpp b/mediachanger/acs/daemon/AcsDaemon.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4142f8e600a99a4ab94dc98a68748a73a7b14f56 --- /dev/null +++ b/mediachanger/acs/daemon/AcsDaemon.cpp @@ -0,0 +1,374 @@ +/* + * 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 "common/Constants.hpp" +#include "AcsDaemon.hpp" +#include "AcsdConfiguration.hpp" +#include "mediachanger/acs/daemon/AcsMessageHandler.hpp" +#include "AcsPendingRequests.hpp" +#include "mediachanger/acs/daemon/AcsdCmdLine.hpp" +#include "common/exception/Errnum.hpp" +#include "common/exception/BadAlloc.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/log.hpp" +#include "common/log/SyslogLogger.hpp" +#include "common/threading/Daemon.hpp" +#include <memory> +#include <signal.h> +#include <unistd.h> + +#include <getopt.h> +#include <iostream> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +namespace cta { namespace mediachanger { namespace acs { namespace daemon { + +AcsDaemon::AcsDaemon( + const int argc, + char **const argv, + cta::log::Logger& log, + cta::mediachanger::reactor::ZMQReactor &reactor, + const AcsdConfiguration &config): + cta::server::Daemon(log), + m_argc(argc), + m_argv(argv), + m_log(log), + m_reactor(reactor), + m_programName("acsd"), + m_hostName(getHostName()), + m_zmqContext(NULL), + m_config(config), + m_acsPendingRequests(config,log) { +} + +//------------------------------------------------------------------------------ +// getHostName +//------------------------------------------------------------------------------ + +std::string cta::mediachanger::acs::daemon::AcsDaemon::getHostName() const { + char nameBuf[81]; + if(gethostname(nameBuf, sizeof(nameBuf))) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to get host name: "<<ex.getMessage().str(); + m_log(LOG_ERR, ex.getMessage().str()); + throw ex; + } + + return nameBuf; +} + + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ + AcsDaemon::~AcsDaemon() throw() { + m_reactor.clear(); + destroyZmqContext(); + google::protobuf::ShutdownProtobufLibrary(); +} + +//------------------------------------------------------------------------------ +// destroyZmqContext +//------------------------------------------------------------------------------ + + void AcsDaemon::destroyZmqContext() throw() { + if(NULL != m_zmqContext) { + if(zmq_term(m_zmqContext)) { + cta::exception::Exception ex; + std::list<log::Param> params = {log::Param("message", ex.getMessage().str())}; + m_log(LOG_ERR, "Failed to destroy ZMQ context", params); + } else { + m_zmqContext = NULL; + m_log(LOG_INFO, "Successfully destroyed ZMQ context"); + } + } +} + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int AcsDaemon::main() throw() { + + try { + exceptionThrowingMain(m_argc, m_argv); + } catch (cta::exception::Exception &ex) { + // Write the error to standard error + std::cerr << std::endl << "Aborting: " << ex.getMessage().str() << std::endl + << std::endl; + // Log the error + std::list<log::Param> params = { + log::Param("Message", ex.getMessage().str())}; + m_log(LOG_ERR, "Aborting", params); + + return 1; + } + + return 0; +} +//------------------------------------------------------------------------------ +// exceptionThrowingMain +//------------------------------------------------------------------------------ + +void AcsDaemon::exceptionThrowingMain( + const int argc, char **const argv) { + logStartOfDaemon(argc, argv); + AcsdCmdLine Commandline(argc,argv); //parse command line + setCommandLineHasBeenParsed(Commandline.foreground); + const std::string runAsStagerSuperuser = m_config.daemonUserName.value(); + const std::string runAsStagerSupergroup = m_config.daemonGroupName.value(); + daemonizeIfNotRunInForegroundAndSetUserAndGroup(runAsStagerSuperuser, runAsStagerSupergroup); + setDumpable(); + + blockSignals(); + initZmqContext(); + setUpReactor(); + mainEventLoop(); + +} + +//------------------------------------------------------------------------------ +// logStartOfDaemon +//------------------------------------------------------------------------------ + + void AcsDaemon::logStartOfDaemon( + const int argc, const char *const *const argv) throw() { + const std::string concatenatedArgs = argvToString(argc, argv); + std::ostringstream msg; + msg << m_programName << " started"; + + std::list<log::Param> params = { + log::Param("argv", concatenatedArgs)}; + m_log(LOG_INFO, msg.str(), params); +} + +//------------------------------------------------------------------------------ +// argvToString +//------------------------------------------------------------------------------ + + std::string AcsDaemon::argvToString( + const int argc, const char *const *const argv) throw() { + std::string str; + + for(int i=0; i < argc; i++) { + if(i != 0) { + str += " "; + } + + str += argv[i]; + } + return str; +} + +//------------------------------------------------------------------------------ +// setDumpable +//------------------------------------------------------------------------------ +void AcsDaemon::setDumpable() { + cta::utils::setDumpableProcessAttribute(true); + const bool dumpable = cta::utils::getDumpableProcessAttribute(); + std::list<log::Param> params = { + log::Param("dumpable", dumpable ? "true" : "false")}; + m_log(LOG_INFO, "Got dumpable attribute of process", params); + if(!dumpable) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to set dumpable attribute of process to true"; + throw ex; + } +} + +//------------------------------------------------------------------------------ +// blockSignals +//------------------------------------------------------------------------------ +void AcsDaemon::blockSignals() const { + sigset_t sigs; + sigemptyset(&sigs); + // The signals that should not asynchronously disturb the daemon + sigaddset(&sigs, SIGHUP); + sigaddset(&sigs, SIGINT); + sigaddset(&sigs, SIGQUIT); + sigaddset(&sigs, SIGPIPE); + sigaddset(&sigs, SIGTERM); + sigaddset(&sigs, SIGUSR1); + sigaddset(&sigs, SIGUSR2); + sigaddset(&sigs, SIGCHLD); + sigaddset(&sigs, SIGTSTP); + sigaddset(&sigs, SIGTTIN); + sigaddset(&sigs, SIGTTOU); + sigaddset(&sigs, SIGPOLL); + sigaddset(&sigs, SIGURG); + sigaddset(&sigs, SIGVTALRM); + cta::exception::Errnum::throwOnNonZero( + sigprocmask(SIG_BLOCK, &sigs, NULL), + "Failed to block signals: sigprocmask() failed"); +} + +//------------------------------------------------------------------------------ +// initZmqContext +//------------------------------------------------------------------------------ + + void AcsDaemon::initZmqContext() { + const int sizeOfIOThreadPoolForZMQ = 1; + m_zmqContext = zmq_init(sizeOfIOThreadPoolForZMQ); + if(NULL == m_zmqContext) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to instantiate ZMQ context: " << ex.getMessage().str(); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// setUpReactor +//------------------------------------------------------------------------------ +void AcsDaemon::setUpReactor() { + createAndRegisterAcsMessageHandler(); +} + +//------------------------------------------------------------------------------ +// createAndRegisterAcsMessageHandler +//------------------------------------------------------------------------------ +void AcsDaemon::createAndRegisterAcsMessageHandler() { + try { + std::unique_ptr<AcsMessageHandler> handler; + try { + handler.reset(new AcsMessageHandler(m_log, m_reactor, m_zmqContext, m_hostName, + m_config, m_acsPendingRequests)); //create event handler for communicating with the acs daemon + } catch(std::bad_alloc &ba) { + cta::exception::BadAlloc ex; + ex.getMessage() << + "Failed to create event handler for communicating with " + "the CTA ACS daemon: " << ba.what(); + throw ex; + } + m_reactor.registerHandler(handler.get()); + handler.release(); + } catch(cta::exception::Exception &ne) { + cta::exception::Exception ex; + ex.getMessage() << + "Failed to create and register AcsMessageHandler: " << + ne.getMessage().str(); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// mainEventLoop +//------------------------------------------------------------------------------ +void AcsDaemon::mainEventLoop() { + while(handleEvents()) { + } +} + +//------------------------------------------------------------------------------ +// handleEvents +//------------------------------------------------------------------------------ +bool AcsDaemon::handleEvents() { + try { + const int timeout = 100; // 100 milliseconds + m_reactor.handleEvents(timeout); + } catch(cta::exception::Exception &ex) { + // Log exception and continue + std::list<log::Param> params = { + log::Param("message", ex.getMessage().str()), + log::Param("backtrace", ex.backtrace()) + }; + m_log(LOG_ERR, + "Unexpected cta exception thrown when handling an I/O event", params); + } catch(std::exception &se) { + // Log exception and continue + std::list<log::Param> params = {log::Param("message", se.what())}; + m_log(LOG_ERR, "Unexpected exception thrown when handling an I/O event", + params); + } catch(...) { + // Log exception and continue + m_log(LOG_ERR, + "Unexpected and unknown exception thrown when handling an I/O event"); + } + + try { + handlePendingRequests(); + } catch(cta::exception::Exception &ex) { + // Log exception and continue + std::list<log::Param> params = { + log::Param("message", ex.getMessage().str()), + log::Param("backtrace", ex.backtrace()) + }; + m_log(LOG_ERR, + "Unexpected cta exception thrown when handling pending requests", + params); + } catch(std::exception &se) { + // Log exception and continue + std::list<log::Param> params = {log::Param("message", se.what())}; + m_log(LOG_ERR, + "Unexpected exception thrown when handling pending requests", params); + } catch(...) { + // Log exception and continue + m_log(LOG_ERR, + "Unexpected and unknown exception thrown when handling pending requests"); + } + + return handlePendingSignals(); +} + +//------------------------------------------------------------------------------ +// handlePendingRequests +//------------------------------------------------------------------------------ +void AcsDaemon::handlePendingRequests() { + m_acsPendingRequests.tick(); + m_acsPendingRequests.handleCompletedRequests(); + m_acsPendingRequests.handleFailedRequests(); + m_acsPendingRequests.handleToDeleteRequests(); +} + +//------------------------------------------------------------------------------ +// handlePendingSignals +//------------------------------------------------------------------------------ + +bool AcsDaemon::handlePendingSignals() throw() { + bool continueMainEventLoop = true; + int sig = 0; + sigset_t allSignals; + siginfo_t sigInfo; + sigfillset(&allSignals); + struct timespec immediateTimeout = {0, 0}; + + // While there is a pending signal to be handled + while (0 < (sig = sigtimedwait(&allSignals, &sigInfo, &immediateTimeout))) { + switch(sig) { + case SIGINT: // Signal number 2 + m_log(LOG_INFO, "Stopping gracefully because SIGINT was received"); + continueMainEventLoop = false; + break; + case SIGTERM: // Signal number 15 + m_log(LOG_INFO, "Stopping gracefully because SIGTERM was received"); + continueMainEventLoop = false; + break; + default: + { + std::list<log::Param> params = {log::Param("signal", sig)}; + m_log(LOG_INFO, "Ignoring signal", params); + } + break; + } + } + + return continueMainEventLoop; +} + + +}}}} diff --git a/mediachanger/acs/daemon/AcsDaemon.hpp b/mediachanger/acs/daemon/AcsDaemon.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b6f61f4e1ff9531441b9000f665307c0bfbbcf5f --- /dev/null +++ b/mediachanger/acs/daemon/AcsDaemon.hpp @@ -0,0 +1,213 @@ +/* + * 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/threading/Daemon.hpp" +#include "mediachanger/reactor/ZMQReactor.hpp" +#include "AcsdConfiguration.hpp" +#include "AcsPendingRequests.hpp" +#include "common/Constants.hpp" +#include "common/log/SyslogLogger.hpp" +#include "AcsdCmdLine.hpp" +#include "common/processCap/ProcessCap.hpp" +#include <signal.h> + +#include <getopt.h> + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * CTA ACS daemon responsible for mounting and dismounting tapes for ACS. + */ +class AcsDaemon : public server::Daemon { + +public: + /** + * Constructor. + * + * @param argc The argc of main(). + * @param argv The argv of main(). + * @param stdOut Stream representing standard out. + * @param stdErr Stream representing standard error. + * @param reactor The reactor responsible for dispatching the I/O requests to + * the CTA ACS daemon. + * @param config The CTA configuration parameters used by the CTA ACS + * daemon. + */ + AcsDaemon( + const int argc, + char **const argv, + log::Logger& log, + cta::mediachanger::reactor::ZMQReactor &reactor, + const AcsdConfiguration &config); + + /** + * Destructor. + */ + ~AcsDaemon() throw(); + + /** + * The main entry function of the daemon. + * + * @return The return code of the process. + */ + int main() throw(); + +protected: + + /** + * Returns the name of the host on which the daemon is running. + */ + std::string getHostName() const; + + /** + * Exception throwing main() function. + * + * @param argc The number of command-line arguments. + * @param argv The array of command-line arguments. + */ + void exceptionThrowingMain(const int argc, char **const argv); + + /** + * Logs the start of the daemon. + */ + void logStartOfDaemon(const int argc, const char *const *const argv) throw(); + + /** + * Creates a string that contains the specified command-line arguments + * separated by single spaces. + * + * @param argc The number of command-line arguments. + * @param argv The array of command-line arguments. + */ + std::string argvToString(const int argc, const char *const *const argv) + throw(); + + /** + * Idempotent method that destroys the ZMQ context. + */ + void destroyZmqContext() throw(); + + /** + * Sets the dumpable attribute of the current process to true. + */ + void setDumpable(); + + /** + * Blocks the signals that should not asynchronously disturb the daemon. + */ + void blockSignals() const; + + /** + * Initialises the ZMQ context. + */ + void initZmqContext(); + /** + * Sets up the reactor. + */ + void setUpReactor(); + + /** + * Creates the handler to handle messages for the acs Zmq requests. + */ + void createAndRegisterAcsMessageHandler(); + + /** + * The main event loop of the daemon. + */ + void mainEventLoop(); + + /** + * Handles any pending events. + * + * @return True if the main event loop should continue, else false. + */ + bool handleEvents(); + + /** + * Handles any pending signals. + * + * @return True if the main event loop should continue, else false. + */ + bool handlePendingSignals() throw(); + + /** + * Handles any pending Acs requests. + * + */ + void handlePendingRequests(); + + /** + * The argc of main(). + */ + const int m_argc; + + /** + * The argv of main(). + */ + char **const m_argv; + + log::Logger &m_log; + /** + * The reactor responsible for dispatching the file-descriptor event-handlers + * of the CTA ACS daemon. + */ + cta::mediachanger::reactor::ZMQReactor &m_reactor; + + /** + * The program name of the daemon. + */ + const std::string m_programName; + + /** + * The name of the host on which the daemon is running. + */ + const std::string m_hostName; + + /** + * The ZMQ context. + */ + void *m_zmqContext; + + /** + * The CTA configuration parameters used by the CTA ACS daemon. + */ + const AcsdConfiguration m_config; + + /** + * The object to handle requests to the CTA ACS daemon. + */ + AcsPendingRequests m_acsPendingRequests; + +private: + + /** + * Flag indicating whether the server should run in foreground or background + * mode. + */ + bool m_foreground; + +}; // class AcsDaemon + +} // namespace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsDaemonMain.cpp b/mediachanger/acs/daemon/AcsDaemonMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f603570ca84768e3a8543b8bd93fb34985dc24f --- /dev/null +++ b/mediachanger/acs/daemon/AcsDaemonMain.cpp @@ -0,0 +1,98 @@ +/* + * 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 "common/log/log.hpp" +#include "common/log/SyslogLogger.hpp" +#include "mediachanger/acs/Constants.hpp" +#include "AcsDaemon.hpp" +#include "AcsdCmdLine.hpp" +#include "mediachanger/reactor/ZMQReactor.hpp" +#include "AcsdConfiguration.hpp" +#include "common/utils/utils.hpp" +#include "common/exception/Exception.hpp" +#include <iostream> + + +//------------------------------------------------------------------------------ +// exceptionThrowingMain +// +// The main() function delegates the bulk of its implementation to this +// exception throwing version. +// +// @param argc The number of command-line arguments. +// @param argv The command-line arguments. +//------------------------------------------------------------------------------ +static int exceptionThrowingMain(cta::log::Logger &log,const int argc,char **const argv); + +//------------------------------------------------------------------------------ +// main +//------------------------------------------------------------------------------ +int main(const int argc, char **const argv) { + using namespace cta; + + const std::string shortHostName = utils::getShortHostname(); + cta::log::SyslogLogger logger(shortHostName, "cta-acsd", log::DEBUG); + try { + logger(LOG_INFO, "started ACSD in CTA"); + } catch(cta::exception::Exception &ex) { + std::cerr << + "Failed to instantiate object representing CTA logging system: " << + ex.getMessage().str() << std::endl; + return 1; + } + int programRc = 1; + try { + programRc = exceptionThrowingMain(logger, argc, argv) ; + } catch(cta::exception::Exception &ex) { + std::list<log::Param> params = { + log::Param("message", ex.getMessage().str())}; + logger(LOG_ERR, "Caught an unexpected CTA exception", params); + } catch(std::exception &se) { + std::list<log::Param> params = {log::Param("what", se.what())}; + logger(LOG_ERR, "Caught an unexpected standard exception", params); + } catch(...) { + logger(LOG_ERR, "Caught an unexpected and unknown exception"); + } + + return programRc; +} + +//------------------------------------------------------------------------------ +// exceptionThrowingMain +//------------------------------------------------------------------------------ +static int exceptionThrowingMain(cta::log::Logger &log, const int argc, char **const argv) { + + + cta::mediachanger::reactor::ZMQReactor reactor(log); + + const cta::mediachanger::acs::daemon::AcsdConfiguration config = cta::mediachanger::acs::daemon::AcsdConfiguration::createFromCtaConf("/etc/cta/cta-acsd.conf",log); + + + // Create the main acsd object + cta::mediachanger::acs::daemon::AcsDaemon daemon( + argc, + argv, + log, + reactor, + config); + + // Run the acsd daemon + return daemon.main(); + +return 0; +} diff --git a/mediachanger/acs/daemon/AcsDismountTape.cpp b/mediachanger/acs/daemon/AcsDismountTape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..99354c573a7e34ec1df86043eead8386c7d555b6 --- /dev/null +++ b/mediachanger/acs/daemon/AcsDismountTape.cpp @@ -0,0 +1,142 @@ +/* + * 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 "AcsDismountTape.hpp" +#include "common/exception/DismountFailed.hpp" +#include "common/log/log.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsDismountTape::AcsDismountTape( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + Acs &acsWrapper, + log::Logger& log, + const AcsdConfiguration &ctaConf): + cta::mediachanger::acs::AcsLibraryInteraction(acsWrapper, log), + m_volId(acsWrapper.str2Volid(vid)), + m_driveId(acsWrapper.alpd2DriveId(acs,lsm,panel,drive)), + m_acsWrapper(acsWrapper), + m_log(log), + m_ctaConf(ctaConf) { +} + +//------------------------------------------------------------------------------ +// execute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsDismountTape::execute() const { + syncDismount(); +} + +//------------------------------------------------------------------------------ +// asyncExecute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsDismountTape::asyncExecute(const SEQ_NO seqNo) const { + asyncDismount(seqNo); +} + + +//------------------------------------------------------------------------------ +// syncDismount +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsDismountTape::syncDismount() const { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendDismountRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, + m_ctaConf.QueryInterval.value(), + m_ctaConf.CmdTimeout.value()); + processDismountResponse(buf); + } catch(cta::exception::Exception &ex) { + cta::exception::DismountFailed df; + df.getMessage() << "Failed to dismount volume " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw df; + } +} + +//------------------------------------------------------------------------------ +// asyncDismount +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsDismountTape::asyncDismount(const SEQ_NO seqNo) const + { + try { + sendDismountRequest(seqNo); + } catch(cta::exception::Exception &ex) { + cta::exception::DismountFailed df; + df.getMessage() << "Failed to send dismount request to ACS " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw df; + } +} + +//------------------------------------------------------------------------------ +// sendDismountRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsDismountTape::sendDismountRequest( + const SEQ_NO seqNumber) const { + const LOCKID lockId = 0; // No lock + const BOOLEAN force = FALSE; + + std::stringstream dbgMsg; + dbgMsg << "Calling Acs::dismount() with seqNumber=" << seqNumber; + m_log(LOG_DEBUG, dbgMsg.str()); + const STATUS s = m_acsWrapper.dismount(seqNumber, lockId, m_volId, + m_driveId, force); + + dbgMsg.str(""); + dbgMsg << "Acs::dismount() for seqNumber=" << seqNumber << " returned " << + acs_status(s); + m_log(LOG_DEBUG,dbgMsg.str()); + if(STATUS_SUCCESS != s) { + cta::exception::DismountFailed ex; + ex.getMessage() << "Failed to send request to dismount volume " << + m_volId.external_label << " from drive " << + m_acsWrapper.driveId2Str(m_driveId) << ": force=" << + (force ? "TRUE" : "FALSE") << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processDismountResponse +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsDismountTape::processDismountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const + { + const ACS_DISMOUNT_RESPONSE *const msg = (ACS_DISMOUNT_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->dismount_status) { + cta::exception::DismountFailed ex; + ex.getMessage() << "Status of dismount response is not success: " << + acs_status(msg->dismount_status); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsDismountTape::~AcsDismountTape() throw() { +} diff --git a/mediachanger/acs/daemon/AcsDismountTape.hpp b/mediachanger/acs/daemon/AcsDismountTape.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bca01954a195dbf19b34c3a3d25cebaa9b4f17d3 --- /dev/null +++ b/mediachanger/acs/daemon/AcsDismountTape.hpp @@ -0,0 +1,130 @@ +/* + * 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 "mediachanger/acs/Acs.hpp" +#include "AcsdConfiguration.hpp" +#include "mediachanger/acs/AcsLibraryInteraction.hpp" + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * Class responsible for dismounting tapes through ACS API. + */ +class AcsDismountTape: public cta::mediachanger::acs::AcsLibraryInteraction { + +public: + + /** + * Constructor. + */ + AcsDismountTape( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + cta::log::Logger& log, + const mediachanger::acs::daemon::AcsdConfiguration &ctaConf); + + /** + * Destructor. + */ + ~AcsDismountTape() throw(); + + /** + * Execute dismount request through ACS API. + */ + void execute() const; + + /** + * Execute asynchronous dismount request through ACS API. + * + * @param The value of sequence number for ACS API. + */ + void asyncExecute(const SEQ_NO seqNo) const; + +protected: + + /** + * Dismounts the tape with the specified m_volId from the drive with the + * specified m_driveId. + * + * This method does not return until the dismount has either succeeded, failed + * or the specified timeout has been reached. + */ + void syncDismount() const; + + + /** + * Dismounts the tape with the specified m_volId from the drive with the + * specified m_driveId. + * This method sends a dismount request to ACSLS and returns. + * + * @param The value of sequence number for ACS API. + */ + void asyncDismount(const SEQ_NO seqNo) const; + + /** + * Sends the dismount request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendDismountRequest(const SEQ_NO seqNumber) const; + + /** + * Throws cta::exception::DismountFailed if the mount was not + * successful. + * + * @param buf The mount-response message. + */ + void processDismountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const; + + /** + * VOLID + */ + VOLID m_volId; + + /** + * DRIVEID + */ + DRIVEID m_driveId; + + /** + * Object providing c wrapper for ACS commands. + */ + Acs &m_acsWrapper; + + log::Logger &m_log; + /** + * The configuration parameters for the CTA ACS daemon. + */ + const mediachanger::acs::daemon::AcsdConfiguration m_ctaConf; + +}; // class AcsDismountTape + +} // namespace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsForceDismountTape.cpp b/mediachanger/acs/daemon/AcsForceDismountTape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..439b3b5e1fff332293acd06016d0760b73e0820f --- /dev/null +++ b/mediachanger/acs/daemon/AcsForceDismountTape.cpp @@ -0,0 +1,142 @@ +/* + * 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 "AcsForceDismountTape.hpp" +#include "common/exception/ForceDismountFailed.hpp" +#include "common/log/log.hpp" +#include "common/log/SyslogLogger.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsForceDismountTape::AcsForceDismountTape( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + cta::log::Logger& log, + const AcsdConfiguration &ctaConf): + AcsLibraryInteraction(acsWrapper, log), + m_volId(acsWrapper.str2Volid(vid)), + m_driveId(acsWrapper.alpd2DriveId(acs,lsm,panel,drive)), + m_acsWrapper(acsWrapper), + m_log(log), + m_ctaConf(ctaConf) { +} + +//------------------------------------------------------------------------------ +// execute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsForceDismountTape::execute() const { + syncForceDismount(); +} + +//------------------------------------------------------------------------------ +// asyncExecute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsForceDismountTape::asyncExecute(const SEQ_NO seqNo) const { + asyncForceDismount(seqNo); +} + + +//------------------------------------------------------------------------------ +// syncForceDismount +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsForceDismountTape::syncForceDismount() const { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendForceDismountRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, + m_ctaConf.QueryInterval.value(), + m_ctaConf.CmdTimeout.value()); + processForceDismountResponse(buf); + } catch(cta::exception::Exception &ex) { + cta::exception::ForceDismountFailed df; + df.getMessage() << "Failed to force dismount volume " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw df; + } +} + +//------------------------------------------------------------------------------ +// asyncDismount +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsForceDismountTape::asyncForceDismount(const SEQ_NO seqNo) + const { + try { + sendForceDismountRequest(seqNo); + } catch(cta::exception::Exception &ex) { + cta::exception::ForceDismountFailed df; + df.getMessage() << "Failed to send dismount request to ACS " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw df; + } +} + +//------------------------------------------------------------------------------ +// sendDismountRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsForceDismountTape::sendForceDismountRequest( + const SEQ_NO seqNumber) const { + const LOCKID lockId = 0; // No lock + const BOOLEAN force = TRUE; + + std::stringstream dbgMsg; + dbgMsg << "Calling Acs::dismount() with seqNumber=" << seqNumber; + m_log(LOG_DEBUG, dbgMsg.str()); + const STATUS s = m_acsWrapper.dismount(seqNumber, lockId, m_volId, + m_driveId, force); + + dbgMsg.str(""); + dbgMsg << "Acs::dismount() for seqNumber=" << seqNumber << " returned " << + acs_status(s); + m_log(LOG_DEBUG,dbgMsg.str()); + if(STATUS_SUCCESS != s) { + cta::exception::ForceDismountFailed ex; + ex.getMessage() << "Failed to send request to force dismount volume " << + m_volId.external_label << " from drive " << + m_acsWrapper.driveId2Str(m_driveId) << ": force=" << + (force ? "TRUE" : "FALSE") << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processForceDismountResponse +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsForceDismountTape::processForceDismountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const { + const ACS_DISMOUNT_RESPONSE *const msg = (ACS_DISMOUNT_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->dismount_status) { + cta::exception::ForceDismountFailed ex; + ex.getMessage() << "Status of force dismount response is not success: " << + acs_status(msg->dismount_status); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsForceDismountTape::~AcsForceDismountTape() throw() { +} diff --git a/mediachanger/acs/daemon/AcsForceDismountTape.hpp b/mediachanger/acs/daemon/AcsForceDismountTape.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0b92ec273c12976099b929bfedad869b24d1c0db --- /dev/null +++ b/mediachanger/acs/daemon/AcsForceDismountTape.hpp @@ -0,0 +1,133 @@ +/* + * 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 "mediachanger/acs/Acs.hpp" +#include "mediachanger/acs/daemon/AcsdConfiguration.hpp" +#include "mediachanger/acs/AcsLibraryInteraction.hpp" +#include "common/log/log.hpp" +#include "common/log/SyslogLogger.hpp" + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * Class responsible for dismounting tapes through ACS API. + */ +class AcsForceDismountTape: public cta::mediachanger::acs::AcsLibraryInteraction { + +public: + + /** + * Constructor. + */ + AcsForceDismountTape( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + log::Logger& log, + const AcsdConfiguration &ctaConf); + + /** + * Destructor. + */ + ~AcsForceDismountTape() throw(); + + /** + * Execute force dismount request through ACS API. + */ + void execute() const; + + /** + * Execute asynchronous force dismount request through ACS API. + * + * @param The value of sequence number for ACS API. + */ + void asyncExecute(const SEQ_NO seqNo) const; + +protected: + + /** + * Force dismounts the tape with the specified m_volId from the drive with the + * specified m_driveId. + * + * This method does not return until the dismount has either succeeded, failed + * or the specified timeout has been reached. + */ + void syncForceDismount() const; + + + /** + * Force dismounts the tape with the specified m_volId from the drive with the + * specified m_driveId. + * This method sends a dismount request to ACSLS and returns. + * + * @param The value of sequence number for ACS API. + */ + void asyncForceDismount(const SEQ_NO seqNo) const; + + /** + * Sends the force dismount request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendForceDismountRequest(const SEQ_NO seqNumber) const; + + /** + * Throws cta::exception::DismountFailed if the mount was not + * successful. + * + * @param buf The mount-response message. + */ + void processForceDismountResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const; + + /** + * VOLID + */ + VOLID m_volId; + + /** + * DRIVEID + */ + DRIVEID m_driveId; + + /** + * Object providing c wrapper for ACS commands. + */ + Acs &m_acsWrapper; + + log::Logger &m_log; + + /** + * The configuration parameters for the CTA ACS daemon. + */ + const AcsdConfiguration m_ctaConf; + +}; // class AcsForceDismountTape + +} // namespace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsMessageHandler.cpp b/mediachanger/acs/daemon/AcsMessageHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4388a97ff92451e51b1194810d29a510b96b1edb --- /dev/null +++ b/mediachanger/acs/daemon/AcsMessageHandler.cpp @@ -0,0 +1,444 @@ +/* + * 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 "common/Constants.hpp" +#include "mediachanger/acs/daemon/Constants.hpp" +#include "AcsMessageHandler.hpp" +#include "AcsDismountTape.hpp" +#include "AcsForceDismountTape.hpp" +#include "AcsMountTapeReadOnly.hpp" +#include "AcsMountTapeReadWrite.hpp" +#include "mediachanger/acs/Acs.hpp" +#include "mediachanger/acs/AcsImpl.hpp" +#include "common/log/log.hpp" +#include "common/log/SyslogLogger.hpp" +#include "mediachanger/messages.hpp" +#include "mediachanger/ReturnValue.pb.h" +#include "mediachanger/AcsMountTapeReadOnly.pb.h" +#include "mediachanger/AcsMountTapeReadWrite.pb.h" +#include "mediachanger/AcsDismountTape.pb.h" +#include "mediachanger/AcsForceDismountTape.pb.h" +#include "mediachanger/Exception.pb.h" +#include "mediachanger/reactor/ZMQPollEventHandler.hpp" +#include "mediachanger/reactor/ZMQReactor.hpp" +#include "mediachanger/ZmqSocket.hpp" +#include "errno.h" + +#include <iostream> +#include <unistd.h> + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsMessageHandler::AcsMessageHandler( + cta::log::Logger &log, + cta::mediachanger::reactor::ZMQReactor &reactor, + void *const zmqContext, + const std::string &hostName, + const AcsdConfiguration &ctaConf, + AcsPendingRequests &acsPendingRequests): + m_log(log), + m_reactor(reactor), + m_socket(zmqContext, ZMQ_ROUTER), + m_hostName(hostName), + m_ctaConf(ctaConf), + m_acsPendingRequests(acsPendingRequests) { + + std::ostringstream endpoint; + endpoint << "tcp://127.0.0.1:" << m_ctaConf.port.value(); + + try { + m_socket.bind(endpoint.str().c_str()); + std::list<log::Param> params = {log::Param("endpoint", endpoint.str())}; + m_log(LOG_INFO, "Bound the ZMQ socket of the AcsMessageHandler", + params); + } catch(cta::exception::Exception &ne){ + cta::exception::Exception ex; + ex.getMessage() << + "Failed to bind the ZMQ socket of the AcsMessageHandler" + ": endpoint=" << endpoint.str() << ": " << ne.getMessage().str(); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsMessageHandler::~AcsMessageHandler() + throw() { +} + +//------------------------------------------------------------------------------ +// getName +//------------------------------------------------------------------------------ +std::string cta::mediachanger::acs::daemon::AcsMessageHandler::getName() + const throw() { + return "AcsMessageHandler"; +} + +//------------------------------------------------------------------------------ +// fillPollFd +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMessageHandler::fillPollFd( + zmq_pollitem_t &fd) throw() { + fd.events = ZMQ_POLLIN; + fd.revents = 0; + fd.socket = m_socket.getZmqSocket(); + fd.fd = -1; +} + +//------------------------------------------------------------------------------ +// handleEvent +//------------------------------------------------------------------------------ +bool cta::mediachanger::acs::daemon::AcsMessageHandler::handleEvent( + const zmq_pollitem_t &fd) throw() { + // Try to receive a request, simply giving up if an exception is raised + cta::mediachanger::Frame rqst; + + //for handling zeroMQ's router socket type specific elements + //ie first frame = identity of the sender + // second one = empty + // third and following = actual data frames + + //The ZmqMsg address data can be dump as string and used as key for storing + //the identity (for clients who need a late answer) + cta::mediachanger::ZmqMsg address; + cta::mediachanger::ZmqMsg empty; + try { + checkSocket(fd); + m_socket.recv(address); + m_socket.recv(empty); + rqst = recvFrame(m_socket); + } catch(cta::exception::Exception &ex) { + std::list<log::Param> params = {log::Param("message", ex.getMessage().str())}; + m_log(LOG_ERR, "AcsMessageHandler failed to handle event", params); + return false; // Give up and stay registered with the reactor + } + std::list<log::Param> params = { + log::Param("sender identity", + utils::hexDump(address.getData(),address.size())) + }; + m_log(LOG_DEBUG, "handling event in AcsMessageHandler", params); + + // From this point on any exception thrown should be converted into an + // Exception message and sent back to the client + cta::mediachanger::Frame reply; + + try { + // if there are any problems we need to send the replay to the client. + reply = dispatchMsgHandler(rqst); + } catch(cta::exception::Exception &ex) { + reply = createExceptionFrame(ECANCELED, ex.getMessage().str()); + m_log(LOG_ERR, ex.getMessage().str()); + } catch(std::exception &se) { + reply = createExceptionFrame(ECANCELED, se.what()); + m_log(LOG_ERR, se.what()); + } catch(...) { + reply = createExceptionFrame(ECANCELED, "Caught an unknown exception"); + m_log(LOG_ERR, "Caught an unknown exception"); + } + + // Send the reply to the client + try { + //we need to prepend our frames the same way we received them + // ie identity + empty frames + m_socket.send(address,ZMQ_SNDMORE); + m_socket.send(empty,ZMQ_SNDMORE); + + cta::mediachanger::sendFrame(m_socket, reply); + } catch(cta::exception::Exception &ex) { + std::list<log::Param> params = {log::Param("message", ex.getMessage().str())}; + m_log(LOG_ERR, "AcsMessageHandler failed to send reply to client", params); + } + + return false; // Stay registered with the reactor +} + +//------------------------------------------------------------------------------ +// checkSocket +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMessageHandler::checkSocket( + const zmq_pollitem_t &fd) const{ + void* underlyingSocket = m_socket.getZmqSocket(); + if(fd.socket != underlyingSocket){ + cta::exception::Exception ex; + ex.getMessage() << "AcsMessageHandler passed wrong poll item"; + throw ex; + } +} + +//------------------------------------------------------------------------------ +// dispatchMsgHandler +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + dispatchMsgHandler(const cta::mediachanger::Frame &rqst) { + m_log(LOG_DEBUG, "AcsMessageHandler dispatching message handler"); + + const cta::mediachanger::acs::daemon::MsgType msgType = (cta::mediachanger::acs::daemon::MsgType)rqst.header.msgtype(); + switch(msgType) { + case cta::mediachanger::MSG_TYPE_ACSMOUNTTAPEREADONLY: + return handleAcsMountTapeReadOnly(rqst); + + case cta::mediachanger::MSG_TYPE_ACSMOUNTTAPEREADWRITE: + return handleAcsMountTapeReadWrite(rqst); + + case cta::mediachanger::MSG_TYPE_ACSDISMOUNTTAPE: + return handleAcsDismountTape(rqst); + + case cta::mediachanger::MSG_TYPE_ACSFORCEDISMOUNTTAPE: + return handleAcsForceDismountTape(rqst); + + default: + { + const std::string msgTypeStr = cta::mediachanger::acs::daemon::msgTypeToString(msgType); + cta::exception::Exception ex; + ex.getMessage() << "Failed to dispatch message handler" + ": Unexpected request type: msgType=" << msgType << " msgTypeStr=" << + msgTypeStr; + throw ex; + } + } +} + +//------------------------------------------------------------------------------ +// handleAcsMountTapeReadOnly +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + handleAcsMountTapeReadOnly(const cta::mediachanger::Frame &rqst) { + m_log(LOG_DEBUG, "Handling AcsMountTapeReadOnly message"); + + try { + cta::mediachanger::AcsMountTapeReadOnly rqstBody; + rqst.parseBodyIntoProtocolBuffer(rqstBody); + + const std::string vid = rqstBody.vid(); + const uint32_t acs = rqstBody.acs(); + const uint32_t lsm = rqstBody.lsm(); + const uint32_t panel = rqstBody.panel(); + const uint32_t drive = rqstBody.drive(); + + std::list<log::Param> params = {log::Param("TPVID", vid), + log::Param("acs", acs), + log::Param("lsm", lsm), + log::Param("panel", panel), + log::Param("drive", drive)}; + m_log(LOG_INFO, "Mount tape for read-only access", params); + + cta::mediachanger::acs::AcsImpl acsWrapper; + cta::mediachanger::acs::daemon::AcsMountTapeReadOnly acsMountTapeReadOnly(vid, acs, lsm, + panel, drive, acsWrapper, m_log, m_ctaConf); + try { + acsMountTapeReadOnly.execute(); + m_log(LOG_INFO,"Tape successfully mounted for read-only access", params); + } catch (cta::exception::Exception &ne) { + m_log(LOG_ERR,"Tape mount for read-only access failed: " + + ne.getMessage().str(), params); + throw; + } + const cta::mediachanger::Frame reply = createReturnValueFrame(0); + return reply; + } catch(cta::exception::Exception &ne) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to handle AcsMountTapeReadOnly message: " << + ne.getMessage().str(); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// handleAcsMountTapeReadWrite +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + handleAcsMountTapeReadWrite(const cta::mediachanger::Frame &rqst) { + m_log(LOG_DEBUG, "Handling AcsMountTapeReadWrite message"); + + try { + cta::mediachanger::AcsMountTapeReadWrite rqstBody; + rqst.parseBodyIntoProtocolBuffer(rqstBody); + + const std::string vid = rqstBody.vid(); + const uint32_t acs = rqstBody.acs(); + const uint32_t lsm = rqstBody.lsm(); + const uint32_t panel = rqstBody.panel(); + const uint32_t drive = rqstBody.drive(); + + std::list<log::Param> params = {log::Param("TPVID", vid), + log::Param("acs", acs), + log::Param("lsm", lsm), + log::Param("panel", panel), + log::Param("drive", drive)}; + m_log(LOG_INFO, "Mount tape for read/write access",params); + + cta::mediachanger::acs::AcsImpl acsWrapper; + cta::mediachanger::acs::daemon::AcsMountTapeReadWrite acsMountTapeReadWrite(vid, acs, + lsm, panel, drive, acsWrapper, m_log, m_ctaConf); + try { + acsMountTapeReadWrite.execute(); + m_log(LOG_INFO,"Tape successfully mounted for read/write access", params); + } catch (cta::exception::Exception &ne) { + m_log(LOG_ERR,"Tape mount for read/write access failed: " + + ne.getMessage().str(), params); + throw; + } + const cta::mediachanger::Frame reply = createReturnValueFrame(0); + return reply; + } catch(cta::exception::Exception &ne) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to handle AcsMountTapeReadWrite message: " << + ne.getMessage().str(); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// handleAcsDismountTape +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + handleAcsDismountTape(const cta::mediachanger::Frame& rqst) { + m_log(LOG_DEBUG, "Handling AcsDismountTape message"); + + try { + cta::mediachanger::AcsDismountTape rqstBody; + rqst.parseBodyIntoProtocolBuffer(rqstBody); + + const std::string vid = rqstBody.vid(); + const uint32_t acs = rqstBody.acs(); + const uint32_t lsm = rqstBody.lsm(); + const uint32_t panel = rqstBody.panel(); + const uint32_t drive = rqstBody.drive(); + + std::list<log::Param> params = {log::Param("TPVID", vid), + log::Param("acs", acs), + log::Param("lsm", lsm), + log::Param("panel", panel), + log::Param("drive", drive)}; + m_log(LOG_INFO, "Dismount tape",params); + + cta::mediachanger::acs::AcsImpl acsWrapper; + cta::mediachanger::acs::daemon::AcsDismountTape acsDismountTape(vid, acs, lsm, panel, drive, + acsWrapper, m_log, m_ctaConf); + try { + acsDismountTape.execute(); + m_log(LOG_INFO,"Tape successfully dismounted", params); + } catch (cta::exception::Exception &ne) { + m_log(LOG_ERR,"Tape dismount failed: "+ne.getMessage().str(), params); + throw; + } + const cta::mediachanger::Frame reply = createReturnValueFrame(0); + return reply; + } catch(cta::exception::Exception &ne) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to handle AcsDismountTape message: " << + ne.getMessage().str(); + throw ex; + } catch(...) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to handle AcsDismountTape message: " + << "Caught an unknown exception"; + throw ex; + } +} + +//------------------------------------------------------------------------------ +// handleAcsForceDismountTape +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + handleAcsForceDismountTape(const cta::mediachanger::Frame& rqst) { + m_log(LOG_DEBUG, "Handling AcsDismountTape message"); + + try { + cta::mediachanger::AcsForceDismountTape rqstBody; + rqst.parseBodyIntoProtocolBuffer(rqstBody); + + const std::string vid = rqstBody.vid(); + const uint32_t acs = rqstBody.acs(); + const uint32_t lsm = rqstBody.lsm(); + const uint32_t panel = rqstBody.panel(); + const uint32_t drive = rqstBody.drive(); + + std::list<log::Param> params = {log::Param("TPVID", vid), + log::Param("acs", acs), + log::Param("lsm", lsm), + log::Param("panel", panel), + log::Param("drive", drive)}; + m_log(LOG_INFO, "Force dismount tape", params); + + cta::mediachanger::acs::AcsImpl acsWrapper; + cta::mediachanger::acs::daemon::AcsForceDismountTape acsForceDismountTape(vid, acs, lsm, + panel, drive, acsWrapper, m_log, m_ctaConf); + try { + acsForceDismountTape.execute(); + m_log(LOG_INFO,"Tape successfully force dismounted", params); + } catch (cta::exception::Exception &ne) { + m_log(LOG_ERR,"Tape force dismount failed: "+ne.getMessage().str(), + params); + throw; + } + const cta::mediachanger::Frame reply = createReturnValueFrame(0); + return reply; + } catch(cta::exception::Exception &ne) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to handle AcsForceDismountTape message: " << + ne.getMessage().str(); + throw ex; + } catch(...) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to handle AcsForceDismountTape message: " + << "Caught an unknown exception"; + throw ex; + } +} + +//------------------------------------------------------------------------------ +// createReturnValueFrame +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + createReturnValueFrame(const int value) { + cta::mediachanger::Frame frame; + + frame.header = cta::mediachanger::protoTapePreFillHeader(); + frame.header.set_msgtype(cta::mediachanger::MSG_TYPE_RETURNVALUE); + frame.header.set_bodyhashvalue(cta::mediachanger::computeSHA1Base64(frame.body)); + frame.header.set_bodysignature("PIPO"); + + cta::mediachanger::ReturnValue body; + body.set_value(value); + frame.serializeProtocolBufferIntoBody(body); + + return frame; +} + +//------------------------------------------------------------------------------ +// createExceptionFrame +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsMessageHandler:: + createExceptionFrame(const int code, const std::string& msg) { + cta::mediachanger::Frame frame; + + frame.header = cta::mediachanger::protoTapePreFillHeader(); + frame.header.set_msgtype(cta::mediachanger::MSG_TYPE_EXCEPTION); + frame.header.set_bodyhashvalue(cta::mediachanger::computeSHA1Base64(frame.body)); + frame.header.set_bodysignature("PIPO"); + + cta::mediachanger::Exception body; + body.set_code(code); + body.set_message(msg); + frame.serializeProtocolBufferIntoBody(body); + + return frame; +} diff --git a/mediachanger/acs/daemon/AcsMessageHandler.hpp b/mediachanger/acs/daemon/AcsMessageHandler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..54990856429e8f94b3982c7cff961948a4185a3d --- /dev/null +++ b/mediachanger/acs/daemon/AcsMessageHandler.hpp @@ -0,0 +1,187 @@ +/* + * 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 "mediachanger/acs/Constants.hpp" +#include "mediachanger/Frame.hpp" +#include "mediachanger/ZmqSocket.hpp" +#include "mediachanger/reactor/ZMQReactor.hpp" +#include "AcsDaemon.hpp" +#include "AcsdConfiguration.hpp" +#include "AcsPendingRequests.hpp" +#include "common/log/SyslogLogger.hpp" +#include "mediachanger/reactor/ZMQPollEventHandler.hpp" + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * Handles the events of the socket listening for connection from the tape + * server daemon. + */ +class AcsMessageHandler: public cta::mediachanger::reactor::ZMQPollEventHandler { +public: + + /** + * Constructor. + * + * @param reactor The reactor to which new CTA ACS daemon connection + * handlers are to be registered. + * @param hostName The name of the host. + * @param zmqContext The ZMQ context. + * @param ctaConf The configuration for the CTA ACS daemon. + * @param acsPendingRequests The object to handle requests to the CTA ACS + * daemon. + */ + AcsMessageHandler( + log::Logger &log, + cta::mediachanger::reactor::ZMQReactor &reactor, + void *const zmqContext, + const std::string &hostName, + const AcsdConfiguration &ctaConf, + AcsPendingRequests &acsPendingRequests); + + /** + * Destructor. + */ + ~AcsMessageHandler() throw(); + + /** + * Returns the human-readable name this event handler. + */ + std::string getName() const throw(); + + /** + * Fills the specified poll file-descriptor ready to be used in a call to + * poll(). + */ + void fillPollFd(zmq_pollitem_t &fd) throw(); + + /** + * Handles the specified event. + * + * @param fd The poll file-descriptor describing the event. + * @return true if the event handler should be removed from and deleted by + * the reactor. + */ + bool handleEvent(const zmq_pollitem_t &fd) throw(); + +private: + + /** + * Creates a message frame containing a ReturnValue message. + * + * @param value The return value of the ReturnValue message. + * @return The message frame. + */ + cta::mediachanger::Frame createReturnValueFrame(const int value); + + /** + * Creates a message frame containing an Exception message. + * + * @param code The error code of the exception. + * @param msg The message string of the exception. + */ + cta::mediachanger::Frame createExceptionFrame(const int code, + const std::string& msg); + + /** + * Make sure the zmq_pollitem_t's socket is the same as m_socket + * Throw an exception if it is not the case + * @param fd the poll item + */ + void checkSocket(const zmq_pollitem_t &fd) const; + + /** + * Dispatches the appropriate handler method for the specified request + * message. + * + * @param rqst The request. + * @return The reply. + */ + cta::mediachanger::Frame dispatchMsgHandler(const cta::mediachanger::Frame &rqst) ; + + /** + * Handles the mount tape for read-only. + * + * @param rqst The request. + * @return The reply. + */ + cta::mediachanger::Frame handleAcsMountTapeReadOnly(const cta::mediachanger::Frame &rqst); + + /** + * Handles the mount tape for read/write. + * + * @param rqst The request. + * @return The reply. + */ + cta::mediachanger::Frame handleAcsMountTapeReadWrite(const cta::mediachanger::Frame &rqst); + + /** + * Handles the dismount tape request. + * + * @param rqst The request. + * @return The reply. + */ + cta::mediachanger::Frame handleAcsDismountTape(const cta::mediachanger::Frame &rqst); + + /** + * Handles the force dismount tape request. + * + * @param rqst The request. + * @return The reply. + */ + cta::mediachanger::Frame handleAcsForceDismountTape(const cta::mediachanger::Frame &rqst); + + log::Logger &m_log; + /** + * The reactor to which new CTA ACS daemon connection handlers are to + * be registered. + */ + cta::mediachanger::reactor::ZMQReactor &m_reactor; + + /** + * The ZMQ socket listening for messages. + */ + cta::mediachanger::ZmqSocketST m_socket; + + /** + * The name of the host on which CTA ACS daemon is running. + */ + const std::string m_hostName; + + + /** + * The configuration parameters for the CTA ACS daemon. + */ + const acs::daemon::AcsdConfiguration m_ctaConf; + + /** + * The object to handle requests to the CTA ACS daemon. + */ + AcsPendingRequests &m_acsPendingRequests; + +}; // class AcsMessageHandler + +} // namespace deamon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsMountTapeReadOnly.cpp b/mediachanger/acs/daemon/AcsMountTapeReadOnly.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b1b83efd0e578869751df799bb5ce4569295b54 --- /dev/null +++ b/mediachanger/acs/daemon/AcsMountTapeReadOnly.cpp @@ -0,0 +1,213 @@ +/* + * 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 "AcsMountTapeReadOnly.hpp" +#include "common/exception/MountFailed.hpp" +#include "common/exception/QueryVolumeFailed.hpp" +#include "common/log/log.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::AcsMountTapeReadOnly( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + log::Logger& log, + const AcsdConfiguration &ctaConf): + AcsLibraryInteraction(acsWrapper, log), + m_volId(acsWrapper.str2Volid(vid)), + m_driveId(acsWrapper.alpd2DriveId(acs,lsm,panel,drive)), + m_acsWrapper(acsWrapper), + m_log(log), + m_ctaConf(ctaConf) { +} + +//------------------------------------------------------------------------------ +// execute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::execute() const { + try { + syncMountTapeReadOnly(); + } catch (cta::exception::MountFailed &mountFailed) { + try { + const std::string queryVolumeResponse = syncQueryVolume(); + mountFailed.getMessage() << " : The query volume response: " << + queryVolumeResponse; + } catch (cta::exception::QueryVolumeFailed &queryFailed) { + mountFailed.getMessage() << " : " << queryFailed.getMessage().str(); + } + throw mountFailed; + } +} + +//------------------------------------------------------------------------------ +// syncMountTapeReadOnly +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::syncMountTapeReadOnly() const + { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendMountTapeReadOnlyRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, + m_ctaConf.QueryInterval.value(), m_ctaConf.CmdTimeout.value()); + processMountTapeReadOnlyResponse(buf); + } catch(cta::exception::Exception &ex) { + cta::exception::MountFailed mf; + mf.getMessage() << "Failed to mount for read-only access volume " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw mf; + } +} + +//------------------------------------------------------------------------------ +// sendMountTapeReadOnlyRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::sendMountTapeReadOnlyRequest( + const SEQ_NO seqNumber) const { + const LOCKID lockId = 0; // No lock + const BOOLEAN bypass = FALSE; + const BOOLEAN readOnly = TRUE; + + m_log(LOG_DEBUG,"Calling Acs::mount()"); + const STATUS s = m_acsWrapper.mount(seqNumber, lockId, m_volId, + m_driveId, readOnly, bypass); + std::stringstream dbgMsg; + dbgMsg << "Acs::mount() returned " << acs_status(s); + m_log(LOG_DEBUG,dbgMsg.str()); + + if(STATUS_SUCCESS != s) { + cta::exception::MountFailed ex; + ex.getMessage() << "Failed to send request to mount for read-only access" + " volume " << m_volId.external_label << " into drive " << + m_acsWrapper.driveId2Str(m_driveId) << ": readOnly=" << + (readOnly ? "TRUE" : "FALSE") << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processMountTapeReadOnlyResponse +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::processMountTapeReadOnlyResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const + { + const ACS_MOUNT_RESPONSE *const msg = (ACS_MOUNT_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->mount_status) { + cta::exception::MountFailed ex; + ex.getMessage() << "Status of mount response is not success: " << + acs_status(msg->mount_status); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// syncQueryVolume +//------------------------------------------------------------------------------ +std::string cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::syncQueryVolume() const { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + try { + sendQueryVolumeRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, + m_ctaConf.QueryInterval.value(), m_ctaConf.CmdTimeout.value()); + return processQueryResponse(buf); + } catch(cta::exception::Exception &ex) { + cta::exception::QueryVolumeFailed qf; + qf.getMessage() << "Failed to query volume " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw qf; + } +} + +//------------------------------------------------------------------------------ +// sendQueryVolumeRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::sendQueryVolumeRequest ( + const SEQ_NO seqNumber) const { + VOLID volIds[MAX_ID]; + + memset(volIds, '\0', sizeof(volIds)); + strncpy(volIds[0].external_label, m_volId.external_label, + sizeof(volIds[0].external_label)); + volIds[0].external_label[sizeof(volIds[0].external_label) - 1] = '\0'; + + m_log(LOG_DEBUG,"Calling Acs::queryVolume()"); + + const STATUS s = m_acs.queryVolume(seqNumber, volIds, 1); + + std::stringstream dbgMsg; + dbgMsg << "Acs::queryVolume() returned " << acs_status(s); + m_log(LOG_DEBUG,"Calling Acs::queryVolume()"); + + if(STATUS_SUCCESS != s) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Failed to send query request for volume " << + m_volId.external_label << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processQueryResponse +//------------------------------------------------------------------------------ +std::string cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::processQueryResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const { + + const ACS_QUERY_VOL_RESPONSE *const msg = (ACS_QUERY_VOL_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->query_vol_status) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Status of query response is not success: " << + acs_status(msg->query_vol_status); + throw ex; + } + + if((unsigned short)1 != msg->count) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Query response does not contain a single volume: count=" + << msg->count; + throw ex; + } + + // count is 1 so it is safe to make a reference to the single volume status + const QU_VOL_STATUS &volStatus = msg->vol_status[0]; + + if(strcmp(m_volId.external_label, volStatus.vol_id.external_label)) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << + "Volume identifier of query response does not match that of request" + ": requestVID=" << m_volId.external_label << + " responseVID=" << volStatus.vol_id.external_label; + throw ex; + } + + return volumeStatusAsString(volStatus); +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsMountTapeReadOnly::~AcsMountTapeReadOnly() throw() { +} diff --git a/mediachanger/acs/daemon/AcsMountTapeReadOnly.hpp b/mediachanger/acs/daemon/AcsMountTapeReadOnly.hpp new file mode 100644 index 0000000000000000000000000000000000000000..51019d304115f6a73c2d2afe5d99802e57d32bdd --- /dev/null +++ b/mediachanger/acs/daemon/AcsMountTapeReadOnly.hpp @@ -0,0 +1,142 @@ +/* + * 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 "mediachanger/acs/Acs.hpp" +#include "AcsdConfiguration.hpp" +#include "mediachanger/acs/AcsLibraryInteraction.hpp" + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * Class responsible for mounting tapes for read-only access through ACS API. + */ +class AcsMountTapeReadOnly: public cta::mediachanger::acs::AcsLibraryInteraction { + +public: + + /** + * Constructor. + */ + AcsMountTapeReadOnly( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + cta::log::Logger& log, + const AcsdConfiguration &ctaConf); + + /** + * Destructor. + */ + ~AcsMountTapeReadOnly() throw(); + + /** + * Execute mount request through ACS API. + * Throws cta::exception::Exception if the mount is not successful. Adds to + * the exception the result of the query volume request for the given volume. + */ + void execute() const ; + +protected: + + /** + * mounts the tape with the specified VID into the drive with the specified + * drive ID. + * + * This method does not return until the mount has either succeeded, failed or + * the specified timeout has been reached. + */ + void syncMountTapeReadOnly() const; + + /** + * Sends the mount request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendMountTapeReadOnlyRequest(const SEQ_NO seqNumber) const; + + /** + * Throws cta::exception::MountFailed if the mount was not + * successful. + * + * @param buf The mount-response message. + */ + void processMountTapeReadOnlyResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const; + + /** + * Queries ACS for information about the volume identifier. + * + * This method does not return until the information has been successfully + * retrieved, an error has occurred or the specified timeout has been + * reached. + * + * @return The string presentation of the query volume response. + */ + std::string syncQueryVolume() const; + + /** + * Sends the query volume request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendQueryVolumeRequest(const SEQ_NO seqNumber) const; + + /** + * Extracts the volume status from the specified query-response message and + * returns it in human-readable form. + * + * @param buf The query-response message. + * @return The string presentation of the query volume response. + */ + std::string processQueryResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const; + + /** + * ACS VOLID + */ + VOLID m_volId; + + /** + * ACS DRIVEID + */ + DRIVEID m_driveId; + + /** + * Object providing c wrapper for ACS commands. + */ + Acs &m_acsWrapper; + log::Logger& m_log; + /** + * The configuration parameters for the CTA ACS daemon. + */ + const AcsdConfiguration m_ctaConf; + +}; // class AcsMountTapeReadOnly + +} // namespace daemon +} // namepsace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsMountTapeReadWrite.cpp b/mediachanger/acs/daemon/AcsMountTapeReadWrite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d7dc1ff4dd0768be486fa59637d086d61ebf1035 --- /dev/null +++ b/mediachanger/acs/daemon/AcsMountTapeReadWrite.cpp @@ -0,0 +1,216 @@ +/* + * 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 "AcsMountTapeReadWrite.hpp" +#include "common/exception/MountFailed.hpp" +#include "mediachanger/acs/AcsLibraryInteraction.hpp" +#include "common/exception/QueryVolumeFailed.hpp" +#include "common/log/log.hpp" + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::AcsMountTapeReadWrite( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + cta::log::Logger &log, + const AcsdConfiguration &ctaConf): + AcsLibraryInteraction(acsWrapper, log), + m_volId(acsWrapper.str2Volid(vid)), + m_driveId(acsWrapper.alpd2DriveId(acs,lsm,panel,drive)), + m_acsWrapper(acsWrapper), + m_log(log), + m_ctaConf(ctaConf) { +} + +//------------------------------------------------------------------------------ +// execute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::execute() const { + try { + syncMountTapeReadWrite(); + } catch (cta::exception::MountFailed &mountFailed) { + try { + const std::string queryVolumeResponse = syncQueryVolume(); + mountFailed.getMessage() << " : The query volume response: " << + queryVolumeResponse; + } catch (cta::exception::QueryVolumeFailed &queryFailed) { + mountFailed.getMessage() << " : " << queryFailed.getMessage().str(); + } + throw mountFailed; + } +} + +//------------------------------------------------------------------------------ +// syncMountTapeReadWrite +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::syncMountTapeReadWrite() const + { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + try { + sendMountTapeReadWriteRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, + m_ctaConf.QueryInterval.value(), m_ctaConf.CmdTimeout.value()); + processMountTapeReadWriteResponse(buf); + } catch(cta::exception::Exception &ex) { + cta::exception::MountFailed mf; + mf.getMessage() << "Failed to mount for read/write access volume " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw mf; + } +} + +//------------------------------------------------------------------------------ +// sendMountTapeReadWriteRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::sendMountTapeReadWriteRequest( + const SEQ_NO seqNumber) const { + const LOCKID lockId = 0; // No lock + const BOOLEAN bypass = FALSE; + const BOOLEAN readOnly = FALSE; + + m_log(LOG_DEBUG,"Calling Acs::mount()"); + const STATUS s = m_acsWrapper.mount(seqNumber, lockId, m_volId, + m_driveId, readOnly, bypass); + std::stringstream dbgMsg; + dbgMsg << "Acs::mount() returned " << acs_status(s); + m_log(LOG_DEBUG,dbgMsg.str()); + + if(STATUS_SUCCESS != s) { + cta::exception::MountFailed ex; + ex.getMessage() << "Failed to send request to mount for read/write access" + " volume " << m_volId.external_label << " into drive " + << m_acsWrapper.driveId2Str(m_driveId) + << ": readOnly=" + << (readOnly ? "TRUE" : "FALSE") << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processMountTapeReadWriteResponse +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::processMountTapeReadWriteResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const + { + const ACS_MOUNT_RESPONSE *const msg = (ACS_MOUNT_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->mount_status) { + cta::exception::MountFailed ex; + ex.getMessage() << "Status of mount response is not success: " << + acs_status(msg->mount_status); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// syncQueryVolume +//------------------------------------------------------------------------------ +std::string cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::syncQueryVolume() const { + const SEQ_NO requestSeqNumber = 1; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + try { + sendQueryVolumeRequest(requestSeqNumber); + requestResponsesUntilFinal(requestSeqNumber, buf, + m_ctaConf.QueryInterval.value(), m_ctaConf.CmdTimeout.value()); + return processQueryResponse(buf); + } catch(cta::exception::Exception &ex) { + cta::exception::QueryVolumeFailed qf; + qf.getMessage() << "Failed to query volume " << + m_volId.external_label << ": " << ex.getMessage().str(); + throw qf; + } +} + +//------------------------------------------------------------------------------ +// sendQueryVolumeRequest +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::sendQueryVolumeRequest ( + const SEQ_NO seqNumber) const { + VOLID volIds[MAX_ID]; + + memset(volIds, '\0', sizeof(volIds)); + strncpy(volIds[0].external_label, m_volId.external_label, + sizeof(volIds[0].external_label)); + volIds[0].external_label[sizeof(volIds[0].external_label) - 1] = '\0'; + + m_log(LOG_DEBUG,"Calling Acs::queryVolume()"); + + + const STATUS s = m_acs.queryVolume(seqNumber, volIds, 1); + + std::stringstream dbgMsg; + dbgMsg << "Acs::queryVolume() returned " << acs_status(s); + m_log(LOG_DEBUG,"Calling Acs::queryVolume()"); + + if(STATUS_SUCCESS != s) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Failed to send query request for volume " << + m_volId.external_label << ": " << acs_status(s); + throw ex; + } +} + +//------------------------------------------------------------------------------ +// processQueryResponse +//------------------------------------------------------------------------------ +std::string cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::processQueryResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const { + + const ACS_QUERY_VOL_RESPONSE *const msg = (ACS_QUERY_VOL_RESPONSE *)buf; + + if(STATUS_SUCCESS != msg->query_vol_status) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Status of query response is not success: " << + acs_status(msg->query_vol_status); + throw ex; + } + + if((unsigned short)1 != msg->count) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << "Query response does not contain a single volume: count=" + << msg->count; + throw ex; + } + + // count is 1 so it is safe to make a reference to the single volume status + const QU_VOL_STATUS &volStatus = msg->vol_status[0]; + + if(strcmp(m_volId.external_label, volStatus.vol_id.external_label)) { + cta::exception::QueryVolumeFailed ex; + ex.getMessage() << + "Volume identifier of query response does not match that of request" + ": requestVID=" << m_volId.external_label << + " responseVID=" << volStatus.vol_id.external_label; + throw ex; + } + + return volumeStatusAsString(volStatus); +} + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsMountTapeReadWrite::~AcsMountTapeReadWrite() throw() { +} diff --git a/mediachanger/acs/daemon/AcsMountTapeReadWrite.hpp b/mediachanger/acs/daemon/AcsMountTapeReadWrite.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a2d42306443ed192b0af9786c1e90f2141562fa1 --- /dev/null +++ b/mediachanger/acs/daemon/AcsMountTapeReadWrite.hpp @@ -0,0 +1,142 @@ +/* + * 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 "mediachanger/acs/Acs.hpp" +#include "AcsdConfiguration.hpp" +#include "mediachanger/acs/AcsLibraryInteraction.hpp" + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * Class responsible for mounting tapes for read/write access through ACS API. + */ +class AcsMountTapeReadWrite: public cta::mediachanger::acs::AcsLibraryInteraction { + +public: + + /** + * Constructor. + */ + AcsMountTapeReadWrite( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + cta::mediachanger::acs::Acs &acsWrapper, + log::Logger& log, + const AcsdConfiguration &ctaConf); + + /** + * Destructor. + */ + ~AcsMountTapeReadWrite() throw(); + + /** + * Execute mount request through ACS API. + */ + void execute() const; + +protected: + + /** + * mounts the tape with the specified VID into the drive with the specified + * drive ID. + * + * This method does not return until the mount has either succeeded, failed or + * the specified timeout has been reached. + */ + void syncMountTapeReadWrite() const; + + /** + * Sends the mount request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendMountTapeReadWriteRequest(const SEQ_NO seqNumber) const; + + /** + * Throws cta::exception::MountFailed if the mount was not + * successful. + * + * @param buf The mount-response message. + */ + void processMountTapeReadWriteResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const; + + /** + * Queries ACS for information about the volume identifier. + * + * This method does not return until the information has been successfully + * retrieved, an error has occurred or the specified timeout has been + * reached. + * + * @return The string presentation of the query volume response. + */ + std::string syncQueryVolume() const; + + /** + * Sends the query volume request to ACSLS. + * + * @param seqNumber The sequence number to be used in the request. + */ + void sendQueryVolumeRequest(const SEQ_NO seqNumber) const; + + /** + * Extracts the volume status from the specified query-response message and + * returns it in human-readable form. + * + * @param buf The query-response message. + * @return The string presentation of the query volume response. + */ + std::string processQueryResponse( + ALIGNED_BYTES (&buf)[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]) const; + + /** + * ACS VOLID + */ + VOLID m_volId; + + /** + * ACS DRIVEID + */ + DRIVEID m_driveId; + + /** + * Object providing C wrapper for ACS commands. + */ + Acs &m_acsWrapper; + + log::Logger& m_log; + + /** + * The configuration parameters for the CTA ACS daemon. + */ + const AcsdConfiguration m_ctaConf; + +}; // class AcsMountTapeReadWrite + +} // namespace daemon +} // namepsace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsPendingRequests.cpp b/mediachanger/acs/daemon/AcsPendingRequests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fedb8521552783d50ad8480315cd46855ec2f04c --- /dev/null +++ b/mediachanger/acs/daemon/AcsPendingRequests.cpp @@ -0,0 +1,331 @@ +/* + * 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 "AcsPendingRequests.hpp" +#include "mediachanger/acs/AcsImpl.hpp" +#include "mediachanger/acs/daemon/AcsRequest.hpp" +#include "mediachanger/acs/daemon/AcsDismountTape.hpp" +#include "AcsRequestDismountTape.hpp" +#include "common/Constants.hpp" +#include "mediachanger/Constants.hpp" +#include "mediachanger/acs/daemon/Constants.hpp" +#include "common/log/log.hpp" +#include "mediachanger/messages.hpp" +#include "mediachanger/Frame.hpp" +#include "mediachanger/AcsDismountTape.pb.h" +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::daemon::AcsPendingRequests::AcsPendingRequests( + const AcsdConfiguration &ctaConf, cta::log::Logger &l): + m_ctaConf(ctaConf), + m_log(l), + m_lastTimeResponseUsed(0) { +} + +//----------------------------------------------------------------------------- +// destructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::daemon::AcsPendingRequests::~AcsPendingRequests() throw() { + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end(); itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + delete acsRequest; + } +} + +//----------------------------------------------------------------------------- +// tick +//----------------------------------------------------------------------------- + + void cta::mediachanger::acs::daemon::AcsPendingRequests::tick() { + bool haveRunningRequests = false; + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + acsRequest->tick(); + if(acsRequest->isRunning()) { + haveRunningRequests = true; + } + } + + if (haveRunningRequests) { + const time_t now = time(0); + + const time_t secsSinceLastResponse = now - m_lastTimeResponseUsed; + const bool responseTimeExceeded = secsSinceLastResponse > + ACS_RESPONSE_TIMEOUT; + + if (responseTimeExceeded) { + const int responseTimeout = 0 ; // 0 - means pool for + // the existence of a response. + + SEQ_NO responseSeqNumber = 0; + REQ_ID reqId = (REQ_ID)0; + ACS_RESPONSE_TYPE responseType = RT_NONE; + ALIGNED_BYTES buf[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + + m_log(LOG_DEBUG, + "AcsPendingRequests::tick() Calling Acs::response()"); + + const STATUS responseStatus = m_acs.response(responseTimeout, + responseSeqNumber, reqId, responseType, buf); + + if (STATUS_SUCCESS == responseStatus) { + setRequestResponse(responseSeqNumber,responseType, buf); + } + m_lastTimeResponseUsed = time(0); + } + } +} + +//----------------------------------------------------------------------------- +// setRequestResponse +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::setRequestResponse( + const SEQ_NO responseSeqNumber, const ACS_RESPONSE_TYPE responseType, + const ALIGNED_BYTES *const responseMsg) { + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + if ( responseSeqNumber == acsRequest->getSeqNo()) { + std::stringstream dbgMsg; + dbgMsg << "AcsPendingRequests::setRequestResponse responseType=" << + responseType << " " << acsRequest->str(); + m_log(LOG_DEBUG, dbgMsg.str()); + acsRequest->setResponse(responseType, responseMsg); + } + } +} + +//----------------------------------------------------------------------------- +// handleCompletedRequests +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::handleCompletedRequests() { + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + if (acsRequest->isCompleted()) { + std::list<log::Param> params = {log::Param("TPVID", acsRequest->getVid()), + log::Param("acs", acsRequest->getAcs()), + log::Param("lsm", acsRequest->getLsm()), + log::Param("panel", acsRequest->getPanel()), + log::Param("drive", acsRequest->getDrive()), + log::Param("sender identity", acsRequest->getIdentity()) + }; + m_log(LOG_INFO,"Tape successfully dismounted",params); + acsRequest->sendReplayToClientOnce(); + acsRequest->setStateToDelete(); + } + } +} + +//----------------------------------------------------------------------------- +// handleFailedRequests +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::handleFailedRequests() { + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + if (acsRequest->isFailed()) { + std::list<log::Param> params = {log::Param("TPVID", acsRequest->getVid()), + log::Param("acs", acsRequest->getAcs()), + log::Param("lsm", acsRequest->getLsm()), + log::Param("panel", acsRequest->getPanel()), + log::Param("drive", acsRequest->getDrive()), + log::Param("sender identity", acsRequest->getIdentity()) + }; + m_log(LOG_INFO,"Dismount tape failed", params); + acsRequest->sendReplayToClientOnce(); + acsRequest->setStateToDelete(); + } + } +} + +//----------------------------------------------------------------------------- +// handleToDeleteRequests +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::handleToDeleteRequests() { + for(RequestList::iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + if (acsRequest->isToDelete()) { + m_log(LOG_DEBUG,"AcsPendingRequests::handleToDeleteRequests " + + acsRequest->str()); + delete acsRequest; + itor=m_acsRequestList.erase(itor); + } + } +} + +//----------------------------------------------------------------------------- +// checkAndAddRequest +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::checkAndAddRequest( + mediachanger::ZmqMsg &address, mediachanger::ZmqMsg &empty, + const cta::mediachanger::Frame &rqst, cta::mediachanger::ZmqSocketST &socket) { + std::list<log::Param> params = { + log::Param("sender identity", + utils::hexDump(address.getData(), address.size())) + }; + m_log(LOG_DEBUG, "AcsPendingRequests::checkAndAddRequest", params); + + const cta::mediachanger::acs::daemon::MsgType msgType = (cta::mediachanger::acs::daemon::MsgType)rqst.header.msgtype(); + switch(msgType) { + case mediachanger::MSG_TYPE_ACSMOUNTTAPEREADONLY: + case mediachanger::MSG_TYPE_ACSMOUNTTAPEREADWRITE: + { + cta::exception::Exception ex; + ex.getMessage() << "Failed to check request" + ": Handling of this message type is not implemented: msgtype=" << + rqst.header.msgtype(); + throw ex; + } + case mediachanger::MSG_TYPE_ACSDISMOUNTTAPE: + checkAndAddRequestDismountTape(address, empty, rqst, socket); + break; + default: + { + const std::string msgTypeStr = cta::mediachanger::acs::daemon::msgTypeToString(msgType); + cta::exception::Exception ex; + ex.getMessage() << "Failed to check request" + ": Unexpected request type: msgType=" << msgType << " msgTypeStr=" << + msgTypeStr; + throw ex; + } + } +} + +//----------------------------------------------------------------------------- +// checkAndAddRequestDismountTape +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::checkAndAddRequestDismountTape( + mediachanger::ZmqMsg &address, mediachanger::ZmqMsg &empty, + const mediachanger::Frame &rqst, mediachanger::ZmqSocketST &socket) { + m_log(LOG_DEBUG, + "AcsPendingRequests::checkAndAddRequestDismountTape"); + + mediachanger::AcsDismountTape rqstBody; + rqst.parseBodyIntoProtocolBuffer(rqstBody); + + const std::string vid = rqstBody.vid(); + const uint32_t acs = rqstBody.acs(); + const uint32_t lsm = rqstBody.lsm(); + const uint32_t panel = rqstBody.panel(); + const uint32_t drive = rqstBody.drive(); + + checkRequest(vid, acs, lsm, panel, drive); + + std::list<log::Param> params = {log::Param("TPVID", vid), + log::Param("acs", acs), + log::Param("lsm", lsm), + log::Param("panel", panel), + log::Param("drive", drive), + log::Param("sender identity", + utils::hexDump(address.getData(), address.size())) + }; + m_log(LOG_INFO, "Dismount tape", params); + + const SEQ_NO seqNo = getSequenceNumber(); + std::list<log::Param> seqParam = {log::Param("seqNumber", seqNo)}; + m_log(LOG_DEBUG, "ACS sequence number", seqParam); + + try { + cta::mediachanger::acs::daemon::AcsRequest * acsRequestDismountTape = + new AcsRequestDismountTape(vid, acs, lsm, panel, drive, + //new AcsRequestDismountTape AcsRequestDismountTape(vid, acs, lsm, panel, drive, + m_ctaConf, socket, address, empty, m_log, seqNo); + + acsRequestDismountTape->setStateToExecute(); + m_acsRequestList.push_back(acsRequestDismountTape); + } catch (cta::exception::Exception &ne) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to add dismount request: " + << ne.getMessage().str(); + m_log(LOG_ERR, ex.getMessage().str()); + throw ex; + } +} + +//----------------------------------------------------------------------------- +// checkRequest +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsPendingRequests::checkRequest(const std::string &vid, + const uint32_t acs, const uint32_t lsm, const uint32_t panel, + const uint32_t drive) const { + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + if (acs == acsRequest->getAcs() && lsm == acsRequest->getLsm() && + panel == acsRequest->getPanel() && drive == acsRequest->getDrive()) { + cta::exception::Exception ex; + ex.getMessage() << "Check request failed: " + "acs, lsm, panel, drive already are used by another request: "<< + acsRequest->str(); + throw ex; + } + if (std::string::npos != vid.find(acsRequest->getVid())) { + cta::exception::Exception ex; + ex.getMessage() << "Check request failed: " + "vid already is used by another request: "<< + acsRequest->str(); + throw ex; + } + } +} + +//----------------------------------------------------------------------------- +// getSequenceNumber +//----------------------------------------------------------------------------- +SEQ_NO cta::mediachanger::acs::daemon::AcsPendingRequests::getSequenceNumber() const { + unsigned short maxSeqNo = 0; + unsigned short minSeqNo = ACS_MAX_SEQ; + + for(RequestList::const_iterator itor = m_acsRequestList.begin(); + itor != m_acsRequestList.end();itor++) { + cta::mediachanger::acs::daemon::AcsRequest *const acsRequest = *itor; + if (maxSeqNo < acsRequest->getSeqNo()) { + maxSeqNo = acsRequest->getSeqNo(); + } + if (minSeqNo > acsRequest->getSeqNo()) { + minSeqNo = acsRequest->getSeqNo(); + } + } + + // first request + if(ACS_MAX_SEQ == minSeqNo && 0 == maxSeqNo) { + return 1; + } + + // try to get number from 1 to minSeqNo + if(1 != minSeqNo ) { + return minSeqNo-1; + } + + // try to get number from maxSeqNo to maximum allowed + if (ACS_MAX_SEQ != maxSeqNo) { + return maxSeqNo+1; + } + + cta::exception::Exception ex; + ex.getMessage() << "Failed to get sequence number for ACS" + ": allocated minimum seqNo=\""<<minSeqNo<<"\""<< + " allocated maximum seqNo=\""<<maxSeqNo<<"\""; + m_log(LOG_ERR, ex.getMessage().str()); + throw ex; +} diff --git a/mediachanger/acs/daemon/AcsPendingRequests.hpp b/mediachanger/acs/daemon/AcsPendingRequests.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8031001f65256b60c5e4070c46f127774ea72ad5 --- /dev/null +++ b/mediachanger/acs/daemon/AcsPendingRequests.hpp @@ -0,0 +1,196 @@ +/* + * 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 "mediachanger/acs/daemon/AcsdConfiguration.hpp" +#include "common/log/log.hpp" +#include "common/log/SyslogLogger.hpp" +#include "mediachanger/acs/daemon/AcsRequest.hpp" +#include "mediachanger/acs/AcsImpl.hpp" +#include "mediachanger/messages.hpp" +#include "mediachanger/Frame.hpp" +#include "mediachanger/ZmqMsg.hpp" +#include "mediachanger/ZmqSocket.hpp" +#include "mediachanger/ZmqSocketST.hpp" +#include <list> +#include <time.h> + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * Class responsible for keeping track of the Acs requests controlled by + * the CTA ACS daemon. + */ +class AcsPendingRequests { +public: + + /** + * Constructor. + * + * @param ctaConf The configuration for the CTA ACS daemon. + */ + AcsPendingRequests(const AcsdConfiguration &ctaConf, cta::log::Logger &); + + /** + * Destructor. + */ + ~AcsPendingRequests() throw(); + + /** + * Notifies the AcsPendingRequests that it should perform any time related + * actions. + * + * This method does not have to be called at any time precise interval. + */ + void tick(); + + /** + * Requests to the CTA ACS daemon might have several states. + * + * ACS_REQUEST_TO_EXECUTE - is initial state. When request arrives from a + * client it is set to be asynchronous executed to ACS Library. + * ACS_REQUEST_IS_RUNNING - the state in which we periodically query ACS + * Library to check the status of the ongoing request. + * ACS_REQUEST_COMPLETED - indicates that the request is completed + * successfully. + * ACS_REQUEST_FAILED - indicates that the request is completed + * unsuccessfully. + * ACS_REQUEST_TO_DELETE - indicates that the request is handled and might + * be deleted. + * + * /- COMPLETED -\ + * TO_EXECUTE -> IS_RUNNING ->| |-> TO_DELETE + * \- FAILED -/ + */ + + /** + * Handles successfully completed requests. + */ + void handleCompletedRequests(); + + /** + * Handles failed requests. + */ + void handleFailedRequests(); + + /** + * Performs cleanup for deleted requests. + */ + void handleToDeleteRequests(); + + /** + * Performs general checks for the incoming requests and calls next checker + * for the message. Throws exceptions if checks are not passed. + * + * @param address ZMQ message with client address. + * @param empty ZMQ empty message. + * @param rqst ZMQ message with CTA frame. + * @param socket ZMQ socket to use. + */ + + void checkAndAddRequest(mediachanger::ZmqMsg &address, + mediachanger::ZmqMsg &empty, + const mediachanger:: Frame &rqst, + mediachanger::ZmqSocketST &socket); + +/** + * Performs dismount specific checks for the incoming request and add it to + * the list of the request to be handled. + * + * @param address ZMQ message with client address. + * @param empty ZMQ empty message. + * @param rqst ZMQ message with CTA frame. + * @param socket ZMQ socket to use. + */ + void checkAndAddRequestDismountTape(mediachanger::ZmqMsg &address, + mediachanger::ZmqMsg &empty, + const mediachanger::Frame &rqst, + mediachanger::ZmqSocketST &socket); + + /** + * Find and return free sequence number for the ACS request. + * + * @return The value of free sequence number for the ACS request. Throws + * exception if the is no free sequence number. + */ + SEQ_NO getSequenceNumber() const; + + /** + * Sets the type of the response and the response message in the ACS request + * with the sequence number equal response sequence number. + * + * @param responseSeqNumber The sequence number to find ongoing ACS request. + * @param responseType The type of the response message. + * @param responseMsg The response message + */ + void setRequestResponse(const SEQ_NO responseSeqNumber, + const ACS_RESPONSE_TYPE responseType, + const ALIGNED_BYTES *const responseMsg); + + /** + * Performs checks for the request before adding it to the ACS requests list. + * Throws exceptions if there are any problems. + * + * @param vid The vid of the ACS request. + * @param acs The acs value of the ACS request. + * @param lsm The lsm value of the ACS request. + * @param panel The panel value of the ACS request. + * @param drive The drive value of the ACS request. + */ + void checkRequest(const std::string &vid, const uint32_t acs, + const uint32_t lsm, const uint32_t panel, const uint32_t drive) const ; + +private: + + /** + * The object representing cta configuration parameters for + * the CTA ACS daemon. + */ + const AcsdConfiguration m_ctaConf; + + log::Logger &m_log; + /** + * Type for the list of the ACS requests. + */ + typedef std::list<AcsRequest *> RequestList; + + /** + * The list for the ACS requests. + */ + RequestList m_acsRequestList; + + /** + * The ACLS C-API wrapper. + */ + AcsImpl m_acs; + + /** + * The time when the last ACS response command was used. + */ + time_t m_lastTimeResponseUsed; + +}; // class AcsPendingRequests + +} // namespace deamon +} // namepsace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsRequest.cpp b/mediachanger/acs/daemon/AcsRequest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..572b2812d59eff684395753ce1d4a4364fcb3362 --- /dev/null +++ b/mediachanger/acs/daemon/AcsRequest.cpp @@ -0,0 +1,283 @@ +/* + * 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 "AcsRequest.hpp" +#include "mediachanger/messages.hpp" +#include "mediachanger/ReturnValue.pb.h" +#include "mediachanger/Exception.pb.h" +#include "common/utils/utils.hpp" + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::daemon::AcsRequest::AcsRequest(cta::mediachanger::ZmqSocketST &socket, + cta::mediachanger::ZmqMsg &address, cta::mediachanger::ZmqMsg &empty, + const SEQ_NO seqNo, const std::string vid, const uint32_t acs, + const uint32_t lsm, const uint32_t panel, const uint32_t drive): + m_seqNo(seqNo), + m_vid(vid), + m_acs(acs), + m_lsm(lsm), + m_panel(panel), + m_drive(drive), + m_socket(socket), + m_identity(utils::hexDump(address.getData(),address.size())), + m_isReplaySent(false) { + zmq_msg_init_size (&m_addressMsg, address.size()); + memcpy (zmq_msg_data (&m_addressMsg), (const void*)&address.getZmqMsg(), + address.size()); + + zmq_msg_init_size (&m_emptyMsg, empty.size()); + memcpy (zmq_msg_data (&m_emptyMsg), (const void*)&empty.getZmqMsg(), + empty.size()); +} + +//----------------------------------------------------------------------------- +// destructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::daemon::AcsRequest::~AcsRequest() { + zmq_msg_close(&m_addressMsg); + zmq_msg_close(&m_emptyMsg); +} + +//----------------------------------------------------------------------------- +// isToExecute +//----------------------------------------------------------------------------- +bool cta::mediachanger::acs::daemon::AcsRequest::isToExecute() const throw () { + if (ACS_REQUEST_TO_EXECUTE == m_state) { + return true; + } else { + return false; + }; +} + +//----------------------------------------------------------------------------- +// isRunning +//----------------------------------------------------------------------------- +bool cta::mediachanger::acs::daemon::AcsRequest::isRunning() const throw () { + if (ACS_REQUEST_IS_RUNNING == m_state) { + return true; + } else { + return false; + }; +} + +//----------------------------------------------------------------------------- +// isCompleted +//----------------------------------------------------------------------------- +bool cta::mediachanger::acs::daemon::AcsRequest::isCompleted() const throw () { + if (ACS_REQUEST_COMPLETED == m_state) { + return true; + } else { + return false; + }; +} + +//----------------------------------------------------------------------------- +// isFailed +//----------------------------------------------------------------------------- +bool cta::mediachanger::acs::daemon::AcsRequest::isFailed() const throw () { + if (ACS_REQUEST_FAILED == m_state) { + return true; + } else { + return false; + }; +} + +//----------------------------------------------------------------------------- +// isToDelete +//----------------------------------------------------------------------------- +bool cta::mediachanger::acs::daemon::AcsRequest::isToDelete() const throw () { + if (ACS_REQUEST_TO_DELETE == m_state) { + return true; + } else { + return false; + }; +} + +//------------------------------------------------------------------------------ +// createReturnValueFrame +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsRequest::createReturnValueFrame( + const int value) { + cta::mediachanger::Frame frame; + + frame.header = cta::mediachanger::protoTapePreFillHeader(); + frame.header.set_msgtype(cta::mediachanger::MSG_TYPE_RETURNVALUE); + frame.header.set_bodyhashvalue( + cta::mediachanger::computeSHA1Base64(frame.body)); + frame.header.set_bodysignature("PIPO"); + + cta::mediachanger::ReturnValue body; + body.set_value(value); + frame.serializeProtocolBufferIntoBody(body); + + return frame; +} + +//------------------------------------------------------------------------------ +// createExceptionFrame +//------------------------------------------------------------------------------ +cta::mediachanger::Frame cta::mediachanger::acs::daemon::AcsRequest:: + createExceptionFrame(const int code, const std::string& msg) { + cta::mediachanger::Frame frame; + + frame.header = cta::mediachanger::protoTapePreFillHeader(); + frame.header.set_msgtype(mediachanger::MSG_TYPE_EXCEPTION); + frame.header.set_bodyhashvalue(mediachanger::computeSHA1Base64(frame.body)); + frame.header.set_bodysignature("PIPO"); + + cta::mediachanger::Exception body; + body.set_code(code); + body.set_message(msg); + frame.serializeProtocolBufferIntoBody(body); + + return frame; +} + + +//----------------------------------------------------------------------------- +// sendReplayToClientOnce +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsRequest::sendReplayToClientOnce() { + if(m_isReplaySent) { + cta::exception::Exception ex; + ex.getMessage() << "Failed to send second replay to the client"; + throw ex; + } + m_socket.send(&m_addressMsg,ZMQ_SNDMORE); + m_socket.send(&m_emptyMsg,ZMQ_SNDMORE); + + //messages::sendFrame(m_socket, m_reply); + sendFrame(m_socket, m_reply); +} + +//----------------------------------------------------------------------------- +// getIdentity +//----------------------------------------------------------------------------- +std::string cta::mediachanger::acs::daemon::AcsRequest::getIdentity() const throw() { + return m_identity; +} + +//----------------------------------------------------------------------------- +// str +//----------------------------------------------------------------------------- +std::string cta::mediachanger::acs::daemon::AcsRequest::str() const { + std::ostringstream oss; + oss << "vid=" << m_vid << " acs=" << m_acs << " lsm=" << m_lsm << " panel=" << + m_panel << " drive=" << m_drive << " identity=" << getIdentity(); + return oss.str(); +} + +//------------------------------------------------------------------------------ +// getVid +//------------------------------------------------------------------------------ +const std::string &cta::mediachanger::acs::daemon::AcsRequest::getVid() const throw () { + return m_vid; +} + +//------------------------------------------------------------------------------ +// getAcs +//------------------------------------------------------------------------------ +uint32_t cta::mediachanger::acs::daemon::AcsRequest::getAcs() const throw () { + return m_acs; +} + +//------------------------------------------------------------------------------ +// getLsm +//------------------------------------------------------------------------------ +uint32_t cta::mediachanger::acs::daemon::AcsRequest::getLsm() const throw () { + return m_lsm; +} + +//------------------------------------------------------------------------------ +// getPanel +//------------------------------------------------------------------------------ +uint32_t cta::mediachanger::acs::daemon::AcsRequest::getPanel() const throw () { + return m_panel; +} + +//------------------------------------------------------------------------------ +// getDrive +//------------------------------------------------------------------------------ +uint32_t cta::mediachanger::acs::daemon::AcsRequest::getDrive() const throw () { + return m_drive; +} + + +//------------------------------------------------------------------------------ +// getSeqNo +//------------------------------------------------------------------------------ +SEQ_NO cta::mediachanger::acs::daemon::AcsRequest::getSeqNo() const throw () { + return m_seqNo; +} + +//------------------------------------------------------------------------------ +// setResponse +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsRequest::setResponse( + const ACS_RESPONSE_TYPE responseType, + const ALIGNED_BYTES *const responseMsg) throw () { + m_responseType = responseType; + memcpy(m_responseMsg,responseMsg,MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)); +} + +//------------------------------------------------------------------------------ +// setStateFailed +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsRequest::setStateFailed(const int code, + const std::string& msg) { + m_reply = createExceptionFrame(code, msg); + m_state = ACS_REQUEST_FAILED; +} + +//------------------------------------------------------------------------------ +// setStateCompleted +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsRequest::setStateCompleted() { + m_reply = createReturnValueFrame(0); + m_state = ACS_REQUEST_COMPLETED; +} + +//------------------------------------------------------------------------------ +// setStateIsRunning +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsRequest::setStateIsRunning() { + if (isToExecute()) { + m_state = ACS_REQUEST_IS_RUNNING; + } else { + cta::exception::Exception ex; + ex.getMessage() << "Failed to set request state to running from state="<< + m_state; + throw ex; + } +} + +//------------------------------------------------------------------------------ +// setStateToExecute +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsRequest::setStateToExecute() throw() { + m_state = ACS_REQUEST_TO_EXECUTE; +} + +//------------------------------------------------------------------------------ +// setStateToDelete +//------------------------------------------------------------------------------ +void cta::mediachanger::acs::daemon::AcsRequest::setStateToDelete() throw() { + m_state = ACS_REQUEST_TO_DELETE; +} diff --git a/mediachanger/acs/daemon/AcsRequest.hpp b/mediachanger/acs/daemon/AcsRequest.hpp new file mode 100644 index 0000000000000000000000000000000000000000..52b22b94990f10b4af45619be8bbda92c1dcda6e --- /dev/null +++ b/mediachanger/acs/daemon/AcsRequest.hpp @@ -0,0 +1,317 @@ +/* + * 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/Constants.hpp" +#include "mediachanger/acs/Constants.hpp" +#include "mediachanger/messages.hpp" +#include "mediachanger/ZmqSocket.hpp" +#include "mediachanger/ZmqSocketST.hpp" +#include "mediachanger/acs/AcsImpl.hpp" +#include "common/exception/Exception.hpp" +#include <time.h> + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + + +/** + * Abstract class defining the ACS request presentation to be used in the list + * of pending ACS requests. + */ +class AcsRequest { +public: + + /** + * Constructor. + * + * @param socket ZMQ socket to use. + * @param address ZMQ message with client address. + * @param empty ZMQ empty message. + * @param seqNo Sequence number for the ACS request. + * @param vid The vid of the ACS request. + * @param acs The acs value of the ACS request. + * @param lsm The lsm value of the ACS request. + * @param panel The panel value of the ACS request. + * @param drive The drive value of the ACS request. + */ + AcsRequest(ZmqSocketST &socket, ZmqMsg &address, + ZmqMsg &empty, const SEQ_NO seqNo, + const std::string vid, const uint32_t acs, + const uint32_t lsm, const uint32_t panel, const uint32_t drive); + + /** + * Destructor. + */ + virtual ~AcsRequest() = 0; + + /** + * Perform any time related actions with the request to CTA ACS daemon. + * + * This method does not have to be called at any time precise interval. + */ + virtual void tick() = 0; + + /** + * Checks if the ACS request is in to be executed state. + * + * @return true if the ACS request in state to Execute. + */ + bool isToExecute() const throw(); + + /** + * Sets state of the ACS request to be executed. + */ + void setStateToExecute() throw(); + + /** + * Checks if the ACS request is in running state. + * + * @return true if the ACS request is in running state. + */ + bool isRunning() const throw(); + + /** + * Sets state of the ACS request to running. + */ + void setStateIsRunning(); + + /** + * Checks if the ACS request is in completed state. + * + * @return true if the ACS request is in completed state. + */ + bool isCompleted() const throw(); + + /** + * Sets state of the ACS request to completed and fills ZMQ replay frame with + * good status 0. + */ + void setStateCompleted(); + + /** + * Checks if the ACS request is in failed state. + * + * @return true if the ACS request is in failed state. + */ + bool isFailed() const throw(); + + /** + * Sets state of the ACS request to failed and fills ZMQ replay frame with + * exception data. + */ + void setStateFailed(const int code,const std::string& msg); + + /** + * Checks if the ACS request is in to delete state. + * + * @return true if the ACS request is in to delete state. + */ + bool isToDelete() const throw(); + + /** + * Sets state of the ACS request to be deleted. + */ + void setStateToDelete() throw(); + + /** + * Gets the vid component of the ACS request. + * + * @return the vid component of the ACS request. + */ + const std::string &getVid() const throw (); + + /** + * Gets the acs component of the ACS request. + * + * @return the acs component of the ACS request. + */ + uint32_t getAcs() const throw (); + + /** + * Gets the lsm component of the ACS request. + * + * @return the lsm component of the ACS request. + */ + uint32_t getLsm() const throw (); + + /** + * Gets the panel component of the ACS request. + * + * @return the panel component of the ACS request. + */ + uint32_t getPanel() const throw (); + + /** + * Gets the drive component of the ACS request. + * + * @return the drive component of the ACS request. + */ + uint32_t getDrive() const throw (); + + /** + * Gets the SeqNumber component of the ACS request. + * + * @return the SeqNo component of the ACS request. + */ + SEQ_NO getSeqNo() const throw (); + + /** + * Sets the fields of the response message of the ACS response request. + * + * @param responseType The type of the response message. + * @param responseMsg The response message. + */ + void setResponse(const ACS_RESPONSE_TYPE responseType, + const ALIGNED_BYTES *const responseMsg) throw (); + + /** + * Send a replay to the client who issued the ACS request. + */ + void sendReplayToClientOnce(); + + /** + * Returns string presentation for the connection identity with the client. + * + * @return The connection Identity. + */ + std::string getIdentity() const throw(); + + /** + * Returns a string representing ACS request. + * + * @return The value of string presentation for the request + */ + std::string str() const; + + /** + * Abstract method to be implemented in concrete implementation. Checks + * the status of the response from the response message buffer and the type of + * the response. Throws exception if the type of the response is RT_FINAL but + * the status is not success. + * + * @return true if the type of response RT_FINAL and the response status + * is STATUS_SUCCESS. + */ + virtual bool isResponseFinalAndSuccess() const = 0; + +private: + + /** + * Creates a message frame containing a ReturnValue message. + * + * @param value The return value of the ReturnValue message. + * @return The message frame. + */ + //cta::messages::Frame createReturnValueFrame(const int value); + Frame createReturnValueFrame(const int value); + + /** + * Creates a message frame containing an Exception message. + * + * @param code The error code of the exception. + * @param msg The message string of the exception. + */ + Frame createExceptionFrame(const int code, + const std::string& msg); + + /** + * Request sequence number of the ACS request. + */ + const SEQ_NO m_seqNo; + + /** + * The vid component of the ACS request. + */ + const std::string m_vid; + + /** + * The acs component of the ACS request. + */ + const uint32_t m_acs; + + /** + * The lsm component of the ACS request. + */ + const uint32_t m_lsm; + + /** + * The panel component of the ACS request. + */ + const uint32_t m_panel; + + /** + * The drive component of the ACS request. + */ + const uint32_t m_drive; + + /** + * Internal state of the ACS request. + */ + RequestState m_state ; + + /** + * Replay ZMQ frame for the client. + */ + Frame m_reply; + + /** + * The ZMQ socket listening for messages. + */ + ZmqSocketST &m_socket; + + /** + * Client identity for logging. + */ + const std::string m_identity; + + /** + * ZMQ address message for the client. + */ + zmq_msg_t m_addressMsg; + + /** + * ZMQ empty message for the client. + */ + zmq_msg_t m_emptyMsg; + + /** + * Store is the replay to the client has been sent or not. + */ + bool m_isReplaySent; + +protected: + /** + * The type of the response message associated with the ACS request. + */ + ACS_RESPONSE_TYPE m_responseType; + + /** + * The response message associated with the ACS request. + */ + ALIGNED_BYTES m_responseMsg[MAX_MESSAGE_SIZE / sizeof(ALIGNED_BYTES)]; + +}; // class AcsRequest + +} // namepsace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsRequestDismountTape.cpp b/mediachanger/acs/daemon/AcsRequestDismountTape.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74ed0fa0a952acb49bc121fc81033c3d43c69576 --- /dev/null +++ b/mediachanger/acs/daemon/AcsRequestDismountTape.cpp @@ -0,0 +1,112 @@ +/* + * 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 "AcsRequestDismountTape.hpp" +#include "common/exception/DismountFailed.hpp" +#include "common/log/log.hpp" + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::daemon::AcsRequestDismountTape::AcsRequestDismountTape( + const std::string &vid, const uint32_t acs, + const uint32_t lsm, const uint32_t panel, const uint32_t drive, + const AcsdConfiguration &ctaConf, + mediachanger::ZmqSocketST &socket, + mediachanger::ZmqMsg &address, + mediachanger::ZmqMsg &empty, + log::Logger &log, + const SEQ_NO seqNo): + AcsRequest(socket, address, empty, seqNo, vid, acs, lsm, panel, drive), + m_ctaConf(ctaConf), + m_acsDismountTape(vid, acs, lsm, panel, drive, m_acs, log, ctaConf), + m_lastTimeLibraryQueried(0), + m_log(log), + m_timeAcsCommandStarted(0) { +} + +//----------------------------------------------------------------------------- +// tick +//----------------------------------------------------------------------------- +void cta::mediachanger::acs::daemon::AcsRequestDismountTape::tick() { + try { + if (isToExecute()) { + m_log(LOG_DEBUG,"AcsRequestDismountTape::tick isToExecute"); + m_acsDismountTape.asyncExecute(getSeqNo()); + setStateIsRunning(); + m_timeAcsCommandStarted = time(0); + } + + const time_t now = time(0); + + const time_t secsSinceLastQuery = now - m_lastTimeLibraryQueried; + const bool firstQueryOrTimeExceeded = (unsigned int)secsSinceLastQuery > + m_ctaConf.QueryInterval.value(); + + if(isRunning() && firstQueryOrTimeExceeded) { + if(isResponseFinalAndSuccess()) { + setStateCompleted(); + m_log(LOG_DEBUG, + "AcsRequestDismountTape::tick ACS_REQUEST_COMPLETED"); + } else { + m_log(LOG_DEBUG,"AcsRequestDismountTape::tick " + "firstQueryOrTimeExceeded()"); + m_lastTimeLibraryQueried = time(0); + } + } + + const time_t secsSinceCommandStarted = now - m_timeAcsCommandStarted; + const bool acsCommandTimeExceeded = (unsigned int)secsSinceCommandStarted > + m_ctaConf.CmdTimeout.value(); + + if(isRunning() && acsCommandTimeExceeded) { + cta::exception::RequestFailed ex; + ex.getMessage() << "ACS command timed out after " << + secsSinceCommandStarted << " seconds"; + throw ex; + } + } catch (cta::exception::Exception &ex) { + setStateFailed(ECANCELED, ex.getMessage().str()); + m_log(LOG_ERR,"Failed to handle the ACS dismount tape request: " + + ex.getMessage().str()); + } catch(std::exception &se) { + setStateFailed(ECANCELED, se.what()); + m_log(LOG_ERR, se.what()); + } catch(...) { + setStateFailed(ECANCELED, "Caught an unknown exception"); + m_log(LOG_ERR, "Caught an unknown exception"); + } +} + +//------------------------------------------------------------------------------ +// isResponseFinalAndSuccess +//------------------------------------------------------------------------------ +bool cta::mediachanger::acs::daemon::AcsRequestDismountTape::isResponseFinalAndSuccess() const { + if (RT_FINAL == m_responseType ) { + const ACS_DISMOUNT_RESPONSE *const msg = + (ACS_DISMOUNT_RESPONSE *)m_responseMsg; + if(STATUS_SUCCESS != msg->dismount_status) { + cta::exception::DismountFailed ex; + ex.getMessage() << "Status of dismount response is not success: " << + acs_status(msg->dismount_status); + throw ex; + } + return true; + } + return false; +} diff --git a/mediachanger/acs/daemon/AcsRequestDismountTape.hpp b/mediachanger/acs/daemon/AcsRequestDismountTape.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7ec284f6e473901e32fc4d555efdb94ca7c9cbf0 --- /dev/null +++ b/mediachanger/acs/daemon/AcsRequestDismountTape.hpp @@ -0,0 +1,113 @@ +/* + * 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 "mediachanger/acs/daemon/AcsdConfiguration.hpp" +#include "mediachanger/acs/daemon/AcsDismountTape.hpp" +#include "mediachanger/acs/AcsImpl.hpp" +#include "mediachanger/acs/daemon/AcsRequest.hpp" + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { +/** + * Concrete class providing a dismount tape implementation of an AcsRequest + * abstract class. + */ +class AcsRequestDismountTape: public AcsRequest { +public: + + /** + * Constructor. + * + * @param vid The vid of the ACS request. + * @param acs The acs value of the ACS request. + * @param lsm The lsm value of the ACS request. + * @param panel The panel value of the ACS request. + * @param drive The drive value of the ACS request. + * @param ctaConf The configuration for the CTA ACS daemon. + * @param socket ZMQ socket to use. + * @param address ZMQ message with client address. + * @param empty ZMQ empty message. + * @param seqNo Sequence number for the ACS request. + */ + AcsRequestDismountTape( + const std::string &vid, + const uint32_t acs, + const uint32_t lsm, + const uint32_t panel, + const uint32_t drive, + const AcsdConfiguration &ctaConf, + mediachanger::ZmqSocketST &socket, + mediachanger::ZmqMsg &address, + mediachanger::ZmqMsg &empty, + cta::log::Logger& log, + const SEQ_NO seqNo); + + /** + * Perform any time related actions with the request to CTA ACS daemon. + * + * This method does not have to be called at any time precise interval. + */ + void tick(); + + /** + * Checks the status of the response from the dismount response message buffer + * and the type of the response. Throws exception if the type of the response + * is RT_FINAL but the status is not success. + * + * @return true if the type of response RT_FINAL and the response status + * is STATUS_SUCCESS. + */ + bool isResponseFinalAndSuccess() const; + +private: + + /** + * The CTA configuration parameters for the CTA ACS daemon. + */ + const AcsdConfiguration m_ctaConf; + + /** + * The object representing the class for tape dismount through ACS API. + */ + AcsDismountTape m_acsDismountTape; + + /** + * The ACLS C-API wrapper. + */ + AcsImpl m_acs; + + /** + * The time when the ACS library queried last time. + */ + time_t m_lastTimeLibraryQueried; + + cta::log::Logger &m_log; + /** + * The time at which ACS command was started. + */ + time_t m_timeAcsCommandStarted; + +}; // class AcsRequestDismountTape +} // namespace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/AcsdCmdLine.cpp b/mediachanger/acs/daemon/AcsdCmdLine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f60f567d3e9c7fb843a53e880b5ca78798435c0c --- /dev/null +++ b/mediachanger/acs/daemon/AcsdCmdLine.cpp @@ -0,0 +1,81 @@ +/* + * 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 "AcsdCmdLine.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/log.hpp" +#include <iostream> +#include <getopt.h> + +//----------------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------------- +cta::mediachanger::acs::daemon::AcsdCmdLine::AcsdCmdLine() throw(): + foreground(false), + help(false), + configLocation(""){ +} + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsdCmdLine::AcsdCmdLine(const int argc, + char *const *const argv): + foreground(false), //< Prevents daemonisation + help(false), //< Help requested: will print out help and exit. + configLocation(""){ //< Location of the configuration file. Defaults to /etc/cta/cta-taped.conf + + +static struct option longopts[] = { + // { .name, .has_args, .flag, .val } (see getopt.h)) + { "foreground", no_argument, NULL, 'f' }, + { "config", required_argument, NULL, 'c' }, + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, '\0' } + }; + + char c; + // Reset getopt's global variables to make sure we start fresh + optind=0; + // Prevent getopt from printing out errors on stdout + opterr=0; + // We ask getopt to not reshuffle argv ('+') + while ((c = getopt_long(argc, argv, "+fc:h", longopts, NULL)) != -1) { + //log:write(LOG_INFO, "Usage: [options]\n"); + switch (c) { + case 'f': + foreground = true; + break; + case 'c': + configLocation = optarg; + break; + case 'h': + help = true; + std::cout<<"Usage: "<<"cta-acsd"<<" [options]\n" + "where options can be:\n" + "--foreground or -f Remain in the Foreground\n" + "--config <config-file> or -c Configuration file\n" + "--help or -h Print this help and exit\n"; + break; + default: + break; + } + } +} + + diff --git a/mediachanger/acs/daemon/AcsdCmdLine.hpp b/mediachanger/acs/daemon/AcsdCmdLine.hpp new file mode 100644 index 0000000000000000000000000000000000000000..058a7d75f28c0fb0109420be23e76c87855f9d21 --- /dev/null +++ b/mediachanger/acs/daemon/AcsdCmdLine.hpp @@ -0,0 +1,69 @@ +/* + * 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 "mediachanger/CmdLine.hpp" +#include <string.h> + +namespace cta{ +namespace mediachanger{ +namespace acs{ +namespace daemon{ + +class AcsdCmdLine: public CmdLine{ + +public: + + /** + * Constructor. + * + * Initialises all BOOLEAN member-variables to FALSE, all integer + * member-variables to 0 and the volume identifier to an empty string. + */ + AcsdCmdLine() throw(); + + /** + * Constructor. + * + * Parses the specified command-line arguments. + * + * @param argc Argument count from the executable's entry function: main(). + * @param argv Argument vector from the executable's entry function: main(). + */ + AcsdCmdLine(const int argc, char *const *const argv); + + bool foreground; + + bool help; + + std::string configLocation; + + +}; + +} +} +} +} + + + + + + diff --git a/mediachanger/acs/daemon/AcsdCmdLineTest.cpp b/mediachanger/acs/daemon/AcsdCmdLineTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..385e997a00f3519e8b36e99e8cbdf955b94576b1 --- /dev/null +++ b/mediachanger/acs/daemon/AcsdCmdLineTest.cpp @@ -0,0 +1,143 @@ +/* + * 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 "common/exception/Exception.hpp" +#include "mediachanger/acs/daemon/AcsdCmdLine.hpp" +#include <gtest/gtest.h> +#include <list> +#include <memory> + +namespace unitTests { + +class cta_mediachanger_acs_daemon_AcsdCmdLineTest : public ::testing::Test { +protected: + + struct Argcv { + int argc; + char **argv; + Argcv(): argc(0), argv(NULL) { + } + }; + typedef std::list<Argcv*> ArgcvList; + ArgcvList m_argsList; + + /** + * Creates a duplicate string using the new operator. + */ + char *dupString(const char *str) { + const size_t len = strlen(str); + char *duplicate = new char[len+1]; + strncpy(duplicate, str, len); + duplicate[len] = '\0'; + return duplicate; + } + + virtual void SetUp() { + } + + virtual void TearDown() { + // Allow getopt_long to be called again + optind = 0; + + for(ArgcvList::const_iterator itor = m_argsList.begin(); + itor != m_argsList.end(); itor++) { + for(int i=0; i < (*itor)->argc; i++) { + delete[] (*itor)->argv[i]; + } + delete[] (*itor)->argv; + delete *itor; + } + } +}; + + +TEST_F(cta_mediachanger_acs_daemon_AcsdCmdLineTest, constructor_no_command_line_args) { + using namespace cta::mediachanger::acs::daemon; + + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 1; + args->argv = new char *[2]; + args->argv[0] = dupString("cta-acsd"); + args->argv[1] = NULL; + cta::mediachanger::acs::daemon::AcsdCmdLine acsdcmdLine1(args->argc, args->argv); + + ASSERT_FALSE(acsdcmdLine1.foreground); + ASSERT_TRUE(acsdcmdLine1.configLocation.empty()); + ASSERT_FALSE(acsdcmdLine1.help); +} + +TEST_F(cta_mediachanger_acs_daemon_AcsdCmdLineTest, default_constructor) { + using namespace cta::mediachanger::acs::daemon; + + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 0; + cta::mediachanger::acs::daemon::AcsdCmdLine acsdcmdLine1(args->argc, args->argv); + + ASSERT_FALSE(acsdcmdLine1.foreground); + ASSERT_TRUE(acsdcmdLine1.configLocation.empty()); + ASSERT_FALSE(acsdcmdLine1.help); +} + +TEST_F(cta_mediachanger_acs_daemon_AcsdCmdLineTest, constructor_foreground) { + using namespace cta::mediachanger::acs::daemon; + + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("cta-acsd"); + args->argv[1] = dupString("-f"); + args->argv[2] = NULL; + cta::mediachanger::acs::daemon::AcsdCmdLine acsdcmdLine1(args->argc, args->argv); + + ASSERT_TRUE(acsdcmdLine1.foreground); +} + + +TEST_F(cta_mediachanger_acs_daemon_AcsdCmdLineTest, constructor_help) { + using namespace cta::mediachanger::acs::daemon; + + Argcv *args = new Argcv(); + m_argsList.push_back(args); + args->argc = 2; + args->argv = new char *[3]; + args->argv[0] = dupString("cta-mediachanger-acs-daemon"); + args->argv[1] = dupString("-h"); + args->argv[2] = NULL; + cta::mediachanger::acs::daemon::AcsdCmdLine acsdcmdLine2(args->argc, args->argv); + ASSERT_TRUE(acsdcmdLine2.help); +} + + +TEST_F(cta_mediachanger_acs_daemon_AcsdCmdLineTest, constructor_configLocation) { + using namespace cta::mediachanger::acs::daemon; + + Argcv *args1 = new Argcv(); + m_argsList.push_back(args1); + args1->argc = 2; + args1->argv = new char *[3]; + args1->argv[0] = dupString("cta-mediachanger-acs-daemon"); + args1->argv[1] = dupString("-c"); + args1->argv[2] = NULL; + cta::mediachanger::acs::daemon::AcsdCmdLine acsdcmdLine3(args1->argc, args1->argv); + ASSERT_EQ(acsdcmdLine3.configLocation,""); +} + +} // namespace unitTests diff --git a/mediachanger/acs/daemon/AcsdConfiguration.cpp b/mediachanger/acs/daemon/AcsdConfiguration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5d5b42117a7a5d2f21db124c24d14aab5edd8c2 --- /dev/null +++ b/mediachanger/acs/daemon/AcsdConfiguration.cpp @@ -0,0 +1,54 @@ +/* + * 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 "AcsdConfiguration.hpp" +#include "common/ConfigurationFile.hpp" +#include "Tpconfig.hpp" +#include <time.h> + + +//------------------------------------------------------------------------------ +// GlobalConfiguration::createFromCtaConf w path +//------------------------------------------------------------------------------ +cta::mediachanger::acs::daemon::AcsdConfiguration cta::mediachanger::acs::daemon::AcsdConfiguration::createFromCtaConf( + const std::string& generalConfigPath, cta::log::Logger& log) { + AcsdConfiguration ret; + // Parse config file + ConfigurationFile cf(generalConfigPath); + // Extract configuration from parsed config file TpConfig + ret.port.setFromConfigurationFile(cf, generalConfigPath); + ret.QueryInterval.setFromConfigurationFile(cf, generalConfigPath); + ret.CmdTimeout.setFromConfigurationFile(cf, generalConfigPath); + ret.daemonUserName.setFromConfigurationFile(cf, generalConfigPath); + ret.daemonGroupName.setFromConfigurationFile(cf, generalConfigPath); + + // If we get here, the configuration file is good enough to be logged. + ret.port.log(log); + ret.QueryInterval.log(log); + ret.CmdTimeout.log(log); + ret.daemonUserName.log(log); + ret.daemonGroupName.log(log); + + return ret; +} + +//------------------------------------------------------------------------------ +// GlobalConfiguration::gDummyLogger (static member) +//------------------------------------------------------------------------------ +cta::log::DummyLogger cta::mediachanger::acs::daemon::AcsdConfiguration::gDummyLogger("",""); + diff --git a/mediachanger/acs/daemon/AcsdConfiguration.hpp b/mediachanger/acs/daemon/AcsdConfiguration.hpp new file mode 100644 index 0000000000000000000000000000000000000000..61f70f714e299bd7ee059aef75e11e454a5b3233 --- /dev/null +++ b/mediachanger/acs/daemon/AcsdConfiguration.hpp @@ -0,0 +1,64 @@ +/* + * 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> +#include <map> +#include <type_traits> +#include <limits> +#include "common/log/DummyLogger.hpp" +#include "common/exception/Exception.hpp" +#include "common/SourcedParameter.hpp" +#include "Tpconfig.hpp" +#include "mediachanger/acs/Constants.hpp" +#include "common/ConfigurationFile.hpp" + +#include <time.h> + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { +/** + * Class containing all the parameters needed by the watchdog process + * to spawn a transfer session per drive. + */ +struct AcsdConfiguration { + static AcsdConfiguration createFromCtaConf( + const std::string & generalConfigPath, + cta::log::Logger & log = gDummyLogger); + + SourcedParameter<uint64_t> port{ + "acsd", "Port", (uint64_t)ACS_PORT, "Compile time default"}; + SourcedParameter<uint64_t> QueryInterval{ + "acsd", "QueryInterval", (long unsigned int)ACS_QUERY_INTERVAL, "Compile time default"}; + SourcedParameter<uint64_t> CmdTimeout{ + "acsd", "CmdTimeout",(long unsigned int) ACS_CMD_TIMEOUT, "Compile time default"}; + SourcedParameter<std::string> daemonUserName{ + "acsd", "DaemonUserName", "cta", "Compile time default"}; + SourcedParameter<std::string> daemonGroupName{ + "acsd", "DaemonGroupName", "tape", "Compile time default"}; +private: + /** A private dummy logger which will simplify the implementation of the + * functions (just unconditionally log things). */ + static cta::log::DummyLogger gDummyLogger; +} ; +} // namespace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/CMakeLists.txt b/mediachanger/acs/daemon/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..1dfee71cbc555055c2cd396987b554543971b81f --- /dev/null +++ b/mediachanger/acs/daemon/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required (VERSION 2.6) + +find_package(Protobuf3 REQUIRED) +find_package(openssl REQUIRED) +find_package(zeromq REQUIRED) + +include_directories (${PROTOBUF3_INCLUDE_DIRS}) + + +PROTOBUF3_GENERATE_CPP(WDMsgSources WDMsgHeaders WatchdogMessage.proto) + +SET_SOURCE_FILES_PROPERTIES(${WDMsgHeaders} PROPERTIES HEADER_FILE_ONLY TRUE) + + +set (ACS_DAEMON_SRC_FILES + AcsDaemon.cpp + AcsDaemonMain.cpp + AcsdConfiguration.cpp + AcsRequest.cpp + AcsPendingRequests.cpp + AcsdCmdLine.cpp + AcsDismountTape.cpp + AcsMessageHandler.cpp + AcsMountTapeReadWrite.cpp + AcsMountTapeReadOnly.cpp + AcsForceDismountTape.cpp + Constants.cpp + AcsRequestDismountTape.cpp +) +add_executable (cta-acsd ${ACS_DAEMON_SRC_FILES}) + +set_target_properties (cta-acsd PROPERTIES + COMPILE_FLAGS -I/usr/include/CDK + COMPILE_DEFINITIONS LINUX) + +target_link_libraries( + cta-acsd + ctacommon + ctareactor + cta-acs + ctamediachanger + zmq + ${STK_LIBRARIES}) + +set_property (TARGET cta-acsd APPEND PROPERTY INSTALL_RPATH ${PROTOBUF3_RPATH}) + +install (FILES cta-acsd.conf DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cta) +install (TARGETS cta-acsd DESTINATION /usr/bin) +install (FILES cta-acsd.logrotate DESTINATION /etc/logrotate.d RENAME cta-acsd) +install (FILES cta-acsd.sysconfig DESTINATION /etc/sysconfig RENAME cta-acsd) +install (FILES cta-acsd.service DESTINATION /etc/systemd/system) + +add_library (ctamediachangeracsdaemonunittests SHARED AcsdCmdLineTest.cpp AcsdCmdLine.cpp) +set_property(TARGET ctamediachangeracsdaemonunittests PROPERTY SOVERSION "${CTA_SOVERSION}") +set_property(TARGET ctamediachangeracsdaemonunittests PROPERTY VERSION "${CTA_LIBVERSION}") + +target_link_libraries (ctamediachangeracsdaemonunittests + ctamediachangerunittests) + +install (TARGETS ctamediachangeracsdaemonunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) + + + diff --git a/mediachanger/acs/daemon/Constants.cpp b/mediachanger/acs/daemon/Constants.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b2feef15fe8e8bd53c66f0f03e1eb84962dfc43 --- /dev/null +++ b/mediachanger/acs/daemon/Constants.cpp @@ -0,0 +1,79 @@ +/* + * 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 "Constants.hpp" + +//------------------------------------------------------------------------------ +// msgTypeToString +//------------------------------------------------------------------------------ +const char *cta::mediachanger::acs::daemon::msgTypeToString(const cta::mediachanger::acs::daemon::MsgType msgType) throw() { + switch(msgType) { + case MSG_TYPE_NONE: + return "None"; + case MSG_TYPE_EXCEPTION: + return "Exception"; + case MSG_TYPE_FORKCLEANER: + return "ForkCleaner"; + case MSG_TYPE_FORKDATATRANSFER: + return "ForkDataTransfer"; + case MSG_TYPE_FORKLABEL: + return "ForkLabel"; + case MSG_TYPE_FORKSUCCEEDED: + return "ForkSucceeded"; + case MSG_TYPE_HEARTBEAT: + return "Heartbeat"; + case MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY: + return "MigrationJobFromTapeGateway"; + case MSG_TYPE_MIGRATIONJOBFROMWRITETP: + return "MigrationJobFromWriteTp"; + case MSG_TYPE_NBFILESONTAPE: + return "NbFilesOnTape"; + case MSG_TYPE_PROCESSCRASHED: + return "ProcessCrashed"; + case MSG_TYPE_PROCESSEXITED: + return "ProcessExited"; + case MSG_TYPE_RECALLJOBFROMREADTP: + return "RecallJobFromReadTp"; + case MSG_TYPE_RECALLJOBFROMTAPEGATEWAY: + return "RecallJobFromTapeGAteway"; + case MSG_TYPE_RETURNVALUE: + return "ReturnValue"; + case MSG_TYPE_STOPPROCESSFORKER: + return "StopProcessForker"; + case MSG_TYPE_TAPEMOUNTEDFORMIGRATION: + return "TapeMountedForMigration"; + case MSG_TYPE_TAPEMOUNTEDFORRECALL: + return "TapeMountedForRecall"; + case MSG_TYPE_LABELERROR: + return "LabelError"; + case MSG_TYPE_ACSMOUNTTAPEREADONLY: + return "AcsMountTapeReadOnly"; + case MSG_TYPE_ACSMOUNTTAPEREADWRITE: + return "AcsMountTapeReadWrite"; + case MSG_TYPE_ACSDISMOUNTTAPE: + return "AcsDismountTape"; + case MSG_TYPE_ACSFORCEDISMOUNTTAPE: + return "AcsForceDismountTape"; + case MSG_TYPE_ADDLOGPARAMS: + return "AddLogParams"; + case MSG_TYPE_DELETELOGPARAMS: + return "DeleteLogParams"; + default: + return "Unknown"; + } +} // msgTypeToString() diff --git a/mediachanger/acs/daemon/Constants.hpp b/mediachanger/acs/daemon/Constants.hpp new file mode 100644 index 0000000000000000000000000000000000000000..08098228e3746563e503a373cfbbe2a683345cef --- /dev/null +++ b/mediachanger/acs/daemon/Constants.hpp @@ -0,0 +1,83 @@ +/* + * 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 + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +enum ProtocolType { + PROTOCOL_TYPE_NONE, + PROTOCOL_TYPE_TAPE +}; + +enum MsgType { + /* 0 */ MSG_TYPE_NONE = 0, + /* 1 */ MSG_TYPE_EXCEPTION = 1, + /* 2 */ MSG_TYPE_FORKCLEANER = 2, + /* 3 */ MSG_TYPE_FORKDATATRANSFER = 3, + /* 4 */ MSG_TYPE_FORKLABEL = 4, + /* 5 */ MSG_TYPE_FORKSUCCEEDED = 5, + /* 6 */ MSG_TYPE_HEARTBEAT = 6, + /* 7 */ MSG_TYPE_MIGRATIONJOBFROMTAPEGATEWAY = 7, + /* 8 */ MSG_TYPE_MIGRATIONJOBFROMWRITETP = 8, + /* 9 */ MSG_TYPE_NBFILESONTAPE = 9, + /* 10 */ MSG_TYPE_PROCESSCRASHED = 10, + /* 11 */ MSG_TYPE_PROCESSEXITED = 11, + /* 12 */ MSG_TYPE_RECALLJOBFROMREADTP = 12, + /* 13 */ MSG_TYPE_RECALLJOBFROMTAPEGATEWAY = 13, + /* 14 */ MSG_TYPE_RETURNVALUE = 14, + /* 15 */ MSG_TYPE_STOPPROCESSFORKER = 15, + /* 16 */ MSG_TYPE_TAPEMOUNTEDFORMIGRATION = 16, + /* 17 */ MSG_TYPE_TAPEMOUNTEDFORRECALL = 17, + /* 18 */ MSG_TYPE_TAPEUNMOUNTSTARTED = 18, + /* 19 */ MSG_TYPE_TAPEUNMOUNTED = 19, + /* 20 */ MSG_TYPE_LABELERROR = 20, + /* 21 */ MSG_TYPE_ACSMOUNTTAPEREADONLY = 21, + /* 22 */ MSG_TYPE_ACSMOUNTTAPEREADWRITE = 22, + /* 23 */ MSG_TYPE_ACSDISMOUNTTAPE = 23, + /* 24 */ MSG_TYPE_ACSFORCEDISMOUNTTAPE = 24, + /* 25 */ MSG_TYPE_ADDLOGPARAMS = 25, + /* 26 */ MSG_TYPE_DELETELOGPARAMS = 26, + /* 27 */ MSG_TYPE_ARCHIVEJOBFROMCTA = 27, + /* 28 */ MSG_TYPE_RETRIEVEJOBFROMCTA = 28 +}; + +enum ProtocolVersion { + PROTOCOL_VERSION_NONE, + PROTOCOL_VERSION_1 +}; + +/** + * Returns the string representation of the specified message type. + * + * This method is thread safe because it only returns pointers to string + * literals. + * + * In the case where the specified message type is unknown this method does not + * throw an exception, instead is returns a string literal that explains the + * message type is unknown. + */ +const char *msgTypeToString(const MsgType msgType) throw(); + +} // namespace daemon +} // namespace acs +} // namespace mediachanger +} // namespace cta diff --git a/mediachanger/acs/daemon/Tpconfig.hpp b/mediachanger/acs/daemon/Tpconfig.hpp new file mode 100644 index 0000000000000000000000000000000000000000..47fafa56aa2fcc65e5aaf84a121c5e76d3db4a21 --- /dev/null +++ b/mediachanger/acs/daemon/Tpconfig.hpp @@ -0,0 +1,46 @@ +/* + * 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 "TpconfigLine.hpp" +#include "common/SourcedParameter.hpp" +#include "common/exception/Exception.hpp" + +#include <map> + +namespace cta { namespace mediachanger { namespace acs { namespace daemon { + +/** + * A map of lines parsed from a TPCONFIG file (key is the drive name) + */ +class Tpconfig: public std::map<std::string, SourcedParameter<cta::mediachanger::acs::daemon::TpconfigLine>> { +public: + + CTA_GENERATE_EXCEPTION_CLASS(InvalidArgument); + CTA_GENERATE_EXCEPTION_CLASS(DuplicateEntry); + /** + * Parses the specified TPCONFIG file. + * + * @param filename The filename of the TPCONFIG file. + * @return The result of parsing the TPCONFIG file. + */ + static Tpconfig parseFile(const std::string &filename); +}; // class TpconfigLines + +}}}} // namespace cta::tape::daemon diff --git a/mediachanger/acs/daemon/TpconfigLine.hpp b/mediachanger/acs/daemon/TpconfigLine.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4b7a74b4cbd9bc969d1acb415b86237808c01cdb --- /dev/null +++ b/mediachanger/acs/daemon/TpconfigLine.hpp @@ -0,0 +1,104 @@ +/* + * 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> +#include "mediachanger/LibrarySlot.hpp" +#include <memory> + +namespace cta { +namespace mediachanger { +namespace acs { +namespace daemon { + +/** + * The data stored in a data-line (as opposed to a comment-line) from a + * TPCONFIG file (/etc/cta/TPCONFIG). + */ +class TpconfigLine { +public: + /** + * The unit name of the tape drive. + */ + std::string unitName; + + /** + * The logical library of the tape drive. + */ + std::string logicalLibrary; + + /** + * The filename of the device file of the tape drive. + */ + std::string devFilename; + + /** + * The slot in the tape library that contains the tape drive (string encoded). + */ + std::string rawLibrarySlot; + + /** + * Accessor method to the library slot strcuture. + * @return reference to the library slot. + */ + const cta::mediachanger::LibrarySlot & librarySlot() const; + +private: + /** + * The library slot structure. + */ + std::unique_ptr <cta::mediachanger::LibrarySlot> m_librarySlot; + +public: + /** + * Trivial constructor (used in unit tests). + */ + TpconfigLine(); + + /** + * Constructor. + * + * @param unitName The unit name of the tape drive. + * @param dgn The Device Group Name (DGN) of the tape drive. + * @param devFilename The filename of the device file of the tape drive. + * @param librarySlot The slot in the tape library that contains the tape + * drive. + */ + TpconfigLine( + const std::string &unitName, + const std::string &logicalLibrary, + const std::string &devFilename, + const std::string &librarySlot); + + /** + * Copy constructor + * @param o the other TpConfigLine to be copied. + */ + TpconfigLine(const TpconfigLine& o); + + /** + * Copy operator + * @param o the other TpConfigLine to copy. + * @return a reference to the object + */ + TpconfigLine& operator=(const TpconfigLine& o); + static const size_t maxNameLen = 100; +}; // struct TpconfigLine + +}}}} // namespace cta::mediachanger::acs::daemon diff --git a/mediachanger/acs/daemon/cta-acsd.conf b/mediachanger/acs/daemon/cta-acsd.conf new file mode 100644 index 0000000000000000000000000000000000000000..e97d8b4096ae2f3df65004ff221f7b5043042c5c --- /dev/null +++ b/mediachanger/acs/daemon/cta-acsd.conf @@ -0,0 +1,38 @@ +# 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/>. + +################################################################################ +# +# CTA Sample Configuration File +# +################################################################################ + +# The log mask. Logs with a level lower than this value will be masked. +# Possible values are: +# EMERG +# ALERT +# CRIT +# ERR +# WARNING +# NOTICE +# INFO +# DEBUG +# USERERR +# +# Please note that the USERERR log level is equivalent to NOTICE because it is +# a convention of CTA to use log level NOTICE to label user errors. +# +# taped LogMask INFO diff --git a/mediachanger/acs/daemon/cta-acsd.logrotate b/mediachanger/acs/daemon/cta-acsd.logrotate new file mode 100644 index 0000000000000000000000000000000000000000..de8fd8ac53024552e0a710d8d6f87ba5a832de3f --- /dev/null +++ b/mediachanger/acs/daemon/cta-acsd.logrotate @@ -0,0 +1,10 @@ +/var/log/cta/cta-acsd*.log { + compress + daily + missingok + rotate 500 + delaycompress + postrotate + /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true + endscript +} diff --git a/mediachanger/acs/daemon/cta-acsd.service b/mediachanger/acs/daemon/cta-acsd.service new file mode 100644 index 0000000000000000000000000000000000000000..b6c4c395248e37320ddcd74d158645c546e3810e --- /dev/null +++ b/mediachanger/acs/daemon/cta-acsd.service @@ -0,0 +1,13 @@ +[Unit] +Description=CERN Tape Archive (CTA) acsd daemon +After=syslog.target network-online.target + +[Service] +EnvironmentFile=-/etc/sysconfig/cta-acsd +ExecStart=/usr/bin/cta-acsd ${CTA_ACSD_OPTIONS} +LimitCORE=infinity +Type=forking +Restart=no + +[Install] +WantedBy=default.target diff --git a/mediachanger/acs/daemon/cta-acsd.sysconfig b/mediachanger/acs/daemon/cta-acsd.sysconfig new file mode 100644 index 0000000000000000000000000000000000000000..8131adf1c7a76484dc10974d51bbd8a8a93b349f --- /dev/null +++ b/mediachanger/acs/daemon/cta-acsd.sysconfig @@ -0,0 +1,5 @@ + +# Arguments for the rmcd server daemon +# -smc_ldr is the picker device as defined in /dev. +# -f keep process in the foreground, do not fork. +#CTA_ACSD_OPTIONS="/dev/sg9" diff --git a/mediachanger/reactor/CMakeLists.txt b/mediachanger/reactor/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9f2886542aab6e83b0124d7db5ba7e5d7920f197 --- /dev/null +++ b/mediachanger/reactor/CMakeLists.txt @@ -0,0 +1,39 @@ +# 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 Castor Dev team, castor-dev@cern.ch +# +cmake_minimum_required (VERSION 2.6) + +################################################################################ +# Rules to build the reactor code that is common to both rmcd and tapeserverd +################################################################################ +set (REACTOR_SRC_FILES + # DummyZMQReactor.cpp + # PollEventHandler.cpp + # PollReactor.cpp + # PollReactorImpl.cpp + ZMQPollEventHandler.cpp + ZMQReactor.cpp) +add_library (ctareactor ${REACTOR_SRC_FILES}) +set_target_properties (ctareactor PROPERTIES + COMPILE_FLAGS -I/usr/include/CDK + COMPILE_DEFINITIONS LINUX) +target_link_libraries (ctareactor ctacommon ctamediachanger zmq + ${STK_LIBRARIES}) +#target_link_libraries (ctareactor ctacommon ctamediachanger) + diff --git a/mediachanger/reactor/ZMQPollEventHandler.cpp b/mediachanger/reactor/ZMQPollEventHandler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..858a8859dad12deb00549480d3cf1e4276067d8c --- /dev/null +++ b/mediachanger/reactor/ZMQPollEventHandler.cpp @@ -0,0 +1,28 @@ +/****************************************************************************** + * + * 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 Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#include "ZMQPollEventHandler.hpp" + +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::reactor::ZMQPollEventHandler::~ZMQPollEventHandler() throw() { +} diff --git a/mediachanger/reactor/ZMQPollEventHandler.hpp b/mediachanger/reactor/ZMQPollEventHandler.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8f43df3d4813be1716d196f2a0c5ec49dc84c81c --- /dev/null +++ b/mediachanger/reactor/ZMQPollEventHandler.hpp @@ -0,0 +1,77 @@ +/****************************************************************************** + * + * 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 Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#pragma once + +#include "common/exception/Exception.hpp" + +#include <zmq.h> + +namespace cta { +namespace mediachanger { +namespace reactor { + +/** + * Handles the events that occur on a poll() file descriptor. + * + * This class is part of an implementation of the Reactor architecture pattern + * described in the following book: + * + * Pattern-Oriented Software Architecture Volume 2 + * Patterns for Concurrent and Networked Objects + * Authors: Schmidt, Stal, Rohnert and Buschmann + * Publication date: 2000 + * ISBN 0-471-60695-2 + */ +class ZMQPollEventHandler { +public: + + /** + * Destructor. + */ + virtual ~ZMQPollEventHandler() throw() = 0; + + /** + * Returns the human-readable name this event handler. + */ + virtual std::string getName() const throw() = 0; + + /** + * Fills the specified poll file-descriptor ready to be used in a call to + * poll(). + */ + virtual void fillPollFd(zmq_pollitem_t &pollitem) =0; + + /** + * Handles the specified event. + * + * @param fd The poll file-descriptor describing the event. + * @return true if the event handler should be removed from and deleted by + * the reactor. + */ + virtual bool handleEvent(const zmq_pollitem_t &fd)=0; + +}; // class ZMQPollEventHandler + +} // namespace reactor +} // namespace tape +} // namespace cta + diff --git a/mediachanger/reactor/ZMQReactor.cpp b/mediachanger/reactor/ZMQReactor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef3d4e3e41434a0d69a08a72df8aae0e6f281a0e --- /dev/null +++ b/mediachanger/reactor/ZMQReactor.cpp @@ -0,0 +1,179 @@ +/****************************************************************************** + * + * 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 Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#include "common/log/log.hpp" +#include "ZMQReactor.hpp" +#include "ZMQPollEventHandler.hpp" +#include "common/utils/utils.hpp" + +#include "common/log/SyslogLogger.hpp" +#include <algorithm> + +namespace{ + bool operator==(const zmq_pollitem_t& a,const zmq_pollitem_t& b){ + if( (a.fd==b.fd && a.fd!= -1 && b.fd != -1) || + (a.socket==b.socket && a.socket!=NULL && b.socket != NULL) ){ + return true; + } + return false; + } +} + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +cta::mediachanger::reactor::ZMQReactor::ZMQReactor(cta::log::Logger &l) throw():m_log(l) { +} +//------------------------------------------------------------------------------ +// destructor +//------------------------------------------------------------------------------ +cta::mediachanger::reactor::ZMQReactor::~ZMQReactor() throw() { + clear(); +} + +//------------------------------------------------------------------------------ +// clear +//------------------------------------------------------------------------------ +void cta::mediachanger::reactor::ZMQReactor::clear() { + for(HandlerMap::iterator it=m_handlers.begin();it!=m_handlers.end();++it){ + delete it->second; + } + m_handlers.clear(); +} + + +//------------------------------------------------------------------------------ +// registerHandler +//------------------------------------------------------------------------------ + + void cta::mediachanger::reactor::ZMQReactor::registerHandler( + ZMQPollEventHandler *const handler) { + zmq_pollitem_t item; + handler->fillPollFd(item); + + std::ostringstream socketInHex; + socketInHex << std::hex << item.socket; + std::list<log::Param> params = {log::Param("fd", item.fd), + log::Param("socket", socketInHex.str())}; + //log::write(LOG_DEBUG, "ZMQReactor registering a new handler", params); + m_log(LOG_DEBUG, "ZMQReactor registering a new handler", params); + + checkDoubleRegistration(item); + m_handlers.push_back(std::make_pair(item,handler)); +} + +//------------------------------------------------------------------------------ +// checkDoubleRegistration +//------------------------------------------------------------------------------ +void cta::mediachanger::reactor::ZMQReactor::checkDoubleRegistration( + const zmq_pollitem_t &item) const { + for(HandlerMap::const_iterator it=m_handlers.begin(); it!=m_handlers.end(); + ++it) { + const std::pair<zmq_pollitem_t, ZMQPollEventHandler*> &maplet = *it; + if(item == maplet.first) { + cta::exception::Exception ex; + ex.getMessage() << "ZMQReactor detected a double registration: fd=" << + item.fd << " socket=" << std::hex << item.socket; + throw ex; + } + } +} + +//------------------------------------------------------------------------------ +// handleEvents +//------------------------------------------------------------------------------ +void cta::mediachanger::reactor::ZMQReactor::handleEvents(const int timeout) { + //it should not bring any copy, thanks to NRVO + std::vector<zmq_pollitem_t> pollFds=buildPollFds(); + + // Please note that we are relying on the fact that the file descriptors of + // the vector are stored contiguously + const int pollRc = zmq_poll(&pollFds[0], pollFds.size(), timeout); + if(0 <= pollRc){ + for(std::vector<zmq_pollitem_t>::const_iterator it=pollFds.begin(); + it!=pollFds.end(); ++it) { + const zmq_pollitem_t &pollFd = *it; + if(0 != pollFd.revents) { + handleEvent(pollFd); + } + } + } else if(0 > pollRc) { + const std::string message = utils::errnoToString(errno); + std::list<log::Param> params = {log::Param("message", message)}; + m_log(LOG_ERR, "Failed to handle I/O event: zmq_poll() failed", params); + } +} + +//------------------------------------------------------------------------------ +// handleEvent +//------------------------------------------------------------------------------ +void cta::mediachanger::reactor::ZMQReactor::handleEvent( + const zmq_pollitem_t &pollFd) { + // Find and dispatch the appropriate handler if there is a pending event + if(pollFd.revents & ZMQ_POLLIN) { + HandlerMap::iterator handlerItor = findHandler(pollFd); + if(handlerItor != m_handlers.end()) { + ZMQPollEventHandler *const handler = handlerItor->second; + const bool removeAndDeleteHandler = handler->handleEvent(pollFd); + if(removeAndDeleteHandler) { + m_handlers.erase(handlerItor); + delete(handler); + } + }else { + std::list<log::Param> params; + params.push_back(log::Param("fd",pollFd.fd)); + params.push_back(log::Param("socket",pollFd.socket)); + m_log(LOG_ERR, "Event on some poll, but no handler to match it", params); + } + } +} + +//------------------------------------------------------------------------------ +// findHandler +//------------------------------------------------------------------------------ + +cta::mediachanger::reactor::ZMQReactor::HandlerMap::iterator + cta::mediachanger::reactor::ZMQReactor::findHandler(const zmq_pollitem_t& pollfd) { + for(HandlerMap::iterator it=m_handlers.begin();it!=m_handlers.end();++it){ + // Use overloaded == to compare zmq_pollitem_t references + if(pollfd==it->first){ + return it; + } + } + return m_handlers.end(); +} + +//------------------------------------------------------------------------------ +// buildPollFds +//------------------------------------------------------------------------------ +std::vector<zmq_pollitem_t> cta::mediachanger::reactor::ZMQReactor::buildPollFds() + const { + std::vector<zmq_pollitem_t> pollFds; + pollFds.reserve(m_handlers.size()); + for(HandlerMap::const_iterator it=m_handlers.begin();it!=m_handlers.end(); + ++it) { + ZMQPollEventHandler *const handler = it->second; + zmq_pollitem_t pollFd; + handler->fillPollFd(pollFd); + pollFds.push_back(pollFd); + } + return pollFds; +} diff --git a/mediachanger/reactor/ZMQReactor.hpp b/mediachanger/reactor/ZMQReactor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c2cf4d62652ba1981f27a0d2e3f91621bcc60990 --- /dev/null +++ b/mediachanger/reactor/ZMQReactor.hpp @@ -0,0 +1,141 @@ +/****************************************************************************** + * + * 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 Castor Dev team, castor-dev@cern.ch + *****************************************************************************/ + +#pragma once + +#include "ZMQPollEventHandler.hpp" +#include "ZMQReactor.hpp" + +#include "common/log/log.hpp" +#include <utility> +#include <vector> + +namespace cta { +namespace mediachanger { +namespace reactor { + +/** + * This reactor wraps the zmq_poll() function. + * + * This class is part of an implementation of the Reactor architecture pattern + * described in the following book: + * + * Pattern-Oriented Software Architecture Volume 2 + * Patterns for Concurrent and Networked Objects + * Authors: Schmidt, Stal, Rohnert and Buschmann + * Publication date: 2000 + * ISBN 0-471-60695-2 + */ +class ZMQReactor { +public: + + /** + * Constructor. + */ + ZMQReactor(cta::log::Logger &) throw(); + /** + * Destructor. + */ + virtual ~ZMQReactor() throw(); + + /** + * Removes and deletes all of the event handlers registered with the reactor. + */ + virtual void clear(); + + /** + * Registers the specified handler. + * + * Please note that the reactor takes ownership of the handler and will + * delete it as appropriate. + * + * @param handler The handler to be registered. Please note that the handler + * MUST be allocated on the heap because the reactor will own the handler + * and therefore delete it as needed. + */ + virtual void registerHandler(ZMQPollEventHandler *const handler); + + /** + * Handles any pending events. + * + * @param timeout Timeout in milliseconds. + */ + virtual void handleEvents(const int timeout); + +private: + + log::Logger &m_log; + + /** + * Type used to map zmq_pollitem_t to event handler. + */ +typedef std::vector<std::pair<zmq_pollitem_t, ZMQPollEventHandler*> > + HandlerMap; + + /** + * Throws a cator::exception::Exception if a handler has already been + * registered for the specified poll item. + * + * @prama item The poll item. + */ + void checkDoubleRegistration(const zmq_pollitem_t &item) const; + + /** + * Builds the vector of file descriptors to be passed to poll(). + * + * Please note that the return type is an std::vector because we can assume + * that its elements are stored contiguously in memory. The address of the + * first element is going to be passed to zmq_poll(). + * + * @return The vector of file descriptors. + */ + std::vector<zmq_pollitem_t> buildPollFds() const; + + /** + * Returns the event handler associated with the specified zmq_pollitem_t. + */ + HandlerMap::iterator findHandler(const zmq_pollitem_t&); + + /** + * Handles the specified ZMQ I/O event. + * + * @param pollFd The file-descriptor representing the I/O event. + */ + void handleEvent(const zmq_pollitem_t &pollFd); + + /** + * Removes the specified handler from the reactor. This method effectively + * does the opposite of registerHandler(). + * + * @param handler The handler to be removed. + */ + void removeHandler(ZMQPollEventHandler *const handler); + + /** + * Map of file descriptor to registered event handler. + */ + HandlerMap m_handlers; + +}; // class ZMQReactor + +} // namespace reactor +} // namespace mediachanger +} // namespace cta diff --git a/objectstore/AgentHeartbeatThread.cpp b/objectstore/AgentHeartbeatThread.cpp index d343d747720df96f07223f9ba6410d33d61f5faa..b0a5d1e15ac013af1d7944657b0c75274277b51c 100644 --- a/objectstore/AgentHeartbeatThread.cpp +++ b/objectstore/AgentHeartbeatThread.cpp @@ -18,6 +18,7 @@ #include "AgentHeartbeatThread.hpp" #include "common/log/LogContext.hpp" +#include "common/Timer.hpp" namespace cta { namespace objectstore { @@ -38,7 +39,17 @@ void AgentHeartbeatThread::run() { auto exitFuture = m_exit.get_future(); try { while (std::future_status::ready != exitFuture.wait_for(m_heartRate)) { + utils::Timer t; m_agentReference.bumpHeatbeat(m_backend); + auto updateTime = t.secs(); + auto updateTimeLimit = std::chrono::duration<double, std::ratio<1, 1>>(m_heartRate).count(); + if (updateTime > updateTimeLimit) { + log::ScopedParamContainer params(lc); + params.add("HeartbeatUpdateTimeLimit", updateTimeLimit) + .add("HeartbeatUpdateTime", updateTime); + lc.log(log::CRIT, "In AgentHeartbeatThread::run(): Could not update heartbeat in time. Exiting."); + ::exit(EXIT_FAILURE); + } } ANNOTATE_HAPPENS_AFTER(&m_exit); ANNOTATE_HAPPENS_BEFORE_FORGET_ALL(&m_exit); diff --git a/objectstore/GarbageCollectorTest.cpp b/objectstore/GarbageCollectorTest.cpp index 24f2dd93a745fc4cd13eb142cec43eb941546318..8079b3e18337ce9124e121474dc6598edad72116 100644 --- a/objectstore/GarbageCollectorTest.cpp +++ b/objectstore/GarbageCollectorTest.cpp @@ -43,7 +43,11 @@ namespace unitTests { TEST(ObjectStore, GarbageCollectorBasicFuctionnality) { // We will need a log object +#ifdef STDOUT_LOGGING + cta::log::StdoutLogger dl("dummy", "unitTest"); +#else cta::log::DummyLogger dl("dummy", "unitTest"); +#endif cta::catalogue::DummyCatalogue catalogue; cta::log::LogContext lc(dl); // Here we check for the ability to detect dead (but empty agents) @@ -96,7 +100,11 @@ TEST(ObjectStore, GarbageCollectorBasicFuctionnality) { TEST(ObjectStore, GarbageCollectorRegister) { // We will need a log object +#ifdef STDOUT_LOGGING + cta::log::StdoutLogger dl("dummy", "unitTest"); +#else cta::log::DummyLogger dl("dummy", "unitTest"); +#endif cta::log::LogContext lc(dl); cta::catalogue::DummyCatalogue catalogue; // Here we check that can successfully call agentRegister's garbage collector @@ -155,7 +163,11 @@ TEST(ObjectStore, GarbageCollectorRegister) { TEST(ObjectStore, GarbageCollectorArchiveQueue) { // We will need a log object +#ifdef STDOUT_LOGGING + cta::log::StdoutLogger dl("dummy", "unitTest"); +#else cta::log::DummyLogger dl("dummy", "unitTest"); +#endif cta::log::LogContext lc(dl); // We need a dummy catalogue cta::catalogue::DummyCatalogue catalogue; @@ -215,7 +227,11 @@ TEST(ObjectStore, GarbageCollectorArchiveQueue) { TEST(ObjectStore, GarbageCollectorDriveRegister) { // We will need a log object +#ifdef STDOUT_LOGGING + cta::log::StdoutLogger dl("dummy", "unitTest"); +#else cta::log::DummyLogger dl("dummy", "unitTest"); +#endif cta::log::LogContext lc(dl); // We need a dummy catalogue cta::catalogue::DummyCatalogue catalogue; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 60f6314790a5da554fd1e6b62edcb775c15f675b..d118913deb4dc0f726fd93e0b244c7b46225543a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -40,6 +40,7 @@ target_link_libraries(cta-unitTests ctaschedulerunittests ctadaemonunittests ctamediachangerunittests + ctamediachangeracsdaemonunittests ${GMOCK_LIB} gtest pthread)