XrdCtaFile.cpp 124 KB
Newer Older
1
/*
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 * 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/>.
 */

19
#include "scheduler/SchedulerDatabase.hpp"
20
#include "xroot_plugins/XrdCtaFile.hpp"
Daniele Kruse's avatar
Daniele Kruse committed
21

22
#include "XrdSec/XrdSecEntity.hh"
23
24

#include "catalogue/ArchiveFileSearchCriteria.hpp"
25
#include "common/Configuration.hpp"
26
#include "common/utils/utils.hpp"
27

28
29
#include <cryptopp/base64.h>
#include <cryptopp/osrng.h>
30
#include <iomanip>
31
#include <iostream>
32
#include <memory>
33
#include <pwd.h>
34
35
#include <sstream>
#include <string>
36
#include <time.h>
37

38
39
namespace cta { namespace xrootPlugins {

40
41
42
//------------------------------------------------------------------------------
// checkClient
//------------------------------------------------------------------------------
43
void XrdCtaFile::checkClient(const XrdSecEntity *client) {
44
45
46
  if(client==NULL || client->name==NULL || client->host==NULL) {
    throw cta::exception::Exception(std::string(__FUNCTION__)+": [ERROR] XrdSecEntity from xroot contains invalid information (NULL pointer detected!)");
  }
47
  std::cout << "FILE Request received from client. Username: " << client->name << " Host: " << client->host << std::endl;
48
49
50
51
52
53
54
55
  m_cliIdentity.username=client->name;
  m_cliIdentity.host=client->host;
}

//------------------------------------------------------------------------------
// logRequestAndSetCmdlineResult
//------------------------------------------------------------------------------
int XrdCtaFile::logRequestAndSetCmdlineResult(const cta::common::dataStructures::FrontendReturnCode rc, const std::string &returnString) {
56
57
  m_cmdlineOutput = returnString;
  m_cmdlineReturnCode = rc;
58
59
60
61
  
  std::list<log::Param> params;
  params.push_back(log::Param("USERNAME", m_cliIdentity.username));
  params.push_back(log::Param("HOST", m_cliIdentity.host));
62
  params.push_back(log::Param("RETURN_CODE", toString(m_cmdlineReturnCode)));
63
  std::stringstream originalRequest;
64
  for(auto it=m_requestTokens.begin(); it!=m_requestTokens.end(); it++) {
65
66
67
68
    originalRequest << *it << " ";
  }
  params.push_back(log::Param("REQUEST", originalRequest.str()));
  
69
  switch(m_cmdlineReturnCode) {
70
71
72
73
    case cta::common::dataStructures::FrontendReturnCode::ok:
      m_log(log::INFO, "Successful Request", params);
      break;
    case cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry:
74
      m_log(log::USERERR, "Syntax error or missing argument(s) in request", params);
75
76
77
78
79
80
81
82
      break;
    default:
      params.push_back(log::Param("ERROR", returnString));
      m_log(log::ERR, "Unsuccessful Request", params);
      break;
  }

  return SFS_OK;
83
84
}

85
86
87
//------------------------------------------------------------------------------
// commandDispatcher
//------------------------------------------------------------------------------
88
int XrdCtaFile::dispatchCommand() {
89
  std::string command(m_requestTokens.at(1));
90
  
91
  std::vector<std::string> adminCommands = {"bs","bootstrap","ad","admin","ah","adminhost","tp","tapepool","ar","archiveroute","ll","logicallibrary",
92
          "ta","tape","sc","storageclass","us","user","mg","mountpolicy","de","dedication","re","repack","sh","shrink","ve","verify",
93
94
95
          "af","archivefile","te","test","dr","drive","rc","reconcile","lpa","listpendingarchives","lpr","listpendingretrieves","lds","listdrivestates"};
  
  if (std::find(adminCommands.begin(), adminCommands.end(), command) != adminCommands.end()) {
96
    m_scheduler->authorizeCliIdentity(m_cliIdentity);
97
98
  }
  
99
100
101
102
103
104
105
106
  if     ("bs"   == command || "bootstrap"              == command) {return xCom_bootstrap();}
  else if("ad"   == command || "admin"                  == command) {return xCom_admin();}
  else if("ah"   == command || "adminhost"              == command) {return xCom_adminhost();}
  else if("tp"   == command || "tapepool"               == command) {return xCom_tapepool();}
  else if("ar"   == command || "archiveroute"           == command) {return xCom_archiveroute();}
  else if("ll"   == command || "logicallibrary"         == command) {return xCom_logicallibrary();}
  else if("ta"   == command || "tape"                   == command) {return xCom_tape();}
  else if("sc"   == command || "storageclass"           == command) {return xCom_storageclass();}
107
108
  else if("rmr"  == command || "requestermountrule"     == command) {return xCom_requestermountrule();}
  else if("gmr"  == command || "groupmountrule"         == command) {return xCom_groupmountrule();}
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
  else if("mg"   == command || "mountpolicy"            == command) {return xCom_mountpolicy();}
  else if("de"   == command || "dedication"             == command) {return xCom_dedication();}
  else if("re"   == command || "repack"                 == command) {return xCom_repack();}
  else if("sh"   == command || "shrink"                 == command) {return xCom_shrink();}
  else if("ve"   == command || "verify"                 == command) {return xCom_verify();}
  else if("af"   == command || "archivefile"            == command) {return xCom_archivefile();}
  else if("te"   == command || "test"                   == command) {return xCom_test();}
  else if("dr"   == command || "drive"                  == command) {return xCom_drive();}
  else if("rc"   == command || "reconcile"              == command) {return xCom_reconcile();}
  else if("lpa"  == command || "listpendingarchives"    == command) {return xCom_listpendingarchives();}
  else if("lpr"  == command || "listpendingretrieves"   == command) {return xCom_listpendingretrieves();}
  else if("lds"  == command || "listdrivestates"        == command) {return xCom_listdrivestates();}
  else if("a"    == command || "archive"                == command) {return xCom_archive();}
  else if("r"    == command || "retrieve"               == command) {return xCom_retrieve();}
  else if("da"   == command || "deletearchive"          == command) {return xCom_deletearchive();}
  else if("cr"   == command || "cancelretrieve"         == command) {return xCom_cancelretrieve();}
  else if("ufi"  == command || "updatefileinfo"         == command) {return xCom_updatefileinfo();}
  else if("ufsc" == command || "updatefilestorageclass" == command) {return xCom_updatefilestorageclass();}
  else if("lsc"  == command || "liststorageclass"       == command) {return xCom_liststorageclass();}
128
  
129
  else {
130
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, getGenericHelp(m_requestTokens.at(0)));
131
  }
132
}
Daniele Kruse's avatar
Daniele Kruse committed
133

134
135
136
//------------------------------------------------------------------------------
// decode
//------------------------------------------------------------------------------
137
std::string XrdCtaFile::decode(const std::string msg) const {
138
139
140
141
142
  std::string ret;
  CryptoPP::StringSource ss1(msg, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(ret)));
  return ret;
}

