From 83eabdfcaa709b8b994e0b9c2269bb8c19a0269e Mon Sep 17 00:00:00 2001
From: mvelosob <miguel.veloso.barros@cern.ch>
Date: Tue, 24 May 2022 13:18:38 +0200
Subject: [PATCH] add cta-tape-label parameter to specify drive (#977)

---
 ReleaseNotes.md                               |  1 +
 tapeserver/tapelabel/TapeLabelCmd.cpp         | 43 ++++++++++++++-----
 tapeserver/tapelabel/TapeLabelCmd.hpp         |  3 +-
 tapeserver/tapelabel/TapeLabelCmdLineArgs.cpp |  7 ++-
 tapeserver/tapelabel/TapeLabelCmdLineArgs.hpp |  6 +++
 5 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index dec4ce1563..0e125eacb4 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -9,6 +9,7 @@
 - cta/CTA#1220 - Improve queued retrieve logging message
 - cta/CTA#1152 - Reduce eos free space query load
 - cta/CTA#1231 - Add --loadtimeout option to cta-tape-label and increase default value
+- cta/CTA#977 - Add --drive option to cta-tape-label
 
 ### Bug fixes
 - cta/CTA#1120 - Fix negative disk space reservation content
diff --git a/tapeserver/tapelabel/TapeLabelCmd.cpp b/tapeserver/tapelabel/TapeLabelCmd.cpp
index 40189185e7..b3ec81172b 100644
--- a/tapeserver/tapelabel/TapeLabelCmd.cpp
+++ b/tapeserver/tapelabel/TapeLabelCmd.cpp
@@ -76,7 +76,7 @@ int TapeLabelCmd::exceptionThrowingMain(const int argc, char *const *const argv)
   params.push_back(cta::log::Param("tapeLoadTimeout", cmdLineArgs.m_tapeLoadTimeout));
   m_log(cta::log::INFO, "Label session started", params);
   
-  readAndSetConfiguration(getUsername(), cmdLineArgs.m_vid, cmdLineArgs.m_oldLabel);
+  readAndSetConfiguration(getUsername(), cmdLineArgs.m_vid, cmdLineArgs.m_oldLabel, cmdLineArgs.m_unitName);
    
   const std::string capabilities("cap_sys_rawio+ep");
   setProcessCapabilities(capabilities);
@@ -412,25 +412,48 @@ void TapeLabelCmd::setProcessCapabilities(const std::string &capabilities) {
 // readConfiguration
 //------------------------------------------------------------------------------
 void TapeLabelCmd::readAndSetConfiguration(const std::string &userName,
-  const std::string &vid, const std::string &oldLabel) {
+  const std::string &vid, const std::string &oldLabel, const std::optional<std::string> &unitName) {
   m_vid = vid;
   m_oldLabel = oldLabel;
   m_userName = userName;
   cta::tape::daemon::Tpconfig tpConfig;
   tpConfig  = cta::tape::daemon::Tpconfig::parseFile(castor::tape::TPCONFIGPATH);
   const int configuredDrives =  tpConfig.size();
-    if( 1 == configuredDrives)
-     for(auto & driveConfig: tpConfig) {
-      m_devFilename = driveConfig.second.value().devFilename;
-      m_rawLibrarySlot = driveConfig.second.value().rawLibrarySlot;
-      m_logicalLibrary = driveConfig.second.value().logicalLibrary;
-      m_unitName = driveConfig.second.value().unitName;
+  
+  if (unitName) {
+    bool found = false;
+    for (auto &driveConfig: tpConfig) {
+      auto currentUnitName = driveConfig.second.value().unitName;
+      if (currentUnitName == unitName.value()) {
+        m_devFilename = driveConfig.second.value().devFilename;
+        m_rawLibrarySlot = driveConfig.second.value().rawLibrarySlot;
+        m_logicalLibrary = driveConfig.second.value().logicalLibrary;
+        m_unitName = driveConfig.second.value().unitName;
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      cta::exception::Exception ex;
+      ex.getMessage() << "Drive with unit name " << unitName.value() << " does not exist in TPCONFIG";
+      throw ex;
+    }
+  } else {
+    m_log(cta::log::INFO, "Unit name not specified, choosing first line of TPCONFIG");
+    if (1 == configuredDrives) {
+      for (auto & driveConfig: tpConfig) {
+        m_devFilename = driveConfig.second.value().devFilename;
+        m_rawLibrarySlot = driveConfig.second.value().rawLibrarySlot;
+        m_logicalLibrary = driveConfig.second.value().logicalLibrary;
+        m_unitName = driveConfig.second.value().unitName;
+      }
     } else {
       cta::exception::Exception ex;
-      ex.getMessage() << "Failed to read configuration: " 
-                      << configuredDrives << " drives configured";
+      ex.getMessage() << "Failed to read configuration: " << configuredDrives << " drives configured, please use the --drive option";
       throw ex;
     }
+  }
+
 
   const cta::rdbms::Login catalogueLogin = cta::rdbms::Login::parseFile(CATALOGUE_CONFIG_PATH);
   const uint64_t nbConns = 1;
diff --git a/tapeserver/tapelabel/TapeLabelCmd.hpp b/tapeserver/tapelabel/TapeLabelCmd.hpp
index de0d1aaf90..b4d5e0fcba 100644
--- a/tapeserver/tapelabel/TapeLabelCmd.hpp
+++ b/tapeserver/tapelabel/TapeLabelCmd.hpp
@@ -169,9 +169,10 @@ private:
    * @param username The name of the user running the command-line tool.
    * @param vid The tape VID to be pre-label.
    * @param oldLabel The old label on tape to be checked when pre-labeling. Could be empty.
+   * @param unitName The unit name of the drive used to label the tape
    */
   void readAndSetConfiguration(const std::string &userName,
-    const std::string &vid, const std::string &oldLabel);
+    const std::string &vid, const std::string &oldLabel,  const std::optional<std::string> &unitName);
   
   
   /**
diff --git a/tapeserver/tapelabel/TapeLabelCmdLineArgs.cpp b/tapeserver/tapelabel/TapeLabelCmdLineArgs.cpp
index 7b92159769..15c7b840d3 100644
--- a/tapeserver/tapelabel/TapeLabelCmdLineArgs.cpp
+++ b/tapeserver/tapelabel/TapeLabelCmdLineArgs.cpp
@@ -39,6 +39,7 @@ TapeLabelCmdLineArgs::TapeLabelCmdLineArgs(const int argc, char *const *const ar
     {"vid", required_argument, nullptr, 'v'},
     {"oldlabel", required_argument, nullptr, 'o'},
     {"debug", no_argument, nullptr, 'd'},
+    {"drive", required_argument, nullptr, 'u'},
     {"loadtimeout", required_argument, nullptr, 't'},
     {"force", no_argument, nullptr, 'f'},
     {"help", no_argument, nullptr, 'h'},
@@ -51,7 +52,7 @@ TapeLabelCmdLineArgs::TapeLabelCmdLineArgs(const int argc, char *const *const ar
 
   int opt = 0;
 
-  while((opt = getopt_long(argc, argv, ":v:o:t:hdf", longopts, nullptr)) != -1) {
+  while((opt = getopt_long(argc, argv, ":v:o:t:u:hdf", longopts, nullptr)) != -1) {
     switch(opt) {
     case 'v':
       if (strlen(optarg) > CA_MAXVIDLEN) {
@@ -91,6 +92,9 @@ TapeLabelCmdLineArgs::TapeLabelCmdLineArgs(const int argc, char *const *const ar
         throw ex;
       }
       break;
+    case 'u':
+      m_unitName = std::string(optarg);
+      break;
     case 'h':
       help = true;
       break;
@@ -151,6 +155,7 @@ void TapeLabelCmdLineArgs::printUsage(std::ostream &os) {
     "Options:" <<std::endl <<
     "  -o, --oldlabel      The vid of the current tape label on the tape if it is not the same as VID" << std::endl <<
     "  -t, --loadtimeout   The timeout to load the tape in the drive slot in seconds (default: 2 hours)" << std::endl <<
+    "  -u, --drive         The unit name of the drive used (if absent, the first line of TPCONFIG is used)" << std::endl <<
     "  -h, --help          Print this help message and exit" << std::endl <<
     "  -d, --debug         Print more logs for label operations" << std::endl <<
     "  -f, --force         Force labeling for not-blank tapes for testing purpose and without label checks. Must only be used manually." << std::endl;  
diff --git a/tapeserver/tapelabel/TapeLabelCmdLineArgs.hpp b/tapeserver/tapelabel/TapeLabelCmdLineArgs.hpp
index 3f59ab6b16..2513d1f238 100644
--- a/tapeserver/tapelabel/TapeLabelCmdLineArgs.hpp
+++ b/tapeserver/tapelabel/TapeLabelCmdLineArgs.hpp
@@ -18,6 +18,7 @@
 #pragma once
 
 #include <string>
+#include <optional>
 
 namespace cta {
 namespace tapeserver {
@@ -43,6 +44,11 @@ struct TapeLabelCmdLineArgs {
    */
   std::string m_oldLabel;
   
+  /**
+   * The unit name of the drive used to mount the tape.
+   */
+  std::optional<std::string> m_unitName;
+
   /**
    * The boolean variable to enable verbose output in the command line.
    * By default it prints only ERR and WARNING messages. 
-- 
GitLab