Commit 28d7008d authored by Steven Murray's avatar Steven Murray
Browse files

Added command-line tool cta-catalogue-schema-lock

parent 9d4d516c
......@@ -22,6 +22,7 @@ set (CATALOGUE_LIB_SRC_FILES
ArchiveFileItor.cpp
Catalogue.cpp
CatalogueFactory.cpp
CmdLineTool.cpp
InMemoryCatalogue.cpp
OracleCatalogue.cpp
RdbmsCatalogueSchema.cpp
......@@ -94,3 +95,13 @@ install(TARGETS ctacatalogueunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
install (FILES cta_catalogue_db.conf.example
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cta
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
add_executable(cta-catalogue-schema-lock
LockSchemaCmd.cpp
LockSchemaCmdLineArgs.cpp
LockSchemaCmdMain.cpp)
target_link_libraries (cta-catalogue-schema-lock
ctacatalogue)
install(TARGETS cta-catalogue-schema-lock DESTINATION /usr/bin)
......@@ -500,7 +500,8 @@ public:
* prevent a disk instance deleting an archive file that belongs to another
* disk instance.
*
* @param instanceName The name of the instance from where the deletion request originated
* @param instanceName The name of the instance from where the deletion request
* originated
* @param archiveFileId The unique identifier of the archive file.
* @return The metadata of the deleted archive file including the metadata of
* the associated and also deleted tape copies.
......@@ -518,6 +519,29 @@ public:
*/
virtual bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const = 0;
/**
* Returns true if SCHEMA_STATUS column of the CTA_TABLE contains the value
* LOCKED.
*
* @return True if SCHEMA_STATUS column of the CTA_TABLE contains the value
* LOCKED.
*/
virtual bool schemaIsLocked() const = 0;
/**
* Sets the value of the SCHEMA_STATUS column of the CTA_TABLE to LOCKED.
*
* Please note that this method is idempotent.
*/
virtual void lockSchema() = 0;
/**
* Sets the value of the SCHEMA_STATUS column of the CTA_TABLE to UNLOCKED.
*
* Please note that this method is idempotent.
*/
virtual void unlockSchema() = 0;
}; // class Catalogue
} // namespace catalogue
......
......@@ -7128,4 +7128,15 @@ TEST_P(cta_catalogue_CatalogueTest, reclaimTape_full_lastFSeq_1_one_tape_file) {
ASSERT_THROW(m_catalogue->reclaimTape(m_admin, vid1), exception::UserError);
}
TEST_P(cta_catalogue_CatalogueTest, lockSchema_unlockSchema_lockSchema) {
using namespace cta;
m_catalogue->lockSchema();
ASSERT_TRUE(m_catalogue->schemaIsLocked());
m_catalogue->unlockSchema();
ASSERT_FALSE(m_catalogue->schemaIsLocked());
m_catalogue->lockSchema();
ASSERT_TRUE(m_catalogue->schemaIsLocked());
}
} // namespace unitTests
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#include "catalogue/CmdLineTool.hpp"
namespace cta {
namespace catalogue {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
CmdLineTool::CmdLineTool(
std::istream &inStream,
std::ostream &outStream,
std::ostream &errStream) noexcept:
m_in(inStream),
m_out(outStream),
m_err(errStream) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
CmdLineTool::~CmdLineTool() noexcept {
}
} // namespace catalogue
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <istream>
#include <ostream>
namespace cta {
namespace catalogue {
/**
* Abstract class implementing common code and data structures for a
* command-line tool.
*/
class CmdLineTool {
public:
/**
* Constructor.
*
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
*/
CmdLineTool(std::istream &inStream, std::ostream &outStream, std::ostream &errStream) noexcept;
/**
* Pure-virtual destructor to guarantee this class is abstract.
*/
virtual ~CmdLineTool() noexcept = 0;
protected:
/**
* Standard input stream.
*/
std::istream &m_in;
/**
* Standard output stream.
*/
std::ostream &m_out;
/**
* Standard error stream.
*/
std::ostream &m_err;
}; // class CmdLineTool
} // namespace catalogue
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#include "catalogue/CatalogueFactory.hpp"
#include "catalogue/LockSchemaCmd.hpp"
#include "catalogue/LockSchemaCmdLineArgs.hpp"
namespace cta {
namespace catalogue {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
LockSchemaCmd::LockSchemaCmd(std::istream &inStream, std::ostream &outStream, std::ostream &errStream):
CmdLineTool(inStream, outStream, errStream) {
}
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
LockSchemaCmd::~LockSchemaCmd() noexcept {
}
//------------------------------------------------------------------------------
// exceptionThrowingMain
//------------------------------------------------------------------------------
int LockSchemaCmd::exceptionThrowingMain(const int argc, char *const *const argv) {
const LockSchemaCmdLineArgs cmdLineArgs(argc, argv);
const auto dbLogin = rdbms::Login::parseFile(cmdLineArgs.dbConfigPath);
const uint64_t nbDbConns = 1;
auto catalogue = CatalogueFactory::create(dbLogin, nbDbConns);
catalogue->lockSchema();
return 0;
}
} // namespace catalogue
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "catalogue/CmdLineTool.hpp"
namespace cta {
namespace catalogue {
/**
* Command-line tool for locking the catalogue schema in order to help
* protect it from accidental deletion.
*/
class LockSchemaCmd: public CmdLineTool {
public:
/**
* Constructor.
*
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
*/
LockSchemaCmd(std::istream &inStream, std::ostream &outStream, std::ostream &errStream);
/**
* Destructor.
*/
~LockSchemaCmd() noexcept;
/**
* An exception throwing version of main().
*
* @param argc The number of command-line arguments including the program name.
* @param argv The command-line arguments.
* @return The exit value of the program.
*/
int exceptionThrowingMain(const int argc, char *const *const argv);
}; // class LockSchemaCmd
} // namespace catalogue
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#include "catalogue/LockSchemaCmdLineArgs.hpp"
#include "common/exception/Exception.hpp"
#include <ostream>
namespace cta {
namespace catalogue {
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
LockSchemaCmdLineArgs::LockSchemaCmdLineArgs(const int argc, const char *const *const argv) {
if(argc != 2) {
exception::Exception ex;
ex.getMessage() << "Wrong number of command-line arguments: excepted=1 actual=" << (argc - 1) << std::endl <<
std::endl;
printUsage(ex.getMessage());
throw ex;
}
dbConfigPath = argv[1];
}
//------------------------------------------------------------------------------
// printUsage
//------------------------------------------------------------------------------
void LockSchemaCmdLineArgs::printUsage(std::ostream &os) {
os <<
"Usage:" << std::endl <<
" cta-catalogue-schema-lock databaseConnectionFile" << std::endl <<
"Where:" << std::endl <<
" databaseConnectionFile" << std::endl <<
" The path to the file containing the connection details of the CTA" << std::endl <<
" catalogue database" << std::endl;
}
} // namespace catalogue
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#include <string>
namespace cta {
namespace catalogue {
/**
* Structure to store the command-line arguments of the command-line tool
* named cta-catalogue-schema-lock.
*/
struct LockSchemaCmdLineArgs {
/**
* Path to the file containing the connection details of the catalogue
* database.
*/
std::string dbConfigPath;
/**
* Constructor that parses the specified command-line arguments.
*
* @param argc The number of command-line arguments including the name of the
* executable.
* @param argv The vector of command-line arguments.
*/
LockSchemaCmdLineArgs(const int argc, const char *const *const argv);
/**
* Prints the usage message of the command-line tool.
*
* @param os The output stream to which the usage message is to be printed.
*/
static void printUsage(std::ostream &os);
};
} // namespace catalogue
} // namespace cta
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
*/
#include "catalogue/LockSchemaCmd.hpp"
#include "common/exception/Exception.hpp"
#include <iostream>
/**
* An exception throwing version of main().
*
* @param argc The number of command-line arguments including the program name.
* @param argv The command-line arguments.
* @return The exit value of the program.
*/
static int exceptionThrowingMain(const int argc, char *const *const argv);
//------------------------------------------------------------------------------
// main
//------------------------------------------------------------------------------
int main(const int argc, char *const *const argv) {
using namespace cta;
std::string errorMessage;
try {
return exceptionThrowingMain(argc, argv);
} catch(exception::Exception &ex) {
errorMessage = ex.getMessage().str();
} catch(std::exception &se) {
errorMessage = se.what();
} catch(...) {
errorMessage = "An unknown exception was thrown";
}
// Reaching this point means the command has failed, an exception was throw
// and errorMessage has been set accordingly
std::cerr << "Aborting: " << errorMessage << std::endl;
return 1;
}
//------------------------------------------------------------------------------
// exceptionThrowingMain
//------------------------------------------------------------------------------
static int exceptionThrowingMain(const int argc, char *const *const argv) {
using namespace cta;
catalogue::LockSchemaCmd cmd(std::cin, std::cout, std::cerr);
return cmd.exceptionThrowingMain(argc, argv);
}
......@@ -4425,5 +4425,95 @@ std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveF
}
}
//------------------------------------------------------------------------------
// schemaIsLocked
//------------------------------------------------------------------------------
bool RdbmsCatalogue::schemaIsLocked() const {
try {
const char *const sql = "SELECT SCHEMA_STATUS FROM CTA_CATALOGUE";
auto conn = m_connPool.getConn();
auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
auto rset = stmt->executeQuery();
if(!rset->next()) {
throw exception::Exception("The CTA_CATALOGUE table does not contain any rows when it should contain exactly "
"one");
}
const bool locked = rset->columnString("SCHEMA_STATUS") == "LOCKED";
if(rset->next()) {
throw exception::Exception("The CTA_CATALOGUE table contains more than one rows when it should contain exactly "
"one");
}
return locked;
} catch(exception::Exception &ex) {
throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
}
}
//------------------------------------------------------------------------------
// lockSchema
//------------------------------------------------------------------------------
void RdbmsCatalogue::lockSchema() {
try {
const char *const sql = "UPDATE CTA_CATALOGUE SET SCHEMA_STATUS = 'LOCKED'";
auto conn = m_connPool.getConn();
rdbms::AutoRollback autoRollback(conn.get());
auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
stmt->executeNonQuery();
const uint64_t nbAffectedRows = stmt->getNbAffectedRows();
switch(nbAffectedRows) {
case 0:
throw exception::Exception("Failed to lock CTA catalogue schema: "
"The CTA_CATALOGUE table does not contain any rows when it should contain exactly one");
case 1:
// Successfully locked the CTA catalogue schema
break;
default:
{
exception::Exception ex;
ex.getMessage() << "Failed to lock CTA catalogue schema: " << "The CTA_CATALOGUE tables contains " <<
nbAffectedRows << " rows when it should contain exactly one";
throw ex;
}
}
conn->commit();
} catch(exception::Exception &ex) {
throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
}
}
//------------------------------------------------------------------------------
// unlockSchema
//------------------------------------------------------------------------------
void RdbmsCatalogue::unlockSchema() {
try {
const char *const sql = "UPDATE CTA_CATALOGUE SET SCHEMA_STATUS = 'UNLOCKED'";
auto conn = m_connPool.getConn();
rdbms::AutoRollback autoRollback(conn.get());
auto stmt = conn->createStmt(sql, rdbms::Stmt::AutocommitMode::OFF);
stmt->executeNonQuery();
const uint64_t nbAffectedRows = stmt->getNbAffectedRows();
switch(nbAffectedRows) {
case 0:
throw exception::Exception("Failed to unlock CTA catalogue schema: "
"The CTA_CATALOGUE table does not contain any rows when it should contain exactly one");
case 1:
// Successfully locked the CTA catalogue schema
break;
default:
{
exception::Exception ex;
ex.getMessage() << "Failed to unlock CTA catalogue schema: " << "The CTA_CATALOGUE tables contains " <<
nbAffectedRows << " rows when it should contain exactly one";
throw ex;
}
}
conn->commit();
} catch(exception::Exception &ex) {
throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
}
}
} // namespace catalogue
} // namespace cta
......@@ -490,6 +490,27 @@ public:
*/
bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const override;
/**
* Returns true if SCHEMA_STATUS column of the CTA_TABLE contains the value LOCKED.
*
* @return True if SCHEMA_STATUS column of the CTA_TABLE contains the value LOCKED.
*/
bool schemaIsLocked() const override;
/**
* Sets the value of the SCHEMA_STATUS column of the CTA_TABLE to LOCKED.
*
* Please note that this method is idempotent.
*/
void lockSchema() override;
/**
* Sets the value of the SCHEMA_STATUS column of the CTA_TABLE to UNLOCKED.
*
* Please note that this method is idempotent.
*/
void unlockSchema() override;
protected:
/**
......
.\" The CERN Tape Archive (CTA) project
.\" Copyright (C) 2015 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 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 <http://www.gnu.org/licenses/>.
.TH CTA-CATALOGUE-SCHEMA-LOCK "8cta" "$Date: 2014/03/24 14:44:00 $" CTA "CTA"
.SH NAME
cta-catalogue-schema-lock \- Lock the CTA catalogue schema
.SH SYNOPSIS
.BI "cta-catalogue-schema-lock databaseConnectionFile"