Daniele Kruse's avatar
Daniele Kruse committed
143
144
145
//------------------------------------------------------------------------------
// open
//------------------------------------------------------------------------------
146
int XrdCtaFile::open(const char *fileName, XrdSfsFileOpenMode openMode, mode_t createMode, const XrdSecEntity *client, const char *opaque) {
147
  try {
148
    checkClient(client);
149
    if(!strlen(fileName)) { //this should never happen
150
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, getGenericHelp(""));
151
    }
152
    
153
    std::stringstream ss(fileName+1); //let's skip the first slash which is always prepended since we are asking for an absolute path
154
155
156
157
158
159
160
161
    std::string item;
    while (std::getline(ss, item, '&')) {
      replaceAll(item, "_", "/"); 
      //need to add this because xroot removes consecutive slashes, and the 
      //cryptopp base64 algorithm may produce consecutive slashes. This is solved 
      //in cryptopp-5.6.3 (using Base64URLEncoder instead of Base64Encoder) but we 
      //currently have cryptopp-5.6.2. To be changed in the future...
      item = decode(item);
162
      m_requestTokens.push_back(item);
163
164
    }

165
    if(m_requestTokens.size() == 0) { //this should never happen
166
167
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, getGenericHelp(""));
    }
168
169
    if(m_requestTokens.size() < 2) {
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, getGenericHelp(m_requestTokens.at(0)));
170
    }    
171
    return dispatchCommand();
172
  } catch (cta::exception::Exception &ex) {
173
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ctaErrorNoRetry, ex.getMessageValue()+"\n");
174
  } catch (std::exception &ex) {
175
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ctaErrorNoRetry, std::string(ex.what())+"\n");
176
  } catch (...) {
177
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ctaErrorNoRetry, "Unknown exception caught!\n");
178
  }
Daniele Kruse's avatar
Daniele Kruse committed
179
180
181
182
183
}

//------------------------------------------------------------------------------
// close
//------------------------------------------------------------------------------
184
int XrdCtaFile::close() {
Daniele Kruse's avatar
Daniele Kruse committed
185
  return SFS_OK;
Daniele Kruse's avatar
Daniele Kruse committed
186
187
188
189
190
}

//------------------------------------------------------------------------------
// fctl
//------------------------------------------------------------------------------
191
int XrdCtaFile::fctl(const int cmd, const char *args, XrdOucErrInfo &eInfo) {  
Daniele Kruse's avatar
Daniele Kruse committed
192
193
194
195
196
197
198
  error.setErrInfo(ENOTSUP, "Not supported.");
  return SFS_ERROR;
}

//------------------------------------------------------------------------------
// FName
//------------------------------------------------------------------------------
199
const char* XrdCtaFile::FName() {
Daniele Kruse's avatar
Daniele Kruse committed
200
201
202
203
204
205
206
  error.setErrInfo(ENOTSUP, "Not supported.");
  return NULL;
}

//------------------------------------------------------------------------------
// getMmap
//------------------------------------------------------------------------------
207
int XrdCtaFile::getMmap(void **Addr, off_t &Size) {
208
209
210
  m_cmdlineOutput = std::to_string(m_cmdlineReturnCode) + m_cmdlineOutput;
  *Addr = const_cast<char *>(m_cmdlineOutput.c_str());
  Size = m_cmdlineOutput.length();
211
  return SFS_OK; //change to "return SFS_ERROR;" in case the read function below is wanted, in that case uncomment the lines in that function.
Daniele Kruse's avatar
Daniele Kruse committed
212
213
214
215
216
}

//------------------------------------------------------------------------------
// read
//------------------------------------------------------------------------------
217
XrdSfsXferSize XrdCtaFile::read(XrdSfsFileOffset offset, char *buffer, XrdSfsXferSize size) {
218
219
220
//  if((unsigned long)offset<m_cmdlineOutput.length()) {
//    strncpy(buffer, m_cmdlineOutput.c_str()+offset, size);
//    return m_cmdlineOutput.length()-offset;
221
222
//  }
//  else {
223
//    return SFS_OK;
224
225
//  }
  error.setErrInfo(ENOTSUP, "Not supported.");
226
  return SFS_ERROR;
Daniele Kruse's avatar
Daniele Kruse committed
227
228
}

229
230
231
//------------------------------------------------------------------------------
// read
//------------------------------------------------------------------------------
232
XrdSfsXferSize XrdCtaFile::read(XrdSfsFileOffset offset, XrdSfsXferSize size) {
233
  error.setErrInfo(ENOTSUP, "Not supported.");
234
  return SFS_ERROR;
235
236
}

Daniele Kruse's avatar
Daniele Kruse committed
237
238
239
//------------------------------------------------------------------------------
// read
//------------------------------------------------------------------------------
240
XrdSfsXferSize XrdCtaFile::read(XrdSfsAio *aioparm) {
Daniele Kruse's avatar
Daniele Kruse committed
241
  error.setErrInfo(ENOTSUP, "Not supported.");
242
  return SFS_ERROR;
Daniele Kruse's avatar
Daniele Kruse committed
243
244
245
246
247
}

//------------------------------------------------------------------------------
// write
//------------------------------------------------------------------------------
248
XrdSfsXferSize XrdCtaFile::write(XrdSfsFileOffset offset, const char *buffer, XrdSfsXferSize size) {
Daniele Kruse's avatar
Daniele Kruse committed
249
  error.setErrInfo(ENOTSUP, "Not supported.");
250
  return SFS_ERROR;
Daniele Kruse's avatar
Daniele Kruse committed
251
252
253
254
255
}

//------------------------------------------------------------------------------
// write
//------------------------------------------------------------------------------
256
int XrdCtaFile::write(XrdSfsAio *aioparm) {
Daniele Kruse's avatar
Daniele Kruse committed
257
258
259
260
261
262
263
  error.setErrInfo(ENOTSUP, "Not supported.");
  return SFS_ERROR;
}

//------------------------------------------------------------------------------
// stat
//------------------------------------------------------------------------------
264
int XrdCtaFile::stat(struct stat *buf) {
265
  buf->st_size=m_cmdlineOutput.length();
Daniele Kruse's avatar
Daniele Kruse committed
266
  return SFS_OK;
Daniele Kruse's avatar
Daniele Kruse committed
267
268
269
270
271
}

//------------------------------------------------------------------------------
// sync
//------------------------------------------------------------------------------
272
int XrdCtaFile::sync() {
Daniele Kruse's avatar
Daniele Kruse committed
273
274
275
276
277
278
279
  error.setErrInfo(ENOTSUP, "Not supported.");
  return SFS_ERROR;
}

//------------------------------------------------------------------------------
// sync
//------------------------------------------------------------------------------
280
int XrdCtaFile::sync(XrdSfsAio *aiop) {
Daniele Kruse's avatar
Daniele Kruse committed
281
282
283
284
285
286
287
  error.setErrInfo(ENOTSUP, "Not supported.");
  return SFS_ERROR;
}

//------------------------------------------------------------------------------
// truncate
//------------------------------------------------------------------------------
288
int XrdCtaFile::truncate(XrdSfsFileOffset fsize) {
Daniele Kruse's avatar
Daniele Kruse committed
289
290
291
292
293
294
295
  error.setErrInfo(ENOTSUP, "Not supported.");
  return SFS_ERROR;
}

//------------------------------------------------------------------------------
// getCXinfo
//------------------------------------------------------------------------------
296
int XrdCtaFile::getCXinfo(char cxtype[4], int &cxrsz) {
Daniele Kruse's avatar
Daniele Kruse committed
297
298
299
300
301
302
303
  error.setErrInfo(ENOTSUP, "Not supported.");
  return SFS_ERROR;
}

//------------------------------------------------------------------------------
// Constructor
//------------------------------------------------------------------------------
304
XrdCtaFile::XrdCtaFile(
305
306
  cta::catalogue::Catalogue *catalogue,
  cta::Scheduler *scheduler,
307
  cta::log::Logger *log,
308
309
310
311
312
  const char *user,
  int MonID):
  error(user, MonID),
  m_catalogue(catalogue),
  m_scheduler(scheduler),
313
  m_log(*log),
314
315
  m_cmdlineOutput(""),
  m_cmdlineReturnCode(cta::common::dataStructures::FrontendReturnCode::ok) {  
Daniele Kruse's avatar
Daniele Kruse committed
316
317
318
319
320
}

//------------------------------------------------------------------------------
// Destructor
//------------------------------------------------------------------------------
321
XrdCtaFile::~XrdCtaFile() {  
322
323
324
325
326
}

//------------------------------------------------------------------------------
// replaceAll
//------------------------------------------------------------------------------
327
void XrdCtaFile::replaceAll(std::string& str, const std::string& from, const std::string& to) const {
328
  if(from.empty() || str.empty())
329
    return;
330
331
  size_t start_pos = 0;
  while((start_pos = str.find(from, start_pos)) != std::string::npos) {
332
333
    str.replace(start_pos, from.length(), to);
    start_pos += to.length();
334
  }
335
336
}

337
338
339
//------------------------------------------------------------------------------
// getOptionValue
//------------------------------------------------------------------------------
340
std::string XrdCtaFile::getOptionValue(const std::string& optionShortName, const std::string& optionLongName, const bool encoded) {
341
  for(auto it=m_requestTokens.cbegin(); it!=m_requestTokens.cend(); it++) {
342
    if(optionShortName == *it || optionLongName == *it) {
343
      auto it_next=it+1;
344
      if(it_next!=m_requestTokens.cend()) {
345
346
        if(!encoded) return *it_next;
        else return decode(*it_next);
347
348
349
350
      }
      else {
        return "";
      }
351
352
353
354
355
    }
  }
  return "";
}

356
357
358
//------------------------------------------------------------------------------
// hasOption
//------------------------------------------------------------------------------
359
bool XrdCtaFile::hasOption(const std::string& optionShortName, const std::string& optionLongName) {
360
  for(auto it=m_requestTokens.cbegin(); it!=m_requestTokens.cend(); it++) {
361
362
363
364
365
366
367
    if(optionShortName == *it || optionLongName == *it) {
      return true;
    }
  }
  return false;
}

368
369
370
//------------------------------------------------------------------------------
// timeToString
//------------------------------------------------------------------------------
371
std::string XrdCtaFile::timeToString(const time_t &time) {
372
373
374
375
376
  std::string timeString(ctime(&time));
  timeString=timeString.substr(0,timeString.size()-1); //remove newline
  return timeString;
}

377
//------------------------------------------------------------------------------
378
// formatResponse
379
//------------------------------------------------------------------------------
380
std::string XrdCtaFile::formatResponse(const std::vector<std::vector<std::string>> &responseTable, const bool withHeader) {
381
382
  if(responseTable.empty()||responseTable.at(0).empty()) {
    return "";
383
  }
384
  std::vector<int> columnSizes;
385
  for(uint j=0; j<responseTable.at(0).size(); j++) { //for each column j
386
    uint columnSize=0;
387
    for(uint i=0; i<responseTable.size(); i++) { //for each row i
388
389
390
      if(responseTable.at(i).at(j).size()>columnSize) {
        columnSize=responseTable.at(i).at(j).size();
      }
391
    }
392
    columnSize++; //add one space
393
    columnSizes.push_back(columnSize);//loops here
394
  }
395
396
  std::stringstream responseSS;
  for(auto row=responseTable.cbegin(); row!=responseTable.cend(); row++) {
397
398
399
    if(withHeader && row==responseTable.cbegin()) responseSS << "\x1b[31;1m";
    for(uint i=0; i<row->size(); i++) {
      responseSS << " " << std::setw(columnSizes.at(i)) << row->at(i);
400
    }
401
402
    if(withHeader && row==responseTable.cbegin()) responseSS << "\x1b[0m" << std::endl;
    else responseSS << std::endl;
403
  }
404
405
406
407
408
409
  return responseSS.str();
}

//------------------------------------------------------------------------------
// addLogInfoToResponseRow
//------------------------------------------------------------------------------
410
void XrdCtaFile::addLogInfoToResponseRow(std::vector<std::string> &responseRow, const cta::common::dataStructures::EntryLog &creationLog, const cta::common::dataStructures::EntryLog &lastModificationLog) {
411
  responseRow.push_back(creationLog.username);
412
413
  responseRow.push_back(creationLog.host);
  responseRow.push_back(timeToString(creationLog.time));
414
  responseRow.push_back(lastModificationLog.username);
415
416
  responseRow.push_back(lastModificationLog.host);
  responseRow.push_back(timeToString(lastModificationLog.time));
417
418
}

419
420
421
422
423
//------------------------------------------------------------------------------
// stringParameterToUint64
//------------------------------------------------------------------------------
uint64_t XrdCtaFile::stringParameterToUint64(const std::string &parameterName, const std::string &parameterValue) const {
  try {
424
425
426
427
428
    return cta::utils::toUint64(parameterValue);
  } catch(cta::exception::Exception &ex) {
    throw cta::exception::Exception(std::string(__FUNCTION__)+" - Parameter: "+parameterName+" ("+parameterValue+
            ") could not be converted to uint64_t because: " + ex.getMessageValue());
  } 
429
430
431
  return 0;
}

432
433
434
//------------------------------------------------------------------------------
// xCom_bootstrap
//------------------------------------------------------------------------------
435
436
int XrdCtaFile::xCom_bootstrap() {
  std::stringstream cmdlineOutput;
437
  std::stringstream help;
438
  help << m_requestTokens.at(0) << " bs/bootstrap --username/-u <user_name> --hostname/-h <host_name> --comment/-m <\"comment\">" << std::endl;
439
440
441
  std::string username = getOptionValue("-u", "--username", false);
  std::string hostname = getOptionValue("-h", "--hostname", false);
  std::string comment = getOptionValue("-m", "--comment", false);
442
  if(username.empty()||hostname.empty()||comment.empty()) {
443
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
444
  }
445
446
  m_catalogue->createBootstrapAdminAndHostNoAuth(m_cliIdentity, username, hostname, comment);
  return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ok, cmdlineOutput.str());
447
448
449
450
451
}

//------------------------------------------------------------------------------
// xCom_admin
//------------------------------------------------------------------------------
452
453
int XrdCtaFile::xCom_admin() {
  std::stringstream cmdlineOutput;
454
  std::stringstream help;
455
  help << m_requestTokens.at(0) << " ad/admin add/ch/rm/ls:" << std::endl
456
457
458
       << "\tadd --username/-u <user_name> --comment/-m <\"comment\">" << std::endl
       << "\tch  --username/-u <user_name> --comment/-m <\"comment\">" << std::endl
       << "\trm  --username/-u <user_name>" << std::endl
459
       << "\tls  [--header/-h]" << std::endl;  
460
  if(m_requestTokens.size() < 3) {
461
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
462
  }
463
  if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2)) {
464
    std::string username = getOptionValue("-u", "--username", false);
465
    if(username.empty()) {
466
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
467
    }
468
    if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2)) {
469
      std::string comment = getOptionValue("-m", "--comment", false);
470
      if(comment.empty()) {
471
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
472
      }
473
      if("add" == m_requestTokens.at(2)) { //add
474
        m_catalogue->createAdminUser(m_cliIdentity, username, comment);
475
476
      }
      else { //ch
477
        m_catalogue->modifyAdminUserComment(m_cliIdentity, username, comment);
478
479
480
      }
    }
    else { //rm
481
      m_catalogue->deleteAdminUser(username);
482
    }
483
  }
484
  else if("ls" == m_requestTokens.at(2)) { //ls
485
    std::list<cta::common::dataStructures::AdminUser> list= m_catalogue->getAdminUsers();
486
    if(list.size()>0) {
487
      std::vector<std::vector<std::string>> responseTable;
488
      std::vector<std::string> header = {"user","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
489
      if(hasOption("-h", "--header")) responseTable.push_back(header);    
490
      for(auto it = list.cbegin(); it != list.cend(); it++) {
491
        std::vector<std::string> currentRow;
492
        currentRow.push_back(it->name);
493
494
        addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
        currentRow.push_back(it->comment);
495
496
        responseTable.push_back(currentRow);
      }
497
      cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
498
499
500
    }
  }
  else {
501
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
502
  }
503
  return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ok, cmdlineOutput.str());
504
}
505

