Commit 26a374ad authored by Cedric Caffy's avatar Cedric Caffy
Browse files

[cta-admin] Tape add/ch/ls is now compatible with the new tape lifecycle (state)

parent 7696131a
......@@ -3166,7 +3166,7 @@ void RdbmsCatalogue::createTape(
bool readOnly = tape.readOnly;
// Translate an empty comment string to a NULL database value
const optional<std::string> tapeComment = tape.comment && tape.comment->empty() ? nullopt : tape.comment;
const optional<std::string> stateReason = tape.stateReason && tape.stateReason->empty() ? nullopt : tape.stateReason;
const optional<std::string> stateReason = tape.stateReason && cta::utils::trimString(tape.stateReason.value()).empty() ? nullopt : tape.stateReason;
if(vid.empty()) {
throw UserSpecifiedAnEmptyStringVid("Cannot create tape because the VID is an empty string");
......@@ -4497,7 +4497,7 @@ void RdbmsCatalogue::modifyTapeState(const std::string &vid, const common::dataS
using namespace common::dataStructures;
const time_t now = time(nullptr);
const optional<std::string> stateReasonCopy = stateReason && stateReason->empty() ? nullopt : stateReason;
const optional<std::string> stateReasonCopy = stateReason && cta::utils::trimString(stateReason.value()).empty() ? nullopt : stateReason;
std::string stateStr;
try {
......
......@@ -61,14 +61,15 @@ CREATE TABLE FILE_RECYCLE_LOG(
CREATE INDEX FILE_RECYCLE_LOG_DFI_IDX ON FILE_RECYCLE_LOG(DISK_FILE_ID);
--rollback DROP INDEX FILE_RECYCLE_LOG_DFI_IDX;
--changeset ccaffy:5 failOnError:true dbms:oracle
--changeset ccaffy:5 failOnError:true dbms:oracle runAlways:true
--preconditions onFail:HALT onError:HALT
--precondition-sql-check expectedResult:"3.1" SELECT CONCAT(CONCAT(CAST(SCHEMA_VERSION_MAJOR as VARCHAR(10)),'.'), CAST(SCHEMA_VERSION_MINOR AS VARCHAR(10))) AS CATALOGUE_VERSION FROM CTA_CATALOGUE;
--precondition-sql-check expectedResult:"1" SELECT COUNT(*) FROM CTA_CATALOGUE WHERE SCHEMA_VERSION_MAJOR = 3 AND (SCHEMA_VERSION_MINOR = 1 OR SCHEMA_VERSION_MINOR = 2);
INSERT INTO FILE_RECYCLE_LOG (
FILE_RECYCLE_LOG_ID,
VID,
FSEQ,
COPY_NB,
BLOCK_ID,
TAPE_FILE_CREATION_TIME,
ARCHIVE_FILE_ID,
DISK_INSTANCE_NAME,
......@@ -112,14 +113,16 @@ INSERT INTO FILE_RECYCLE_LOG (
ARCHIVE_FILE ON TAPE_FILE.ARCHIVE_FILE_ID = ARCHIVE_FILE.ARCHIVE_FILE_ID
WHERE TAPE_FILE.SUPERSEDED_BY_VID IS NOT NULL;
--changeset ccaffy:6 failOnError:true dbms:oracle
--changeset ccaffy:6 failOnError:true dbms:oracle runAlways:true
--labels: delete_repacked_files
--preconditions onFail:HALT onError:HALT
--precondition-sql-check expectedResult:"3.1" SELECT CONCAT(CONCAT(CAST(SCHEMA_VERSION_MAJOR as VARCHAR(10)),'.'), CAST(SCHEMA_VERSION_MINOR AS VARCHAR(10))) AS CATALOGUE_VERSION FROM CTA_CATALOGUE;
--precondition-sql-check expectedResult:"1" SELECT COUNT(*) FROM CTA_CATALOGUE WHERE SCHEMA_VERSION_MAJOR = 3 AND (SCHEMA_VERSION_MINOR = 1 OR SCHEMA_VERSION_MINOR = 2);
DELETE FROM TAPE_FILE WHERE SUPERSEDED_BY_VID IS NOT NULL;
--changeset ccaffy:7 failOnError:true dbms:oracle
--changeset ccaffy:7 failOnError:true dbms:oracle runAlways:true
--labels: move_deleted_files_to_recycle_log
--preconditions onFail:HALT onError:HALT
--precondition-sql-check expectedResult:"3.1" SELECT CONCAT(CONCAT(CAST(SCHEMA_VERSION_MAJOR as VARCHAR(10)),'.'), CAST(SCHEMA_VERSION_MINOR AS VARCHAR(10))) AS CATALOGUE_VERSION FROM CTA_CATALOGUE;
--precondition-sql-check expectedResult:"1" SELECT COUNT(*) FROM CTA_CATALOGUE WHERE SCHEMA_VERSION_MAJOR = 3 AND (SCHEMA_VERSION_MINOR = 1 OR SCHEMA_VERSION_MINOR = 2);
INSERT INTO FILE_RECYCLE_LOG (
FILE_RECYCLE_LOG_ID,
VID,
......@@ -170,14 +173,16 @@ INSERT INTO FILE_RECYCLE_LOG (
TAPE_FILE_RECYCLE_BIN JOIN
ARCHIVE_FILE_RECYCLE_BIN ON TAPE_FILE_RECYCLE_BIN.ARCHIVE_FILE_ID = ARCHIVE_FILE_RECYCLE_BIN.ARCHIVE_FILE_ID;
--changeset ccaffy:8 failOnError:true dbms:oracle
--changeset ccaffy:8 failOnError:true dbms:oracle runAlways:true
--labels: delete_files_from_tape_file_recycle_bin
--preconditions onFail:HALT onError:HALT
--precondition-sql-check expectedResult:"3.1" SELECT CONCAT(CONCAT(CAST(SCHEMA_VERSION_MAJOR as VARCHAR(10)),'.'), CAST(SCHEMA_VERSION_MINOR AS VARCHAR(10))) AS CATALOGUE_VERSION FROM CTA_CATALOGUE;
--precondition-sql-check expectedResult:"1" SELECT COUNT(*) FROM CTA_CATALOGUE WHERE SCHEMA_VERSION_MAJOR = 3 AND (SCHEMA_VERSION_MINOR = 1 OR SCHEMA_VERSION_MINOR = 2);
DELETE FROM TAPE_FILE_RECYCLE_BIN;
--changeset ccaffy:9 failOnError:true dbms:oracle
--changeset ccaffy:9 failOnError:true dbms:oracle runAlways:true
--labels: delete_files_from_archive_file_recycle_bin
--preconditions onFail:HALT onError:HALT
--precondition-sql-check expectedResult:"3.1" SELECT CONCAT(CONCAT(CAST(SCHEMA_VERSION_MAJOR as VARCHAR(10)),'.'), CAST(SCHEMA_VERSION_MINOR AS VARCHAR(10))) AS CATALOGUE_VERSION FROM CTA_CATALOGUE;
--precondition-sql-check expectedResult:"1" SELECT COUNT(*) FROM CTA_CATALOGUE WHERE SCHEMA_VERSION_MAJOR = 3 AND (SCHEMA_VERSION_MINOR = 1 OR SCHEMA_VERSION_MINOR = 2);
DELETE FROM ARCHIVE_FILE_RECYCLE_BIN;
--changeset ccaffy:10 failOnError:true dbms:oracle
......
......@@ -22,12 +22,15 @@
#include <map>
#include <set>
#include <string>
#include "common/dataStructures/Tape.hpp"
#include "CtaFrontendApi.hpp"
namespace cta {
namespace admin {
using namespace common::dataStructures;
/*!
* Command line option class
*/
......@@ -317,7 +320,8 @@ const std::map<std::string, OptionString::Key> strOptions = {
{ "--disksystem", OptionString::DISK_SYSTEM },
{ "--fileregexp", OptionString::FILE_REGEXP },
{ "--freespacequeryurl", OptionString::FREE_SPACE_QUERY_URL },
{ "--reason", OptionString::REASON }
{ "--reason", OptionString::REASON },
{ "--state", OptionString::STATE }
};
......@@ -473,6 +477,8 @@ const Option opt_reason { Option::OPT_STR, "--reason",
const Option opt_no_recall { Option::OPT_FLAG, "--no-recall", "-nr", "" };
const Option opt_object_id { Option::OPT_STR, "--objectid", "-o", " <objectId>" };
const Option opt_state { Option::OPT_STR, "--state", "-s", std::string(" <\"") + Tape::stateToString(Tape::ACTIVE) +"\"" + " or \"" + Tape::stateToString(Tape::DISABLED) + "\" or \"" + Tape::stateToString(Tape::BROKEN) + "\">" };
/*!
* Map valid options to commands
*/
......@@ -554,18 +560,18 @@ const std::map<cmd_key_t, cmd_val_t> cmdOptions = {
{{ AdminCmd::CMD_STORAGECLASS, AdminCmd::SUBCMD_LS }, { }},
/*----------------------------------------------------------------------------------------------------*/
{{ AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_ADD },
{ opt_vid, opt_mediatype, opt_vendor, opt_logicallibrary, opt_tapepool, opt_disabled, opt_full, opt_readonly,
opt_comment.optional() }},
{ opt_vid, opt_mediatype, opt_vendor, opt_logicallibrary, opt_tapepool, opt_disabled, opt_full, opt_readonly,
opt_state.optional(), opt_reason.optional(), opt_comment.optional() }},
{{ AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_CH },
{ opt_vid, opt_mediatype.optional(), opt_vendor.optional(), opt_logicallibrary.optional(),
opt_tapepool.optional(), opt_encryptionkeyname.optional(), opt_disabled.optional(),
opt_full.optional(), opt_readonly.optional(), opt_comment.optional() }},
opt_full.optional(), opt_readonly.optional(), opt_state.optional(), opt_reason.optional(), opt_comment.optional() }},
{{ AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_RM }, { opt_vid }},
{{ AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_RECLAIM }, { opt_vid }},
{{ AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_LS },
{ opt_vid.optional(), opt_mediatype.optional(), opt_vendor.optional(),
opt_logicallibrary.optional(), opt_tapepool.optional(), opt_vo.optional(), opt_capacity.optional(),
opt_disabled.optional(), opt_full.optional(), opt_readonly.optional(), opt_fidfile.optional(), opt_all.optional() }},
opt_disabled.optional(), opt_full.optional(), opt_readonly.optional(), opt_fidfile.optional(), opt_all.optional(), opt_state.optional() }},
{{ AdminCmd::CMD_TAPE, AdminCmd::SUBCMD_LABEL },
{ opt_vid, opt_force.optional() }},
/*----------------------------------------------------------------------------------------------------*/
......
......@@ -271,7 +271,7 @@ void TextFormatter::print(const DriveLsItem &drls_item)
(drls_item.time_since_last_update() > DRIVE_TIMEOUT ? " [STALE]" : "");
//If there is a reason, we only want to display the beginning
std::string reason = cta::utils::postEllipsis(drls_item.reason(),NB_CHAR_REASON_DRIVE);
std::string reason = cta::utils::postEllipsis(drls_item.reason(),NB_CHAR_REASON);
push_back(
drls_item.logical_library(),
......@@ -789,6 +789,8 @@ void TextFormatter::printTapeLsHeader() {
"disabled",
"rdonly",
"from castor",
"state",
"state reason",
"label drive",
"label time",
"last w drive",
......@@ -808,6 +810,7 @@ void TextFormatter::printTapeLsHeader() {
}
void TextFormatter::print(const TapeLsItem &tals_item) {
std::string state_reason = cta::utils::postEllipsis(tals_item.state_reason(),NB_CHAR_REASON);
push_back(
tals_item.vid(),
tals_item.media_type(),
......@@ -823,6 +826,8 @@ void TextFormatter::print(const TapeLsItem &tals_item) {
tals_item.disabled(),
tals_item.rdonly(),
tals_item.from_castor(),
tals_item.state(),
state_reason,
tals_item.has_label_log() ? tals_item.label_log().drive() : "",
tals_item.has_label_log() ? timeToStr(tals_item.label_log().time()) : "",
tals_item.has_last_written_log() ? tals_item.last_written_log().drive() : "",
......
......@@ -162,7 +162,7 @@ private:
static constexpr const char* const TEXT_RED = "\x1b[31;1m"; //!< Terminal formatting code for red text
static constexpr const char* const TEXT_NORMAL = "\x1b[0m"; //!< Terminal formatting code for normal text
static constexpr const int NB_CHAR_REASON_DRIVE = 50; //!< DriveLs reason max length to display in tabular output
static constexpr const int NB_CHAR_REASON = 50; //!< Reason max length to display in tabular output (DriveLs and TapeLs)
};
}}
......@@ -102,17 +102,17 @@ std::string Tape::stateToString(const Tape::State & state) {
try {
return Tape::STATE_TO_STRING_MAP.at(state);
} catch (std::out_of_range &ex){
throw cta::exception::Exception(std::string("In Tape::stateToString(): The state given (") + std::to_string(state) + ") does not exist.");
throw cta::exception::Exception(std::string("The state given (") + std::to_string(state) + ") does not exist.");
}
}
Tape::State Tape::stringToState(const std::string& state) {
std::string stateUpperCase = state;
cta::utils::toUpper(stateUpperCase);
try {
std::string stateCopy = state;
cta::utils::toUpper(stateCopy);
return Tape::STRING_TO_STATE_MAP.at(state);
return Tape::STRING_TO_STATE_MAP.at(stateUpperCase);
} catch(std::out_of_range &ex){
throw cta::exception::Exception(std::string("In Tape::stringToState(): The state given (") + state + ") does not exist. Possible values are " + Tape::getAllPossibleStates());
throw cta::exception::Exception(std::string("The state given (") + stateUpperCase + ") does not exist. Possible values are " + Tape::getAllPossibleStates());
}
}
......
......@@ -81,7 +81,10 @@ TapeLsStream::TapeLsStream(const RequestMessage &requestMsg, cta::catalogue::Cat
searchCriteria.mediaType = requestMsg.getOptional(OptionString::MEDIA_TYPE, &has_any);
searchCriteria.vendor = requestMsg.getOptional(OptionString::VENDOR, &has_any);
searchCriteria.diskFileIds = requestMsg.getOptional(OptionStrList::FILE_ID, &has_any);
auto stateOpt = requestMsg.getOptional(OptionString::STATE, &has_any);
if(stateOpt){
searchCriteria.state = common::dataStructures::Tape::stringToState(stateOpt.value());
}
if(!(requestMsg.has_flag(OptionBoolean::ALL) || has_any)) {
throw cta::exception::UserError("Must specify at least one search option, or --all");
} else if(requestMsg.has_flag(OptionBoolean::ALL) && has_any) {
......@@ -142,6 +145,11 @@ int TapeLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
lastModificationLog->set_time(tape.lastModificationLog.time);
tape_item->set_comment(tape.comment);
tape_item->set_state(tape.getStateStr());
tape_item->set_state_reason(tape.stateReason ? tape.stateReason.value() : "");
tape_item->set_state_update_time(tape.stateUpdateTime);
tape_item->set_state_modified_by(tape.stateModifiedBy);
is_buffer_full = streambuf->Push(record);
}
return streambuf->Size();
......
......@@ -1733,7 +1733,9 @@ void RequestMessage::processTape_Add(cta::xrd::Response &response)
auto &disabled = getRequired(OptionBoolean::DISABLED);
auto &full = getRequired(OptionBoolean::FULL);
auto &readOnly = getRequired(OptionBoolean::READ_ONLY);
auto comment = getOptional(OptionString::COMMENT);
auto state = getOptional(OptionString::STATE);
auto stateReason = getOptional(OptionString::REASON);
auto comment = getOptional(OptionString::COMMENT);
cta::catalogue::CreateTapeAttributes tape;
tape.vid = vid;
......@@ -1745,7 +1747,14 @@ void RequestMessage::processTape_Add(cta::xrd::Response &response)
tape.disabled = disabled;
tape.readOnly = readOnly;
tape.comment = comment ? comment.value() : "";
tape.state = common::dataStructures::Tape::ACTIVE;
if(!state){
//By default, the state of the tape will be ACTIVE
tape.state = common::dataStructures::Tape::ACTIVE;
} else {
//State has been provided by the user, assign it. Will throw an exception if the state provided does not exist.
tape.state = common::dataStructures::Tape::stringToState(state.value());
}
tape.stateReason = stateReason;
m_catalogue.createTape(m_cliIdentity, tape);
response.set_type(cta::xrd::Response::RSP_SUCCESS);
......@@ -1767,6 +1776,8 @@ void RequestMessage::processTape_Ch(cta::xrd::Response &response)
auto disabled = getOptional(OptionBoolean::DISABLED);
auto full = getOptional(OptionBoolean::FULL);
auto readOnly = getOptional(OptionBoolean::READ_ONLY);
auto state = getOptional(OptionString::STATE);
auto stateReason = getOptional(OptionString::REASON);
if(mediaType) {
m_catalogue.modifyTapeMediaType(m_cliIdentity, vid, mediaType.value());
......@@ -1799,6 +1810,10 @@ void RequestMessage::processTape_Ch(cta::xrd::Response &response)
if(readOnly) {
m_catalogue.setTapeReadOnly(m_cliIdentity, vid, readOnly.value());
}
if(state){
auto stateEnumValue = common::dataStructures::Tape::stringToState(state.value());
m_catalogue.modifyTapeState(vid,stateEnumValue,stateReason,m_cliIdentity.username+"@"+m_cliIdentity.host);
}
response.set_type(cta::xrd::Response::RSP_SUCCESS);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment