LabelSession.cpp 17.6 KB
Newer Older
1
2
3
4
5
6
7
/*
 * @project        The CERN Tape Archive (CTA)
 * @copyright      Copyright(C) 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.
Daniele Kruse's avatar
Daniele Kruse committed
8
 *
9
10
11
12
 *                 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.
Daniele Kruse's avatar
Daniele Kruse committed
13
 *
14
15
16
 *                 You should have received a copy of the GNU General Public License
 *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
Daniele Kruse's avatar
Daniele Kruse committed
17

Victor Kotlyar's avatar
Victor Kotlyar committed
18
#include "common/log/LogContext.hpp"
19
#include "common/threading/System.hpp"
Steven Murray's avatar
Steven Murray committed
20
#include "castor/tape/tapeserver/daemon/LabelSession.hpp"
21
#include "castor/tape/tapeserver/daemon/LabelSessionConfig.hpp"
22
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
23
#include "castor/tape/tapeserver/file/File.hpp"
Steven Murray's avatar
Steven Murray committed
24
#include "castor/tape/tapeserver/file/Structures.hpp"
25
#include "castor/tape/tapeserver/SCSI/Device.hpp"
26
#include "common/exception/Exception.hpp"
Daniele Kruse's avatar
Daniele Kruse committed
27

28
#include <memory>
Daniele Kruse's avatar
Daniele Kruse committed
29

30
31
32
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
Daniele Kruse's avatar
Daniele Kruse committed
33
castor::tape::tapeserver::daemon::LabelSession::LabelSession(
34
  cta::server::ProcessCap &capUtils,
35
  cta::tape::daemon::TapedProxy &tapeserver,
36
  cta::mediachanger::MediaChangerFacade &mc, 
Daniele Kruse's avatar
Daniele Kruse committed
37
  const legacymsg::TapeLabelRqstMsgBody &clientRequest,
Victor Kotlyar's avatar
Victor Kotlyar committed
38
  cta::log::Logger &log,
39
  System::virtualWrapper &sysWrapper,
40
  const cta::tape::daemon::TpconfigLine &driveConfig,
41
42
  const bool force,
  const bool lbp,
43
44
  const LabelSessionConfig &labelSessionConfig,
  const std::string & externalEncryptionKeyScript):
45
  m_capUtils(capUtils),
46
  m_tapeserver(tapeserver),
47
  m_mc(mc),
48
  m_request(clientRequest),
49
  m_log(log),
50
  m_sysWrapper(sysWrapper),
51
  m_driveConfig(driveConfig),
52
53
  m_labelSessionConfig (labelSessionConfig),
  m_force(force),
54
55
  m_lbp(lbp),
  m_encryptionControl(externalEncryptionKeyScript) {}
Daniele Kruse's avatar
Daniele Kruse committed
56

57
58
59
//------------------------------------------------------------------------------
// execute
//------------------------------------------------------------------------------
60
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
61
62
63
  castor::tape::tapeserver::daemon::LabelSession::execute() throw() {
  std::string errorMessage;

64
  try {
65
    return exceptionThrowingExecute();
66
  } catch(cta::exception::Exception &ex) {
67
68
69
70
71
72
    errorMessage = ex.getMessage().str();
  } catch(std::exception &se) {
    errorMessage = se.what();
  } catch(...) {
    errorMessage = "Caught an unknown exception";
  }
73

74
75
  // Reaching this point means the label session failed and an exception was
  // thrown
Victor Kotlyar's avatar
Victor Kotlyar committed
76
77
78
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
79
80
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
81
82
83
84
85
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
  params.push_back(cta::log::Param("message", errorMessage));
  m_log(cta::log::ERR, "Label session failed", params);
86

87
88
  // Send details of exception to tapeserverd and then re-throw
  m_tapeserver.labelError(m_request.drive, errorMessage);
89

90
91
92
93
94
95
96
  return MARK_DRIVE_AS_DOWN;
}

//------------------------------------------------------------------------------
// exceptionThrowingExecute
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
97
98
99
100
101
102
103
104
  castor::tape::tapeserver::daemon::LabelSession::exceptionThrowingExecute() { 
  if (!m_labelSessionConfig.useLbp && m_lbp) {
    const std::string message = "Tapeserver configuration does not allow label "
    "a tape with logical block protection.";
    notifyTapeserverOfUserError(message);
    return MARK_DRIVE_AS_UP;
  }
  if (!m_lbp && m_labelSessionConfig.useLbp) {
Victor Kotlyar's avatar
Victor Kotlyar committed
105
106
107
    std::list<cta::log::Param> params;
    params.push_back(cta::log::Param("uid", m_request.uid));
    params.push_back(cta::log::Param("gid", m_request.gid));
108
109
    params.push_back(cta::log::Param("tapeVid", m_request.vid));
    params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
110
111
112
113
    params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
    params.push_back(cta::log::Param("force", boolToStr(m_force)));
    params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
    m_log(cta::log::WARNING, "Label session configured to use LBP but lbp parameter "
114
115
      "is not set", params);
  }
116
  setProcessCapabilities("cap_sys_rawio+ep");
117
   
118
  std::unique_ptr<drive::DriveInterface> drivePtr = createDrive();
119
120
  drive::DriveInterface &drive = *drivePtr.get();

121
122
123
  if(m_lbp) {
    // only crc32c lbp mode is supported
    drive.enableCRC32CLogicalBlockProtectionReadWrite();
124
125
  } else {
    drive.disableLogicalBlockProtection();
126
  }
127
128
129
130

  // The label to be written without encryption
  m_encryptionControl.disable(drive);

131
  mountTape();
132
  waitUntilTapeLoaded(drive, 60); // 60 = 60 seconds
133
134
  
  if(drive.isWriteProtected()) {
135
    const std::string message = "Cannot label the tape because it is write-protected";
136
    notifyTapeserverOfUserError(message);
137
  }
138
139
140
141
142
143
144
145
146
147
148
  else {
    rewindDrive(drive);

    // If the user is trying to label a non-empty tape without the force option
    if(!m_force && !drive.isTapeBlank()) {
      const std::string message = "Cannot label a non-empty tape without the"
        " force option";
      notifyTapeserverOfUserError(message);

    // Else the labeling can go ahead
    } else {
149
150
151
152
153
        if (m_lbp) {
          writeLabelWithLbpToTape(drive);
        } else {
          writeLabelToTape(drive);
        }
154
155
    }
  }
156
157
  unloadTape(m_request.vid, drive);
  dismountTape(m_request.vid);
158
  drive.disableLogicalBlockProtection();
159
160
161
162
163
164
165
166
167

  return MARK_DRIVE_AS_UP;
}

//------------------------------------------------------------------------------
// setProcessCapabilities
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::setProcessCapabilities(
  const std::string &capabilities) {
Victor Kotlyar's avatar
Victor Kotlyar committed
168
169
170
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
171
172
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
173
174
175
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
176
177

  m_capUtils.setProcText(capabilities);
Victor Kotlyar's avatar
Victor Kotlyar committed
178
179
  params.push_back(cta::log::Param("capabilities", m_capUtils.getProcText()));
  m_log(cta::log::INFO, "Label session set process capabilities", params);
180
181
}

Daniele Kruse's avatar
Daniele Kruse committed
182
//------------------------------------------------------------------------------
183
// createDrive
Daniele Kruse's avatar
Daniele Kruse committed
184
//------------------------------------------------------------------------------
185
std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface>
186
187
  castor::tape::tapeserver::daemon::LabelSession::createDrive() {
  SCSI::DeviceVector dv(m_sysWrapper);    
188
  SCSI::DeviceInfo driveInfo = dv.findBySymlink(m_driveConfig.devFilename);
Daniele Kruse's avatar
Daniele Kruse committed
189
  
190
  // Instantiate the drive object
191
  std::unique_ptr<drive::DriveInterface>
192
    drive(drive::createDrive(driveInfo, m_sysWrapper));
193
194

  if(NULL == drive.get()) {
195
    cta::exception::Exception ex;
196
    ex.getMessage() << "Failed to instantiate drive object";
197
    throw ex;
198
  }
199
  
200
  return drive;
Daniele Kruse's avatar
Daniele Kruse committed
201
202
203
}

//------------------------------------------------------------------------------
204
// mountTape
Daniele Kruse's avatar
Daniele Kruse committed
205
//------------------------------------------------------------------------------
206
void castor::tape::tapeserver::daemon::LabelSession::mountTape() {
207
  const cta::mediachanger::LibrarySlot &librarySlot = m_driveConfig.librarySlot();
208

Victor Kotlyar's avatar
Victor Kotlyar committed
209
210
211
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
212
213
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
214
215
216
217
218
219
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
  params.push_back(cta::log::Param("librarySlot", librarySlot.str()));

  m_log(cta::log::INFO, "Label session mounting tape", params);
220
  m_mc.mountTapeReadWrite(m_request.vid, librarySlot);
221
  if(cta::mediachanger::TAPE_LIBRARY_TYPE_MANUAL == librarySlot.getLibraryType()) {
Victor Kotlyar's avatar
Victor Kotlyar committed
222
    m_log(cta::log::INFO, "Label session did not mounted tape because the media"
223
224
      " changer is manual", params);
  } else {
Victor Kotlyar's avatar
Victor Kotlyar committed
225
   m_log(cta::log::INFO, "Label session mounted tape", params);
226
  }
Daniele Kruse's avatar
Daniele Kruse committed
227
228
229
}

//------------------------------------------------------------------------------
230
// waitUntilTapeLoaded
Daniele Kruse's avatar
Daniele Kruse committed
231
//------------------------------------------------------------------------------
232
void castor::tape::tapeserver::daemon::LabelSession::waitUntilTapeLoaded(
233
  drive::DriveInterface &drive, const int timeoutSecond) { 
Victor Kotlyar's avatar
Victor Kotlyar committed
234
235
236
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
237
238
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
239
240
241
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
242

243
  try {
244
    drive.waitUntilReady(timeoutSecond);
Victor Kotlyar's avatar
Victor Kotlyar committed
245
    m_log(cta::log::INFO, "Label session loaded tape", params);
246
247
  } catch(cta::exception::Exception &ne) {
    cta::exception::Exception ex;
248
249
250
251
    ex.getMessage() << "Failed to wait for tape to be loaded: " <<
      ne.getMessage().str();
    throw ex;
  }
Daniele Kruse's avatar
Daniele Kruse committed
252
}
253

254
255
256
257
258
//------------------------------------------------------------------------------
// rewindDrive
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::rewindDrive(
  drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
259
260
261
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
262
263
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
264
265
266
267
268
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));

  m_log(cta::log::INFO, "Label session rewinding tape", params);
269
  drive.rewind();
Victor Kotlyar's avatar
Victor Kotlyar committed
270
  m_log(cta::log::INFO, "Label session successfully rewound tape", params);
271
272
273
274
275
276
277
}

//------------------------------------------------------------------------------
// notifyTapeserverOfUserError
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::
  notifyTapeserverOfUserError(const std::string message) {
Victor Kotlyar's avatar
Victor Kotlyar committed
278
279
280
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
281
282
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
283
284
285
286
287
288
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
  params.push_back(cta::log::Param("message", message));

  m_log(cta::log::ERR, "Label session encountered user error", params);
289
290
291
292
293
294
295
296
  m_tapeserver.labelError(m_request.drive, message);
}

//------------------------------------------------------------------------------
// writeLabelToTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::writeLabelToTape(
  drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
297
298
299
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
300
301
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
302
303
304
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
305

306
  if(m_lbp) {
Victor Kotlyar's avatar
Victor Kotlyar committed
307
    m_log(cta::log::WARNING, "LBP mode mismatch. Force labeling without lbp.", params);
308
  }
Victor Kotlyar's avatar
Victor Kotlyar committed
309
  m_log(cta::log::INFO, "Label session is writing label to tape", params);
310
  tapeFile::LabelSession ls(drive, m_request.vid, false);
Victor Kotlyar's avatar
Victor Kotlyar committed
311
  m_log(cta::log::INFO, "Label session has written label to tape", params);
312
313
}

314
315
316
317
318
//------------------------------------------------------------------------------
// writeLabelWithLbpToTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::writeLabelWithLbpToTape(
  drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
319
320
321
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
322
323
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
324
325
326
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
327
328

  if(!m_lbp) {
Victor Kotlyar's avatar
Victor Kotlyar committed
329
    m_log(cta::log::WARNING, "LBP mode mismatch. Force labeling with lbp.", params);
330
  }
Victor Kotlyar's avatar
Victor Kotlyar committed
331
  m_log(cta::log::INFO, "Label session is writing label with LBP to tape", params);
332
  tapeFile::LabelSession ls(drive, m_request.vid, true);
Victor Kotlyar's avatar
Victor Kotlyar committed
333
  m_log(cta::log::INFO, "Label session has written label with LBP to tape", params);
334
335
}

336
337
338
339
340
//------------------------------------------------------------------------------
// unloadTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::unloadTape(
  const std::string &vid, drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
341
342
343
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
344
345
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
346
347
348
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
349
350
351

  // We implement the same policy as with the tape sessions: 
  // if the librarySlot parameter is "manual", do nothing.
352
  if(cta::mediachanger::TAPE_LIBRARY_TYPE_MANUAL ==
353
    m_driveConfig.librarySlot().getLibraryType()) {
Victor Kotlyar's avatar
Victor Kotlyar committed
354
    m_log(cta::log::INFO, "Label session not unloading tape because media changer is"
355
356
357
358
359
      " manual", params);
    return;
  }

  try {
Victor Kotlyar's avatar
Victor Kotlyar committed
360
    m_log(cta::log::INFO, "Label session unloading tape", params);
361
    drive.unloadTape();
Victor Kotlyar's avatar
Victor Kotlyar committed
362
    m_log(cta::log::INFO, "Label session unloaded tape", params);
363
364
  } catch (cta::exception::Exception &ne) {
    cta::exception::Exception ex;
365
366
367
368
369
370
371
372
373
374
375
    ex.getMessage() << "Label session failed to unload tape: " <<
      ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// dismountTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::dismountTape(
  const std::string &vid) {
376
  const cta::mediachanger::LibrarySlot &librarySlot = m_driveConfig.librarySlot();
Victor Kotlyar's avatar
Victor Kotlyar committed
377
378
379
  std::list<cta::log::Param> params;
  params.push_back(cta::log::Param("uid", m_request.uid));
  params.push_back(cta::log::Param("gid", m_request.gid));
380
381
  params.push_back(cta::log::Param("tapeVid", m_request.vid));
  params.push_back(cta::log::Param("tapeDrive", m_request.drive));
Victor Kotlyar's avatar
Victor Kotlyar committed
382
383
384
385
  params.push_back(cta::log::Param("logicalLibrary", m_request.logicalLibrary));
  params.push_back(cta::log::Param("force", boolToStr(m_force)));
  params.push_back(cta::log::Param("lbp", boolToStr(m_lbp)));
  params.push_back(cta::log::Param("librarySlot", librarySlot.str()));
386
387

  try {
Victor Kotlyar's avatar
Victor Kotlyar committed
388
    m_log(cta::log::INFO, "Label session dismounting tape", params);
389
    m_mc.dismountTape(vid, librarySlot);
390
    const bool dismountWasManual = cta::mediachanger::TAPE_LIBRARY_TYPE_MANUAL ==
391
      librarySlot.getLibraryType();
392
    if(dismountWasManual) {
Victor Kotlyar's avatar
Victor Kotlyar committed
393
      m_log(cta::log::INFO, "Label session did not dismount tape because media"
394
395
        " changer is manual", params);
    } else {
Victor Kotlyar's avatar
Victor Kotlyar committed
396
      m_log(cta::log::INFO, "Label session dismounted tape", params);
397
    }
398
399
  } catch(cta::exception::Exception &ne) {
    cta::exception::Exception ex;
400
401
402
403
    ex.getMessage() << "Label session failed to dismount tape: " <<
      ne.getMessage().str();
    throw ex;
  }
404
405
406
}

//------------------------------------------------------------------------------
407
// boolToStr
408
//------------------------------------------------------------------------------
409
410
411
const char *castor::tape::tapeserver::daemon::LabelSession::boolToStr(
  const bool value) {
  return value ? "true" : "false";
Daniele Kruse's avatar
Daniele Kruse committed
412
}