506
//------------------------------------------------------------------------------
507
// xCom_adminhost
508
//------------------------------------------------------------------------------
509
510
int XrdCtaFile::xCom_adminhost() {
  std::stringstream cmdlineOutput;
511
  std::stringstream help;
512
  help << m_requestTokens.at(0) << " ah/adminhost add/ch/rm/ls:" << std::endl
513
       << "\tadd --name/-n <host_name> --comment/-m <\"comment\">" << std::endl
Daniele Kruse's avatar
Daniele Kruse committed
514
       << "\tch  --name/-n <host_name> --comment/-m <\"comment\">" << std::endl
515
       << "\trm  --name/-n <host_name>" << std::endl
516
       << "\tls  [--header/-h]" << std::endl;  
517
  if(m_requestTokens.size() < 3) {
518
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
519
  }
520
  if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2)) {
521
    std::string hostname = getOptionValue("-n", "--name", false);
Daniele Kruse's avatar
Daniele Kruse committed
522
    if(hostname.empty()) {
523
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
524
    }
525
    if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2)) {
526
      std::string comment = getOptionValue("-m", "--comment", false);
Daniele Kruse's avatar
Daniele Kruse committed
527
      if(comment.empty()) {
528
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
529
      }
530
      if("add" == m_requestTokens.at(2)) { //add
531
        m_catalogue->createAdminHost(m_cliIdentity, hostname, comment);
Daniele Kruse's avatar
Daniele Kruse committed
532
533
      }
      else { //ch
534
        m_catalogue->modifyAdminHostComment(m_cliIdentity, hostname, comment);
Daniele Kruse's avatar
Daniele Kruse committed
535
536
537
      }
    }
    else { //rm
538
      m_catalogue->deleteAdminHost(hostname);
Daniele Kruse's avatar
Daniele Kruse committed
539
540
    }
  }
541
  else if("ls" == m_requestTokens.at(2)) { //ls
542
    std::list<cta::common::dataStructures::AdminHost> list= m_catalogue->getAdminHosts();
Daniele Kruse's avatar
Daniele Kruse committed
543
544
    if(list.size()>0) {
      std::vector<std::vector<std::string>> responseTable;
545
      std::vector<std::string> header = {"hostname","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
546
      if(hasOption("-h", "--header")) responseTable.push_back(header);
547
      for(auto it = list.cbegin(); it != list.cend(); it++) {
Daniele Kruse's avatar
Daniele Kruse committed
548
        std::vector<std::string> currentRow;
549
550
551
        currentRow.push_back(it->name);
        addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
        currentRow.push_back(it->comment);
Daniele Kruse's avatar
Daniele Kruse committed
552
553
        responseTable.push_back(currentRow);
      }
554
      cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
Daniele Kruse's avatar
Daniele Kruse committed
555
556
557
    }
  }
  else {
558
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
559
  }
560
  return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ok, cmdlineOutput.str());
561
}
562

563
564
565
//------------------------------------------------------------------------------
// xCom_tapepool
//------------------------------------------------------------------------------
566
567
int XrdCtaFile::xCom_tapepool() {
  std::stringstream cmdlineOutput;
568
  std::stringstream help;
569
  help << m_requestTokens.at(0) << " tp/tapepool add/ch/rm/ls:" << std::endl
570
571
       << "\tadd --name/-n <tapepool_name> --partialtapesnumber/-p <number_of_partial_tapes> [--encryption/-e or --clear/-c] --comment/-m <\"comment\">" << std::endl
       << "\tch  --name/-n <tapepool_name> [--partialtapesnumber/-p <number_of_partial_tapes>] [--encryption/-e or --clear/-c] [--comment/-m <\"comment\">]" << std::endl
572
       << "\trm  --name/-n <tapepool_name>" << std::endl
573
       << "\tls  [--header/-h]" << std::endl;  
574
  if(m_requestTokens.size() < 3) {
575
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
576
  }
577
  if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2)) {
578
    std::string name = getOptionValue("-n", "--name", false);
Daniele Kruse's avatar
Daniele Kruse committed
579
    if(name.empty()) {
580
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
581
    }
582
    if("add" == m_requestTokens.at(2)) { //add
583
584
      std::string ptn_s = getOptionValue("-p", "--partialtapesnumber", false);
      std::string comment = getOptionValue("-m", "--comment", false);
Daniele Kruse's avatar
Daniele Kruse committed
585
      if(comment.empty()||ptn_s.empty()) {
586
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
587
      }
588
      uint64_t ptn = stringParameterToUint64("--partialtapesnumber/-p", ptn_s);
589
      bool encryption=false;
590
591
      if((hasOption("-e", "--encryption") && hasOption("-c", "--clear"))) {
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
592
      }
593
594
      encryption=hasOption("-e", "--encryption");
      m_catalogue->createTapePool(m_cliIdentity, name, ptn, encryption, comment);
Daniele Kruse's avatar
Daniele Kruse committed
595
    }
596
    else if("ch" == m_requestTokens.at(2)) { //ch
597
598
      std::string ptn_s = getOptionValue("-p", "--partialtapesnumber", false);
      std::string comment = getOptionValue("-m", "--comment", false);
Daniele Kruse's avatar
Daniele Kruse committed
599
      if(comment.empty()&&ptn_s.empty()) {
600
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
601
602
      }
      if(!comment.empty()) {
603
        m_catalogue->modifyTapePoolComment(m_cliIdentity, name, comment);
Daniele Kruse's avatar
Daniele Kruse committed
604
605
      }
      if(!ptn_s.empty()) {
606
        uint64_t ptn = stringParameterToUint64("--partialtapesnumber/-p", ptn_s);
607
        m_catalogue->modifyTapePoolNbPartialTapes(m_cliIdentity, name, ptn);
Daniele Kruse's avatar
Daniele Kruse committed
608
      }
609
610
      if(hasOption("-e", "--encryption")) {
        m_catalogue->setTapePoolEncryption(m_cliIdentity, name, true);
611
      }
612
613
      if(hasOption("-c", "--clear")) {
        m_catalogue->setTapePoolEncryption(m_cliIdentity, name, false);
614
      }
Daniele Kruse's avatar
Daniele Kruse committed
615
616
    }
    else { //rm
617
      m_catalogue->deleteTapePool(name);
Daniele Kruse's avatar
Daniele Kruse committed
618
619
    }
  }
