CleanerSession.cpp 10.5 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/******************************************************************************
 *
 * 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.
 *
 * 
 *
 * @author Castor Dev team, castor-dev@cern.ch
 *****************************************************************************/

#include "castor/tape/tapeserver/daemon/CleanerSession.hpp"

//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::CleanerSession::CleanerSession(
30
  server::ProcessCap &capUtils,
31
  mediachanger::MediaChangerFacade &mc,
32
33
  castor::log::Logger &log,
  const utils::DriveConfig &driveConfig,
34
  System::virtualWrapper &sysWrapper,
35
36
  const std::string &vid,
  const uint32_t driveReadyDelayInSeconds):
37
  m_capUtils(capUtils),
38
  m_mc(mc),
39
40
  m_log(log),
  m_driveConfig(driveConfig),
41
  m_sysWrapper(sysWrapper),
42
43
  m_vid(vid),
  m_driveReadyDelayInSeconds(driveReadyDelayInSeconds) {
44
45
46
}

//------------------------------------------------------------------------------
47
// execute
48
//------------------------------------------------------------------------------
49
50
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::CleanerSession::execute() {
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  std::string errorMessage;

  try {
    return exceptionThrowingExecute();
  } catch(castor::exception::Exception &ex) {
    errorMessage = ex.getMessage().str();
  } catch(std::exception &se) {
    errorMessage = se.what();
  } catch(...) {
    errorMessage = "Caught an unknown exception";
  }

  // Reaching this point means the cleaner failed and an exception was thrown
  log::Param params[] = {
    log::Param("TPVID", m_vid),
    log::Param("unitName", m_driveConfig.unitName),
    log::Param("message", errorMessage)};
  m_log(LOG_ERR, "Cleaner failed", params);
  return MARK_DRIVE_AS_DOWN;
}

//------------------------------------------------------------------------------
// exceptionThrowingExecute
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::CleanerSession::exceptionThrowingExecute() {
  std::list<log::Param> params;
  params.push_back(log::Param("TPVID", m_vid));
  params.push_back(log::Param("unitName", m_driveConfig.unitName));

  setProcessCapabilities("cap_sys_rawio+ep");

  std::auto_ptr<tapeserver::drive::DriveInterface> drive(createDrive());

  waitUntilDriveIsReady(drive.get());

  if(!drive->hasTapeInPlace()) {
    m_log(LOG_INFO, "Cleaner found tape drive empty", params);
    return MARK_DRIVE_AS_UP;
  }

  rewindDrive(drive.get());

  checkTapeContainsData(drive.get());

  const std::string volumeLabelVSN = checkVolumeLabel(drive.get());

  unloadTape(volumeLabelVSN, drive.get());

  dismountTape(volumeLabelVSN);

  return MARK_DRIVE_AS_UP;
}

//------------------------------------------------------------------------------
// setProcessCapabilities
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CleanerSession::setProcessCapabilities(
  const std::string &capabilities) {
  m_capUtils.setProcText(capabilities);
111
112
113
  {
    log::Param params[] = {
      log::Param("capabilities", m_capUtils.getProcText())};
114
    m_log(LOG_INFO, "Cleaner set process capabilities for using tape",
115
116
      params);
  }
117
}
118

119
120
121
122
123
124
125
126
127
//------------------------------------------------------------------------------
// createDrive
//------------------------------------------------------------------------------
castor::tape::tapeserver::drive::DriveInterface *
  castor::tape::tapeserver::daemon::CleanerSession::createDrive() {
  SCSI::DeviceVector dv(m_sysWrapper);    
  SCSI::DeviceInfo driveInfo = dv.findBySymlink(m_driveConfig.devFilename);
  drive::DriveInterface *const drive = drive::createDrive(driveInfo,
    m_sysWrapper);
128

129
  if(NULL == drive) {
130
131
    castor::exception::Exception ex;
    ex.getMessage() <<
132
      "Failed to instantiate drive object";
133
134
    throw ex;
  }
135
136
137
138
139
140
141
142
143

  return drive;
}

//------------------------------------------------------------------------------
// waitUntilDriveIsReady
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CleanerSession::waitUntilDriveIsReady(
  drive::DriveInterface *const drive) {
144
  if(0 != m_driveReadyDelayInSeconds) {
145
146
147
148
149
150
    std::list<log::Param> params;
    params.push_back(log::Param("TPVID", m_vid));
    params.push_back(log::Param("unitName", m_driveConfig.unitName));
    params.push_back(log::Param("driveReadyDelayInSeconds",
      m_driveReadyDelayInSeconds));

151
    try {
152
      m_log(LOG_INFO, "Cleaner waiting for drive to be ready", params);
153
      drive->waitUntilReady(m_driveReadyDelayInSeconds);
154
      m_log(LOG_INFO, "Cleaner detected drive is ready", params);
155
    } catch (castor::exception::Exception &ex) {
156
157
158
      params.push_back(log::Param("message", ex.getMessage().str()));
      m_log(LOG_INFO, "Cleaner caught non-fatal exception whilst waiting for"
        " drive to become ready", params);
159
    }
160
  }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
}

