LabelSession.cpp 17.6 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
  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 DriveConfig &driveConfig,
50
51
52
  const bool force,
  const bool lbp,
  const LabelSessionConfig &labelSessionConfig):
53
  m_capUtils(capUtils),
54
  m_tapeserver(tapeserver),
55
  m_mc(mc),
56
  m_request(clientRequest),
57
  m_log(log),
58
  m_sysWrapper(sysWrapper),
59
  m_driveConfig(driveConfig),
60
61
62
  m_labelSessionConfig (labelSessionConfig),
  m_force(force),
  m_lbp(lbp){
63
}
Daniele Kruse's avatar
Daniele Kruse committed
64

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

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

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

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

98
99
100
101
102
103
104
  return MARK_DRIVE_AS_DOWN;
}

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

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

  return MARK_DRIVE_AS_UP;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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