// ----------------------------------------------------------------------
// File: TapeRestApiBusiness.cc
// Author: Cedric Caffy - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2013 CERN/Switzerland *
* *
* 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. *
* *
* 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, see .*
************************************************************************/
#include "mgm/http/rest-api/exception/ObjectNotFoundException.hh"
#include "TapeRestApiBusiness.hh"
#include "mgm/http/rest-api/model/tape/common/FilesContainer.hh"
#include "mgm/bulk-request/utils/PrepareArgumentsWrapper.hh"
#include "mgm/bulk-request/interface/RealMgmFileSystemInterface.hh"
#include "mgm/bulk-request/prepare/manager/BulkRequestPrepareManager.hh"
#include "mgm/bulk-request/business/BulkRequestBusiness.hh"
#include "mgm/bulk-request/dao/factories/ProcDirectoryDAOFactory.hh"
#include "mgm/http/rest-api/exception/tape/TapeRestApiBusinessException.hh"
#include "mgm/http/rest-api/exception/tape/FileDoesNotBelongToBulkRequestException.hh"
#include "mgm/http/rest-api/exception/ForbiddenException.hh"
#include "mgm/bulk-request/exception/PersistencyException.hh"
#include "mgm/Stat.hh"
EOSMGMRESTNAMESPACE_BEGIN
std::shared_ptr TapeRestApiBusiness::createStageBulkRequest(
const CreateStageBulkRequestModel* model, const common::VirtualIdentity* vid)
{
const FilesContainer& files = model->getFiles();
EXEC_TIMING_BEGIN("TapeRestApiBusiness::createStageBulkRequest");
gOFS->MgmStats.Add("TapeRestApiBusiness::createStageBulkRequest", vid->uid,
vid->gid, 1);
bulk::PrepareArgumentsWrapper pargsWrapper(
"fake_id", Prep_STAGE, files.getPaths(), files.getOpaqueInfos());
auto prepareManager = createBulkRequestPrepareManager();
XrdOucErrInfo error;
int prepareRetCode = prepareManager->prepare(
*pargsWrapper.getPrepareArguments(), error, vid);
if (prepareRetCode != SFS_DATA) {
throw TapeRestApiBusinessException(error.getErrText());
}
EXEC_TIMING_END("TapeRestApiBusiness::createStageBulkRequest");
return prepareManager->getBulkRequest();
}
void TapeRestApiBusiness::cancelStageBulkRequest(const std::string& requestId,
const PathsModel* model, const common::VirtualIdentity* vid)
{
EXEC_TIMING_BEGIN("TapeRestApiBusiness::cancelStageBulkRequest");
gOFS->MgmStats.Add("TapeRestApiBusiness::cancelStageBulkRequest", vid->uid,
vid->gid, 1);
std::shared_ptr bulkRequestBusiness =
createBulkRequestBusiness();
auto bulkRequest = bulkRequestBusiness->getStageBulkRequest(requestId);
if (bulkRequest == nullptr) {
std::stringstream ss;
ss << "Unable to find the STAGE bulk-request ID = " << requestId;
throw ObjectNotFoundException(ss.str());
}
//First, check if the issuer of the cancellation is root, or is the person who submitted the stage request
//checkIssuerAuthorizedToAccessStageBulkRequest(bulkRequest.get(), vid,"cancel");
//Create the prepare arguments, we will only cancel the files that were given by the user
const FilesContainer& filesFromClient = model->getFiles();
auto filesFromBulkRequestContainer = bulkRequest->getFilesMap();
bulk::PrepareArgumentsWrapper pargsWrapper(requestId, Prep_CANCEL);
for (const auto& fileFromClient : filesFromClient.getPaths()) {
const auto& fileFromBulkRequestKeyVal = filesFromBulkRequestContainer->find(
fileFromClient);
if (fileFromBulkRequestKeyVal != filesFromBulkRequestContainer->end()) {
auto& fileFromBulkRequest = fileFromBulkRequestKeyVal->second;
auto& error = fileFromBulkRequest->getError();
if (!error) {
//We only cancel the files that do not have any error
pargsWrapper.addFile(fileFromClient, "");
}
} else {
std::stringstream ss;
ss << "The file " << fileFromClient << " does not belong to the STAGE request "
<< bulkRequest->getId() << ". No modification has been made to this request.";
throw FileDoesNotBelongToBulkRequestException(ss.str());
}
}
//Do the cancellation if there are files to cancel
if (pargsWrapper.getNbFiles() != 0) {
auto pm = createBulkRequestPrepareManager();
XrdOucErrInfo error;
int retCancellation = pm->prepare(*pargsWrapper.getPrepareArguments(), error,
vid);
if (retCancellation != SFS_OK) {
std::stringstream ss;
ss << "Unable to cancel the files provided. errMsg=\""
<< error.getErrText() << "\"";
throw TapeRestApiBusinessException(ss.str());
}
}
EXEC_TIMING_END("TapeRestApiBusiness::cancelStageBulkRequest");
}
std::shared_ptr
TapeRestApiBusiness::getStageBulkRequest(const std::string& requestId,
const common::VirtualIdentity* vid)
{
EXEC_TIMING_BEGIN("TapeRestApiBusiness::getStageBulkRequest");
gOFS->MgmStats.Add("TapeRestApiBusiness::getStageBulkRequest", vid->uid,
vid->gid, 1);
std::shared_ptr ret =
std::make_shared();
auto bulkRequestBusiness = createBulkRequestBusiness();
std::unique_ptr bulkRequest;
try {
bulkRequest = bulkRequestBusiness->getStageBulkRequest(requestId);
if (!bulkRequest) {
std::stringstream ss;
ss << "Unable to find the STAGE bulk-request ID =" << requestId;
throw ObjectNotFoundException(ss.str());
}
} catch (bulk::PersistencyException& ex) {
throw TapeRestApiBusinessException(ex.what());
}
//checkIssuerAuthorizedToAccessStageBulkRequest(bulkRequest.get(), vid,"get");
//Set bulk-request related attributes
ret->setCreationTime(bulkRequest->getCreationTime());
ret->setId(bulkRequest->getId());
//Instanciate prepare manager to get the tape, disk residency and an eventual error (set by CTA)
bulk::PrepareArgumentsWrapper pargsWrapper(requestId, Prep_QUERY);
auto files = bulkRequest->getFiles();
for (auto& file : *files) {
pargsWrapper.addFile(file->getPath(), "");
}
auto pm = createPrepareManager();
XrdOucErrInfo error;
auto queryPrepareResult = pm->queryPrepare(*pargsWrapper.getPrepareArguments(),
error, vid);
if (!queryPrepareResult->hasQueryPrepareFinished()) {
std::stringstream ss;
ss << "Unable to get information about the files belonging to the request " <<
requestId << ". errMsg=\"" << error.getErrText() << "\"";
throw TapeRestApiBusinessException(ss.str());
}
for (const auto& queryPrepareResponse :
queryPrepareResult->getResponse()->responses) {
auto& filesFromBulkRequest = bulkRequest->getFilesMap();
auto fileFromBulkRequestItor = filesFromBulkRequest->find(
queryPrepareResponse.path);
if (fileFromBulkRequestItor != filesFromBulkRequest->end()) {
auto& fileFromBulkRequest = fileFromBulkRequestItor->second;
std::unique_ptr item =
std::make_unique();
item->mPath = queryPrepareResponse.path;
if (fileFromBulkRequest->getError()) {
item->mError = *fileFromBulkRequest->getError();
} else if (!queryPrepareResponse.error_text.empty()) {
//Error comes from CTA, so we need to update the state of the file to ERROR
item->mError = queryPrepareResponse.error_text;
} else if (!queryPrepareResponse.is_online && !queryPrepareResponse.is_reqid_present) {
//If there is no request for the file, an error should be returned
item->mError = "File not requested with request ID " + requestId;
} else {
item->mError = "";
}
item->mOnDisk = queryPrepareResponse.is_online;
ret->addFile(std::move(item));
}
}
EXEC_TIMING_END("TapeRestApiBusiness::getStageBulkRequest");
return ret;
}
void TapeRestApiBusiness::deleteStageBulkRequest(const std::string& requestId,
const common::VirtualIdentity* vid)
{
EXEC_TIMING_BEGIN("TapeRestApiBusiness::deleteStageBulkRequest");
gOFS->MgmStats.Add("TapeRestApiBusiness::deleteStageBulkRequest", vid->uid,
vid->gid, 1);
//Get the prepare request from the persistency
std::shared_ptr bulkRequestBusiness =
createBulkRequestBusiness();
auto bulkRequest = bulkRequestBusiness->getStageBulkRequest(requestId);
if (bulkRequest == nullptr) {
std::stringstream ss;
ss << "Unable to find the STAGE bulk-request ID = " << requestId;
throw ObjectNotFoundException(ss.str());
}
//checkIssuerAuthorizedToAccessStageBulkRequest(bulkRequest.get(), vid,"delete");
//Create the prepare arguments, we will cancel all the files from this bulk-request
auto filesFromBulkRequest = bulkRequest->getFiles();
bulk::PrepareArgumentsWrapper pargsWrapper(requestId, Prep_CANCEL);
for (auto& fileFromBulkRequest : *filesFromBulkRequest) {
pargsWrapper.addFile(fileFromBulkRequest->getPath(), "");
}
auto pm = createPrepareManager();
XrdOucErrInfo error;
int retCancellation = pm->prepare(*pargsWrapper.getPrepareArguments(), error,
vid);
if (retCancellation != SFS_OK) {
std::stringstream ss;
ss << "Unable to cancel the files provided. errMsg=\"" << error.getErrText() <<
"\"";
throw TapeRestApiBusinessException(ss.str());
}
//Now that the request got cancelled, let's delete it from the persistency
try {
bulkRequestBusiness->deleteBulkRequest(bulkRequest.get());
} catch (bulk::PersistencyException& ex) {
throw TapeRestApiBusinessException(ex.what());
}
EXEC_TIMING_END("TapeRestApiBusiness::deleteStageBulkRequest");
}
std::shared_ptr TapeRestApiBusiness::getFileInfo(
const PathsModel* model, const common::VirtualIdentity* vid)
{
EXEC_TIMING_BEGIN("TapeRestApiBusiness::getFileInfo");
gOFS->MgmStats.Add("TapeRestApiBusiness::getFileInfo", vid->uid, vid->gid, 1);
auto& filesContainer = model->getFiles();
bulk::PrepareArgumentsWrapper pargsWrapper("fake_id", Prep_QUERY);
for (const auto& pathFromUser : filesContainer.getPaths()) {
pargsWrapper.addFile(pathFromUser, "");
}
auto pm = createPrepareManager();
XrdOucErrInfo error;
auto queryPrepareResult = pm->queryPrepare(*pargsWrapper.getPrepareArguments(),
error, vid);
if (!queryPrepareResult->hasQueryPrepareFinished()) {
std::stringstream ss;
ss << "Unable to get information about the files provided. errMsg=\"" <<
error.getErrText() << "\"";
throw TapeRestApiBusinessException(ss.str());
}
EXEC_TIMING_END("TapeRestApiBusiness::getFileInfo");
return queryPrepareResult->getResponse();
}
void TapeRestApiBusiness::releasePaths(const PathsModel* model,
const common::VirtualIdentity* vid)
{
EXEC_TIMING_BEGIN("TapeRestApiBusiness::releasePaths");
gOFS->MgmStats.Add("TapeRestApiBusiness::releasePaths", vid->uid, vid->gid, 1);
auto& filesContainer = model->getFiles();
bulk::PrepareArgumentsWrapper pargsWrapper("fake_id", Prep_EVICT,
filesContainer.getPaths(),
filesContainer.getOpaqueInfos());
auto pm = createBulkRequestPrepareManager();
XrdOucErrInfo error;
int retEvict = pm->prepare(*pargsWrapper.getPrepareArguments(), error, vid);
if (retEvict != SFS_OK) {
std::stringstream ss;
ss << "Unable to release the files provided. errMsg=\"" << error.getErrText() <<
"\"";
throw TapeRestApiBusinessException(ss.str());
}
EXEC_TIMING_END("TapeRestApiBusiness::releasePaths");
}
std::unique_ptr
TapeRestApiBusiness::createBulkRequestPrepareManager()
{
std::unique_ptr mgmOfs =
std::make_unique(gOFS);
std::unique_ptr prepareManager =
std::make_unique(std::move(mgmOfs));
std::shared_ptr bulkRequestBusiness =
createBulkRequestBusiness();
prepareManager->setBulkRequestBusiness(bulkRequestBusiness);
return prepareManager;
}
std::unique_ptr
TapeRestApiBusiness::createPrepareManager()
{
std::unique_ptr mgmOfs =
std::make_unique(gOFS);
std::unique_ptr prepareManager =
std::make_unique(std::move(mgmOfs));
return prepareManager;
}
std::shared_ptr
TapeRestApiBusiness::createBulkRequestBusiness()
{
std::unique_ptr daoFactory(new
bulk::ProcDirectoryDAOFactory(gOFS,
*gOFS->mProcDirectoryBulkRequestTapeRestApiLocations));
return std::make_shared(std::move(daoFactory));
}
void TapeRestApiBusiness::checkIssuerAuthorizedToAccessStageBulkRequest(
const bulk::StageBulkRequest* bulkRequest, const common::VirtualIdentity* vid,
const std::string& action)
{
//First, check if the issuer of the cancellation is root, or is the person who submitted the stage request
if (vid->uid != 0 && vid->uid != bulkRequest->getIssuerVid().uid) {
throw ForbiddenException("You are not allowed to " + action +
" this bulk-request");
}
}
EOSMGMRESTNAMESPACE_END