//------------------------------------------------------------------------------
// rewindDrive
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CleanerSession::rewindDrive(
  drive::DriveInterface *const drive) {
  std::list<log::Param> params;
  params.push_back(log::Param("TPVID", m_vid));
  params.push_back(log::Param("unitName", m_driveConfig.unitName));

  m_log(LOG_INFO, "Cleaner rewinding drive", params);
  drive->rewind();
  m_log(LOG_INFO, "Cleaner successfully rewound drive", params);
}

//------------------------------------------------------------------------------
// checkTapeContainsData
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CleanerSession::checkTapeContainsData(
  drive::DriveInterface *const drive) {
  std::list<log::Param> params;
  params.push_back(log::Param("TPVID", m_vid));
  params.push_back(log::Param("unitName", m_driveConfig.unitName));

  m_log(LOG_INFO, "Cleaner checking tape contains data", params);
  if(drive->isTapeBlank()) {
    castor::exception::Exception ex;
    ex.getMessage() << "Tape is completely blank when it should be labeled";
    throw ex;
  }
  m_log(LOG_INFO, "Cleaner successfully detected tape contains data", params);
}

//------------------------------------------------------------------------------
// checkVolumeLabel
//------------------------------------------------------------------------------
std::string castor::tape::tapeserver::daemon::CleanerSession::checkVolumeLabel(
  drive::DriveInterface *const drive) {
  tapeFile::VOL1 vol1;
  std::list<log::Param> params;
  params.push_back(log::Param("TPVID", m_vid));
  params.push_back(log::Param("unitName", m_driveConfig.unitName));
204
  
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  try {
    drive->readExactBlock((void * )&vol1, sizeof(vol1),
      "[CleanerSession::clean()] - Reading header VOL1");
    vol1.verify();

    const std::string &volumeLabelVSN = vol1.getVSN();
    params.push_back(log::Param("volumeLabelVSN", volumeLabelVSN));

    m_log(LOG_INFO, "Cleaner read VSN from volume label", params);

    // If the cleaner was given a VID
    if(!m_vid.empty()) {
      if(m_vid == volumeLabelVSN) {
        m_log(LOG_INFO, "Cleaner detected volume label contains expected VSN",
          params);
220
      } else {
221
222
        m_log(LOG_WARNING,
          "Cleaner detected volume label does not contain expected VSN", params);
223
      }
224
    }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281

    return volumeLabelVSN;
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Failed to check volume label: " << ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// unloadTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CleanerSession::unloadTape(
  const std::string &vid, drive::DriveInterface *const drive) {
  std::list<log::Param> params;
  params.push_back(log::Param("TPVID", vid));
  params.push_back(log::Param("unitName", m_driveConfig.unitName));

  // We implement the same policy as with the tape sessions: 
  // if the librarySlot parameter is "manual", do nothing.
  if(mediachanger::TAPE_LIBRARY_TYPE_MANUAL ==
    m_driveConfig.librarySlot.getLibraryType()) {
    m_log(LOG_INFO, "Cleaner not unloading tape because media changer is"
      " manual", params);
    return;
  }

  try {
    m_log(LOG_INFO, "Cleaner unloading tape", params);
    drive->unloadTape();
    m_log(LOG_INFO, "Cleaner unloaded tape", params);
  } catch (castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Cleaner failed to unload tape: " <<
      ne.getMessage().str();
    throw ex;
  }
}

//------------------------------------------------------------------------------
// dismountTape
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CleanerSession::dismountTape(
  const std::string &vid) {
  std::list<log::Param> params;
  params.push_back(log::Param("TPVID", vid));
  params.push_back(log::Param("unitName", m_driveConfig.unitName));

  try {
    m_mc.dismountTape(vid, m_driveConfig.librarySlot.str());
    const bool dismountWasManual = mediachanger::TAPE_LIBRARY_TYPE_MANUAL ==
      m_driveConfig.librarySlot.getLibraryType();
    if(dismountWasManual) {
      m_log(LOG_INFO, "Cleaner did not dismount tape because media changer is"
        " manual", params);
    } else {
      m_log(LOG_INFO, "Cleaner dismounted tape", params);
282
    }
283
284
285
286
287
  } catch(castor::exception::Exception &ne) {
    castor::exception::Exception ex;
    ex.getMessage() << "Cleaner failed to dismount tape: " <<
      ne.getMessage().str();
    throw ex;
288
289
  }
}