LabelSession.cpp 17.7 KB
Newer Older
Daniele Kruse's avatar
Daniele Kruse committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/******************************************************************************
 *
 * 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.
 *
 * 
 *
21
 * @author Castor Dev team, castor-dev@cern.ch
Daniele Kruse's avatar
Daniele Kruse committed
22
23
 *****************************************************************************/

Victor Kotlyar's avatar
Victor Kotlyar committed
24
#include "common/log/LogContext.hpp"
25
#include "common/threading/System.hpp"
Steven Murray's avatar
Steven Murray committed
26
#include "castor/tape/tapeserver/daemon/LabelSession.hpp"
27
#include "castor/tape/tapeserver/daemon/LabelSessionConfig.hpp"
28
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
29
#include "castor/tape/tapeserver/file/File.hpp"
Steven Murray's avatar
Steven Murray committed
30
#include "castor/tape/tapeserver/file/Structures.hpp"
31
#include "castor/tape/tapeserver/SCSI/Device.hpp"
32
#include "common/exception/Exception.hpp"
Daniele Kruse's avatar
Daniele Kruse committed
33

34
#include <memory>
Daniele Kruse's avatar
Daniele Kruse committed
35

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

63
64
65
//------------------------------------------------------------------------------
// execute
//------------------------------------------------------------------------------
66
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
67
68
69
  castor::tape::tapeserver::daemon::LabelSession::execute() throw() {
  std::string errorMessage;

70
  try {
71
    return exceptionThrowingExecute();
72
  } catch(cta::exception::Exception &ex) {
73
74
75
76
77
78
    errorMessage = ex.getMessage().str();
  } catch(std::exception &se) {
    errorMessage = se.what();
  } catch(...) {
    errorMessage = "Caught an unknown exception";
  }
79

80
81
  // Reaching this point means the label session failed and an exception was
  // thrown
Victor Kotlyar's avatar
Victor Kotlyar committed
82
83
84
85
86
87
88
89
90
91
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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);
92

93
94
  // Send details of exception to tapeserverd and then re-throw
  m_tapeserver.labelError(m_request.drive, errorMessage);
95

96
97
98
99
100
101
102
  return MARK_DRIVE_AS_DOWN;
}

//------------------------------------------------------------------------------
// exceptionThrowingExecute
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
103
104
105
106
107
108
109
110
  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
111
112
113
114
115
116
117
118
119
    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));
    params.push_back(cta::log::Param("TPVID", m_request.vid));
    params.push_back(cta::log::Param("unitName", m_request.drive));
    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 "
120
121
      "is not set", params);
  }
122
  setProcessCapabilities("cap_sys_rawio+ep");
123
   
124
  std::unique_ptr<drive::DriveInterface> drivePtr = createDrive();
125
126
  drive::DriveInterface &drive = *drivePtr.get();

127
128
129
  if(m_lbp) {
    // only crc32c lbp mode is supported
    drive.enableCRC32CLogicalBlockProtectionReadWrite();
130
131
  } else {
    drive.disableLogicalBlockProtection();
132
  }
133
134
135
136

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

137
  mountTape();
138
  waitUntilTapeLoaded(drive, 60); // 60 = 60 seconds
139
140
  
  if(drive.isWriteProtected()) {
141
    const std::string message = "Cannot label the tape because it is write-protected";
142
    notifyTapeserverOfUserError(message);
143
  }
144
145
146
147
148
149
150
151
152
153
154
  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 {
155
156
157
158
159
        if (m_lbp) {
          writeLabelWithLbpToTape(drive);
        } else {
          writeLabelToTape(drive);
        }
160
161
    }
  }
162
163
  unloadTape(m_request.vid, drive);
  dismountTape(m_request.vid);
164
  drive.disableLogicalBlockProtection();
165
166
167
168
169
170
171
172
173

  return MARK_DRIVE_AS_UP;
}

//------------------------------------------------------------------------------
// setProcessCapabilities
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::setProcessCapabilities(
  const std::string &capabilities) {
Victor Kotlyar's avatar
Victor Kotlyar committed
174
175
176
177
178
179
180
181
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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)));
182
183

  m_capUtils.setProcText(capabilities);
Victor Kotlyar's avatar
Victor Kotlyar committed
184
185
  params.push_back(cta::log::Param("capabilities", m_capUtils.getProcText()));
  m_log(cta::log::INFO, "Label session set process capabilities", params);
186
187
}