620
  else if("ls" == m_requestTokens.at(2)) { //ls
621
    std::list<cta::common::dataStructures::TapePool> list= m_catalogue->getTapePools();
Daniele Kruse's avatar
Daniele Kruse committed
622
623
    if(list.size()>0) {
      std::vector<std::vector<std::string>> responseTable;
624
      std::vector<std::string> header = {"name","# partial tapes","encrypt","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
625
      if(hasOption("-h", "--header")) responseTable.push_back(header);    
626
      for(auto it = list.cbegin(); it != list.cend(); it++) {
Daniele Kruse's avatar
Daniele Kruse committed
627
        std::vector<std::string> currentRow;
628
629
        currentRow.push_back(it->name);
        currentRow.push_back(std::to_string((unsigned long long)it->nbPartialTapes));
630
        if(it->encryption) currentRow.push_back("true"); else currentRow.push_back("false");
631
632
        addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
        currentRow.push_back(it->comment);
Daniele Kruse's avatar
Daniele Kruse committed
633
634
        responseTable.push_back(currentRow);
      }
635
      cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
Daniele Kruse's avatar
Daniele Kruse committed
636
637
638
    }
  }
  else {
639
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
640
  }
641
  return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ok, cmdlineOutput.str());
642
}
643

644
645
646
//------------------------------------------------------------------------------
// xCom_archiveroute
//------------------------------------------------------------------------------
647
648
int XrdCtaFile::xCom_archiveroute() {
  std::stringstream cmdlineOutput;
649
  std::stringstream help;
650
  help << m_requestTokens.at(0) << " ar/archiveroute add/ch/rm/ls:" << std::endl
651
652
653
       << "\tadd --storageclass/-s <storage_class_name> --copynb/-c <copy_number> --tapepool/-t <tapepool_name> --comment/-m <\"comment\">" << std::endl
       << "\tch  --storageclass/-s <storage_class_name> --copynb/-c <copy_number> [--tapepool/-t <tapepool_name>] [--comment/-m <\"comment\">]" << std::endl
       << "\trm  --storageclass/-s <storage_class_name> --copynb/-c <copy_number>" << std::endl
654
       << "\tls  [--header/-h]" << std::endl;  
655
  if(m_requestTokens.size() < 3) {
656
657
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
  }
658
  if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2)) {
659
660
    std::string scn = getOptionValue("-s", "--storageclass", false);
    std::string cn_s = getOptionValue("-c", "--copynb", false);
Daniele Kruse's avatar
Daniele Kruse committed
661
    if(scn.empty()||cn_s.empty()) {
662
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
663
    }    
664
    uint64_t cn = stringParameterToUint64("--copynb/-c", cn_s);
665
    if("add" == m_requestTokens.at(2)) { //add
666
667
      std::string tapepool = getOptionValue("-t", "--tapepool", false);
      std::string comment = getOptionValue("-m", "--comment", false);
Daniele Kruse's avatar
Daniele Kruse committed
668
      if(comment.empty()||tapepool.empty()) {
669
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
670
      }
671
      m_catalogue->createArchiveRoute(m_cliIdentity, scn, cn, tapepool, comment);
Daniele Kruse's avatar
Daniele Kruse committed
672
    }
673
    else if("ch" == m_requestTokens.at(2)) { //ch
674
675
      std::string tapepool = getOptionValue("-t", "--tapepool", false);
      std::string comment = getOptionValue("-m", "--comment", false);
Daniele Kruse's avatar
Daniele Kruse committed
676
      if(comment.empty()&&tapepool.empty()) {
677
        return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
678
679
      }
      if(!comment.empty()) {
680
        m_catalogue->modifyArchiveRouteComment(m_cliIdentity, scn, cn, comment);
Daniele Kruse's avatar
Daniele Kruse committed
681
682
      }
      if(!tapepool.empty()) {
683
        m_catalogue->modifyArchiveRouteTapePoolName(m_cliIdentity, scn, cn, tapepool);
Daniele Kruse's avatar
Daniele Kruse committed
684
685
686
      }
    }
    else { //rm
687
      m_catalogue->deleteArchiveRoute(scn, cn);
Daniele Kruse's avatar
Daniele Kruse committed
688
689
    }
  }
