LabelSession.cpp 17.8 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
 *****************************************************************************/

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

37
#include <memory>
Daniele Kruse's avatar
Daniele Kruse committed
38

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

66
67
68
//------------------------------------------------------------------------------
// execute
//------------------------------------------------------------------------------
69
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
70
71
72
  castor::tape::tapeserver::daemon::LabelSession::execute() throw() {
  std::string errorMessage;

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

83
84
  // Reaching this point means the label session failed and an exception was
  // thrown
Victor Kotlyar's avatar
Victor Kotlyar committed
85
86
87
88
89
90
91
92
93
94
  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);
95

96
97
  // Send details of exception to tapeserverd and then re-throw
  m_tapeserver.labelError(m_request.drive, errorMessage);
98

99
100
101
102
103
104
105
  return MARK_DRIVE_AS_DOWN;
}

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

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

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

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

  return MARK_DRIVE_AS_UP;
}

//------------------------------------------------------------------------------
// setProcessCapabilities
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::setProcessCapabilities(
  const std::string &capabilities) {
Victor Kotlyar's avatar
Victor Kotlyar committed
177
178
179
180
181
182
183
184
  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)));
185
186

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

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

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

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

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

//------------------------------------------------------------------------------
239
// waitUntilTapeLoaded
Daniele Kruse's avatar
Daniele Kruse committed
240
//------------------------------------------------------------------------------
241
void castor::tape::tapeserver::daemon::LabelSession::waitUntilTapeLoaded(
242
  drive::DriveInterface &drive, const int timeoutSecond) { 
Victor Kotlyar's avatar
Victor Kotlyar committed
243
244
245
246
247
248
249
250
  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)));
251

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

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

//------------------------------------------------------------------------------
// notifyTapeserverOfUserError
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::
  notifyTapeserverOfUserError(const std::string message) {
Victor Kotlyar's avatar
Victor Kotlyar committed
287
288
289
290
291
292
293
294
295
296
297
  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);
298
299
300
301
302
303
304
305
  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
306
307
308
309
310
311
312
313
  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)));
314

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

323
324
325
326
327
//------------------------------------------------------------------------------
// writeLabelWithLbpToTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::writeLabelWithLbpToTape(
  drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
328
329
330
331
332
333
334
335
  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)));
336
337

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

345
346
347
348
349
//------------------------------------------------------------------------------
// unloadTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::LabelSession::unloadTape(
  const std::string &vid, drive::DriveInterface &drive) {
Victor Kotlyar's avatar
Victor Kotlyar committed
350
351
352
353
354
355
356
357
  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)));
358
359
360

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

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

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

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