Skip to content
Snippets Groups Projects
XrdSsiCtaRequestMessage.hpp 15.29 KiB
/*
 * @project        The CERN Tape Archive (CTA)
 * @copyright      Copyright(C) 2015-2021 CERN
 * @license        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 <XrdSsi/XrdSsiEntity.hh>

#include "XrdSsiCtaServiceProvider.hpp"
#include "cta_frontend.pb.h"
#include "common/utils/utils.hpp"
#include "Versions.hpp"


namespace cta { namespace xrd {

/*!
 * CTA Frontend Request Message class
 */
class RequestMessage
{
public:
  RequestMessage(const XrdSsiEntity &client, const XrdSsiCtaServiceProvider *service) :
    m_service(*service),
    m_catalogue(service->getCatalogue()),
    m_scheduler(service->getScheduler()),
    m_archiveFileMaxSize(service->getArchiveFileMaxSize()),
    m_repackBufferURL(service->getRepackBufferURL()),
    m_namespaceMap(service->getNamespaceMap()),
    m_lc(service->getLogContext()),
    m_catalogue_conn_string(service->getCatalogueConnectionString())
    {
      m_cliIdentity.username   = client.name;
      m_cliIdentity.host       = cta::utils::getShortHostname(); // Host should be of the machine that executes the command
      m_cliIdentity.clientHost = client.host;

      m_lc.pushOrReplace({"user", m_cliIdentity.username + "@" + m_cliIdentity.host});

      // Map the client protocol string to an enum value
      auto proto_it = m_protomap.find(client.prot);
      m_protocol = proto_it != m_protomap.end() ? proto_it->second : Protocol::OTHER;
    }

  /*!
   * Process a Notification request or an Admin command request
   *
   * @param[in]     request
   * @param[out]    response        Response protocol buffer
   * @param[out]    stream          Reference to Response stream pointer
   */
  void process(const cta::xrd::Request &request, cta::xrd::Response &response, XrdSsiStream* &stream);

  /*!
   * Get a required option
   */
  const std::string &getRequired(cta::admin::OptionString::Key key) const {
    return m_option_str.at(key);
  }
  const std::vector<std::string> &getRequired(cta::admin::OptionStrList::Key key) const {
    return m_option_str_list.at(key);
  }
  const uint64_t &getRequired(cta::admin::OptionUInt64::Key key) const {
    return m_option_uint64.at(key);
  }
  const bool &getRequired(cta::admin::OptionBoolean::Key key) const {
    return m_option_bool.at(key);
  }
  const Versions &getClientVersions() const {
    return m_client_versions;
  }
  const std::string &getClientXrdSsiProtoIntVersion() const {
    return m_client_xrd_ssi_proto_int_version;
  }

  /*!
   * Get an optional option
   *
   * The has_option parameter is set if the option exists and left unmodified if the option does not
   * exist. This is provided as a convenience to monitor whether at least one option was set from a
   * list of optional options.
   *
   * @param[in]     key           option key to look up in options
   * @param[out]    has_option    Set to true if the option exists, unmodified if it does not
   *
   * @returns       value of the option if it exists, an object of type nullopt_t if it does not
   */
  template<typename K, typename V>
  optional<V> getOptional(K key, const std::map<K,V> &options, bool *has_option) const
  {
    auto it = options.find(key);

    if(it != options.end()) {
      if(has_option != nullptr) *has_option = true;
      return it->second;
    } else {
      return cta::nullopt;
    }
  }

  /*!
   * Overloaded versions of getOptional
   *
   * These map the key type to the template specialization of <key,value> pairs
   */
  optional<std::string> getOptional(cta::admin::OptionString::Key key, bool *has_option = nullptr) const {
    return getOptional(key, m_option_str, has_option);
  }
  optional<std::vector<std::string>> getOptional(cta::admin::OptionStrList::Key key, bool *has_option = nullptr) const {
    return getOptional(key, m_option_str_list, has_option);
  }
  optional<uint64_t> getOptional(cta::admin::OptionUInt64::Key key, bool *has_option = nullptr) const {
    return getOptional(key, m_option_uint64, has_option);
  }
  optional<bool> getOptional(cta::admin::OptionBoolean::Key key, bool *has_option = nullptr) const {
    return getOptional(key, m_option_bool, has_option);
  }