Daniele Kruse's avatar
Daniele Kruse committed
188
//------------------------------------------------------------------------------
189
// createDrive
Daniele Kruse's avatar
Daniele Kruse committed
190
//------------------------------------------------------------------------------
191
std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface>
192
193
  castor::tape::tapeserver::daemon::LabelSession::createDrive() {
  SCSI::DeviceVector dv(m_sysWrapper);    
194
  SCSI::DeviceInfo driveInfo = dv.findBySymlink(m_driveConfig.devFilename);
Daniele Kruse's avatar
Daniele Kruse committed
195
  
196
  // Instantiate the drive object
197
  std::unique_ptr<drive::DriveInterface>
198
    drive(drive::createDrive(driveInfo, m_sysWrapper));
199
200

  if(NULL == drive.get()) {
201
    cta::exception::Exception ex;
202
    ex.getMessage() << "Failed to instantiate drive object";
203
    throw ex;
204
  }
205
  
206
  return drive;
Daniele Kruse's avatar
Daniele Kruse committed
207
208
209
}

//------------------------------------------------------------------------------
210
// mountTape
Daniele Kruse's avatar
Daniele Kruse committed
211
//------------------------------------------------------------------------------
212
void castor::tape::tapeserver::daemon::LabelSession::mountTape() {
213
  const cta::mediachanger::LibrarySlot &librarySlot = m_driveConfig.librarySlot();
214

Victor Kotlyar's avatar
Victor Kotlyar committed
215
216
217
218
219
220
221
222
223
224
225
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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);
226
  m_mc.mountTapeReadWrite(m_request.vid, librarySlot);
227
  if(cta::mediachanger::TAPE_LIBRARY_TYPE_MANUAL == librarySlot.getLibraryType()) {
Victor Kotlyar's avatar
Victor Kotlyar committed
228
    m_log(cta::log::INFO, "Label session did not mounted tape because the media"
229
230
      " changer is manual", params);
  } else {
Victor Kotlyar's avatar
Victor Kotlyar committed
231
   m_log(cta::log::INFO, "Label session mounted tape", params);
232
  }
Daniele Kruse's avatar
Daniele Kruse committed
233
234
235
}

//------------------------------------------------------------------------------
236
// waitUntilTapeLoaded
Daniele Kruse's avatar
Daniele Kruse committed
237
//------------------------------------------------------------------------------
238
void castor::tape::tapeserver::daemon::LabelSession::waitUntilTapeLoaded(
239
  drive::DriveInterface &drive, const int timeoutSecond) { 
Victor Kotlyar's avatar
Victor Kotlyar committed
240
241
242
243
244
245
246
247
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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)));
248

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

260
261
262
263
264
//------------------------------------------------------------------------------
// rewindDrive
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::rewindDrive(
  drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
265
266
267
268
269
270
271
272
273
274
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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);
275
  drive.rewind();
Victor Kotlyar's avatar
Victor Kotlyar committed
276
  m_log(cta::log::INFO, "Label session successfully rewound tape", params);
277
278
279
280
281
282
283
}

//------------------------------------------------------------------------------
// notifyTapeserverOfUserError
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::
  notifyTapeserverOfUserError(const std::string message) {
Victor Kotlyar's avatar
Victor Kotlyar committed
284
285
286
287
288
289
290
291
292
293
294
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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);
295
296
297
298
299
300
301
302
  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
303
304
305
306
307
308
309
310
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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)));
311

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

320
321
322
323
324
//------------------------------------------------------------------------------
// writeLabelWithLbpToTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::writeLabelWithLbpToTape(
  drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
325
326
327
328
329
330
331
332
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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)));
333
334

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

342
343
344
345
346
//------------------------------------------------------------------------------
// unloadTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::unloadTape(
  const std::string &vid, drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
347
348
349
350
351
352
353
354
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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)));
355
356
357

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

  try {
Victor Kotlyar's avatar
Victor Kotlyar committed
366
    m_log(cta::log::INFO, "Label session unloading tape", params);
367
    drive.unloadTape();
Victor Kotlyar's avatar
Victor Kotlyar committed
368
    m_log(cta::log::INFO, "Label session unloaded tape", params);
369
370
  } catch (cta::exception::Exception &ne) {
    cta::exception::Exception ex;
371
372
373
374
375
376
377
378
379
380
381
    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) {
382
  const cta::mediachanger::LibrarySlot &librarySlot = m_driveConfig.librarySlot();
Victor Kotlyar's avatar
Victor Kotlyar committed
383
384
385
386
387
388
389
390
391
  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));
  params.push_back(cta::log::Param("TPVID", m_request.vid));
  params.push_back(cta::log::Param("unitName", m_request.drive));
  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()));
392
393

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

//------------------------------------------------------------------------------
413
// boolToStr
414
//------------------------------------------------------------------------------
415
416
417
const char *castor::tape::tapeserver::daemon::LabelSession::boolToStr(
  const bool value) {
  return value ? "true" : "false";
Daniele Kruse's avatar
Daniele Kruse committed
418
}