690
  else if("ls" == m_requestTokens.at(2)) { //ls
691
    std::list<cta::common::dataStructures::ArchiveRoute> list= m_catalogue->getArchiveRoutes();
Daniele Kruse's avatar
Daniele Kruse committed
692
693
    if(list.size()>0) {
      std::vector<std::vector<std::string>> responseTable;
694
      std::vector<std::string> header = {"storage class","copy number","tapepool","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
695
      if(hasOption("-h", "--header")) responseTable.push_back(header);    
696
      for(auto it = list.cbegin(); it != list.cend(); it++) {
Daniele Kruse's avatar
Daniele Kruse committed
697
        std::vector<std::string> currentRow;
698
699
700
701
702
        currentRow.push_back(it->storageClassName);
        currentRow.push_back(std::to_string((unsigned long long)it->copyNb));
        currentRow.push_back(it->tapePoolName);
        addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
        currentRow.push_back(it->comment);
Daniele Kruse's avatar
Daniele Kruse committed
703
704
        responseTable.push_back(currentRow);
      }
705
      cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
Daniele Kruse's avatar
Daniele Kruse committed
706
707
708
    }
  }
  else {
709
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
710
  }
711
  return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::ok, cmdlineOutput.str());
712
}
713

714
715
716
//------------------------------------------------------------------------------
// xCom_logicallibrary
//------------------------------------------------------------------------------
717
718
int XrdCtaFile::xCom_logicallibrary() {
  std::stringstream cmdlineOutput;
719
  std::stringstream help;
720
  help << m_requestTokens.at(0) << " ll/logicallibrary add/ch/rm/ls:" << std::endl
721
722
       << "\tadd --name/-n <logical_library_name> --comment/-m <\"comment\">" << std::endl
       << "\tch  --name/-n <logical_library_name> --comment/-m <\"comment\">" << std::endl
723
       << "\trm  --name/-n <logical_library_name>" << std::endl
724
       << "\tls  [--header/-h]" << std::endl;  
725
  if(m_requestTokens.size() < 3) {
726
    return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
727
  }
728
  if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2) || "rm" == m_requestTokens.at(2)) {
729
    std::string name = getOptionValue("-n", "--name", false);
730
    if(name.empty()) {
731
      return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
732
    }
733
    if("add" == m_requestTokens.at(2) || "ch" == m_requestTokens.at(2)) {
734
      std::string comment = getOptionValue("-m", "--comment", false);
735
      if("add" == m_requestTokens.at(2)) { //add
736
        if(comment.empty()) {
737
          return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
738
        }
739
        m_catalogue->createLogicalLibrary(m_cliIdentity, name, comment);
Daniele Kruse's avatar
Daniele Kruse committed
740
741
      }
      else { //ch
742
        if(comment.empty()) {
743
          return logRequestAndSetCmdlineResult(cta::common::dataStructures::FrontendReturnCode::userErrorNoRetry, help.str());
Daniele Kruse's avatar
Daniele Kruse committed
744
        }
745
        m_catalogue->modifyLogicalLibraryComment(m_cliIdentity, name, comment);
Daniele Kruse's avatar
Daniele Kruse committed
746
747
748
      }
    }
    else { //rm
749
      m_catalogue->deleteLogicalLibrary(name);
Daniele Kruse's avatar
Daniele Kruse committed
750
751
    }
  }
752
  else if("ls" == m_requestTokens.at(2)) { //ls
753
    std::list<cta::common::dataStructures::LogicalLibrary> list= m_catalogue->getLogicalLibraries();
Daniele Kruse's avatar
Daniele Kruse committed
754
755
    if(list.size()>0) {
      std::vector<std::vector<std::string>> responseTable;
756
      std::vector<std::string> header = {"name","c.user","c.host","c.time","m.user","m.host","m.time","comment"};
757
      if(hasOption("-h", "--header")) responseTable.push_back(header);    
758
      for(auto it = list.cbegin(); it != list.cend(); it++) {
Daniele Kruse's avatar
Daniele Kruse committed
759
        std::vector<std::string> currentRow;
760
761
762
        currentRow.push_back(it->name);
        addLogInfoToResponseRow(currentRow, it->creationLog, it->lastModificationLog);
        currentRow.push_back(it->comment);
Daniele Kruse's avatar
Daniele Kruse committed
763
764
        responseTable.push_back(currentRow);
      }
765
      cmdlineOutput << formatResponse(responseTable, hasOption("-h", "--header"));
Daniele Kruse's avatar
Daniele Kruse committed
766
767
768