  /*!
   * Check if an optional flag has been set
   *
   * This is a simpler version of getOptional for checking flags which are either present
   * or not. In the case of flags, they should always have the value true if the flag is
   * present, but we do a redundant check anyway.
   *
   * @param[in] option    Optional command line option
   *
   * @retval    true      The flag is present in the options map, and its value is true
   * @retval    false     The flag is either not present or is present and set to false
   */
  bool has_flag(cta::admin::OptionBoolean::Key option) const {
    auto opt_it = m_option_bool.find(option);
    return opt_it != m_option_bool.end() && opt_it->second;
  }

private:
  /*!
   * Process Notification events
   *
   * @param[in]     notification    Notification request message from EOS WFE
   * @param[out]    response        Response message to return to EOS
   */
  void processOPENW        (const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< Ignore OPENW event
  void processCREATE       (const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< New archive file ID event
  void processCLOSEW       (const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< Archive file event
  void processPREPARE      (const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< Retrieve file event
  void processABORT_PREPARE(const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< Abort retrieve file event
  void processDELETE       (const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< Delete file event
  void processUPDATE_FID   (const cta::eos::Notification &notification, cta::xrd::Response &response);    //!< Disk file ID update event

  /*!
   * Process AdminCmd events
   *
   * @param[out]    response        CTA Admin command response message
   */
  void processAdmin_Add             (cta::xrd::Response &response);
  void processAdmin_Ch              (cta::xrd::Response &response);
  void processAdmin_Rm              (cta::xrd::Response &response);
  void processArchiveRoute_Add      (cta::xrd::Response &response);
  void processArchiveRoute_Ch       (cta::xrd::Response &response);
  void processArchiveRoute_Rm       (cta::xrd::Response &response);
  void processDrive_Up              (cta::xrd::Response &response);
  void processDrive_Down            (cta::xrd::Response &response);
  void processDrive_Ch              (cta::xrd::Response &response);
  void processDrive_Rm              (cta::xrd::Response &response);
  void processFailedRequest_Rm      (cta::xrd::Response &response);
  void processGroupMountRule_Add    (cta::xrd::Response &response);
  void processGroupMountRule_Ch     (cta::xrd::Response &response);
  void processGroupMountRule_Rm     (cta::xrd::Response &response);
  void processLogicalLibrary_Add    (cta::xrd::Response &response);
  void processLogicalLibrary_Ch     (cta::xrd::Response &response);
  void processLogicalLibrary_Rm     (cta::xrd::Response &response);
  void processMediaType_Add         (cta::xrd::Response &response);
  void processMediaType_Ch          (cta::xrd::Response &response);
  void processMediaType_Rm          (cta::xrd::Response &response);
  void processMountPolicy_Add       (cta::xrd::Response &response);
  void processMountPolicy_Ch        (cta::xrd::Response &response);
  void processMountPolicy_Rm        (cta::xrd::Response &response);
  void processRepack_Add            (cta::xrd::Response &response);
  void processRepack_Rm             (cta::xrd::Response &response);
  void processRepack_Err            (cta::xrd::Response &response);
  void processRequesterMountRule_Add(cta::xrd::Response &response);
  void processRequesterMountRule_Ch (cta::xrd::Response &response);
  void processRequesterMountRule_Rm (cta::xrd::Response &response);
  void processActivityMountRule_Add (cta::xrd::Response &response);
  void processActivityMountRule_Ch  (cta::xrd::Response &response);
  void processActivityMountRule_Rm  (cta::xrd::Response &response);
  void processStorageClass_Add      (cta::xrd::Response &response);
  void processStorageClass_Ch       (cta::xrd::Response &response);
  void processStorageClass_Rm       (cta::xrd::Response &response);
  void processTape_Add              (cta::xrd::Response &response);
  void processTape_Ch               (cta::xrd::Response &response);
  void processTape_Rm               (cta::xrd::Response &response);
  void processTape_Reclaim          (cta::xrd::Response &response);
  void processTape_Label            (cta::xrd::Response &response);
  void processTapeFile_Rm           (cta::xrd::Response &response);
  void processTapePool_Add          (cta::xrd::Response &response);
  void processTapePool_Ch           (cta::xrd::Response &response);
  void processTapePool_Rm           (cta::xrd::Response &response);
  void processDiskSystem_Add        (cta::xrd::Response &response);
  void processDiskSystem_Ch         (cta::xrd::Response &response);
  void processDiskSystem_Rm         (cta::xrd::Response &response);
  void processDiskInstance_Add      (cta::xrd::Response &response);
  void processDiskInstance_Ch       (cta::xrd::Response &response);
  void processDiskInstance_Rm       (cta::xrd::Response &response);
  void processDiskInstanceSpace_Add (cta::xrd::Response &response);
  void processDiskInstanceSpace_Ch  (cta::xrd::Response &response);
  void processDiskInstanceSpace_Rm  (cta::xrd::Response &response);
  void processVirtualOrganization_Add(cta::xrd::Response &response);
  void processVirtualOrganization_Ch(cta::xrd::Response &response);
  void processVirtualOrganization_Rm(cta::xrd::Response &response);
  void processRecycleTapeFile_Restore(cta::xrd::Response &response);
  
  /*!
   * Process AdminCmd events which can return a stream response
   *
   * @param[out]    response    Response protocol buffer message. This is used for response
   *                            headers or for summary responses.
   * @param[out]    stream      Reference to Response stream message pointer
   */
  typedef void admincmdstream_t(cta::xrd::Response &response, XrdSsiStream* &stream);

  admincmdstream_t processAdmin_Ls;
  admincmdstream_t processArchiveRoute_Ls;
  admincmdstream_t processDrive_Ls;
  admincmdstream_t processFailedRequest_Ls;
  admincmdstream_t processGroupMountRule_Ls;
  admincmdstream_t processActivityMountRule_Ls;
  admincmdstream_t processLogicalLibrary_Ls;
  admincmdstream_t processMediaType_Ls;
  admincmdstream_t processMountPolicy_Ls;
  admincmdstream_t processRequesterMountRule_Ls;
  admincmdstream_t processShowQueues;
  admincmdstream_t processStorageClass_Ls;
  admincmdstream_t processTapePool_Ls;
  admincmdstream_t processTape_Ls;
  admincmdstream_t processTapeFile_Ls;
  admincmdstream_t processRepack_Ls;
  admincmdstream_t processDiskSystem_Ls;
  admincmdstream_t processDiskInstance_Ls;
  admincmdstream_t processDiskInstanceSpace_Ls;
  admincmdstream_t processVirtualOrganization_Ls;
  admincmdstream_t processVersion;
  admincmdstream_t processSchedulingInfos_Ls;
  admincmdstream_t processRecycleTapeFile_Ls;

  /*!
   * Log an admin command
   *
   * @param[in]    admincmd    CTA Admin command request message
   * @param[in]    t           CTA Catalogue timer
   */
  void logAdminCmd(const std::string &function, const std::string &status, const std::string &reason, 
    const cta::admin::AdminCmd &admincmd, cta::utils::Timer &t);

  /*!
   * Drive state enum
   */
  enum DriveState { Up, Down };

  /*!
   * Changes state for the drives by a given regex.
   *
   * @param[in]     regex          The regex to match drive name(s) to change
   * @param[in]     desiredDriveState The object holding desired drive state informations (up, forceDown, reason, comment)
   * 
   * @returns       The result of the operation, to return to the client
   */
  std::string setDriveState(const std::string &regex, const cta::common::dataStructures::DesiredDriveState & desiredDriveState);

  /*!
   * Import Google Protobuf option fields into maps
   *
   * @param[in]     admincmd        CTA Admin command request message
   */
  void importOptions(const cta::admin::AdminCmd &admincmd);

  /*!
   * Throw an exception for empty protocol buffer strings
   */
  void checkIsNotEmptyString(const std::string &value, const std::string &error_txt) {
    if(value.empty()) throw XrdSsiPb::PbException("Protocol buffer field " + error_txt + " is an empty string.");
  }

  // Security protocol used to connect

  enum class Protocol { SSS, KRB5, OTHER };

  const std::map<std::string, Protocol> m_protomap = {
    { "sss",  Protocol::SSS  },
    { "krb5", Protocol::KRB5 },
  };

  // Member variables

  Protocol                                              m_protocol;           //!< The protocol the client used to connect
  cta::common::dataStructures::SecurityIdentity         m_cliIdentity;        //!< Client identity: username/host
  const XrdSsiCtaServiceProvider                       &m_service;            //!< Const reference to the XRootD SSI Service
  cta::catalogue::Catalogue                            &m_catalogue;          //!< Reference to CTA Catalogue
  cta::Scheduler                                       &m_scheduler;          //!< Reference to CTA Scheduler
  uint64_t                                              m_archiveFileMaxSize; //!< Maximum allowed file size for archive requests
  optional<std::string>				        m_repackBufferURL;    //!< Repack buffer URL
  NamespaceMap_t                                        m_namespaceMap;       //!< Identifiers for namespace queries
  cta::log::LogContext                                  m_lc;                 //!< CTA Log Context
  std::map<cta::admin::OptionBoolean::Key, bool>        m_option_bool;        //!< Boolean options
  std::map<cta::admin::OptionUInt64::Key, uint64_t>     m_option_uint64;      //!< UInt64 options
  std::map<cta::admin::OptionString::Key, std::string>  m_option_str;         //!< String options
  std::map<cta::admin::OptionStrList::Key,
    std::vector<std::string>>                           m_option_str_list;    //!< String List options
  Versions                                              m_client_versions;    //!< Client CTA and xrootd-ssi-proto version(tag)
  std::string m_client_cta_version;                                           //!< Client CTA Version
  std::string m_client_xrd_ssi_proto_int_version;                             //!< Client xrootd-ssi-protobuf-interface version (tag)  
  std::string m_catalogue_conn_string;                                        //!< Server catalogue connection string
};

}} // namespace cta::xrd