Skip to content
Snippets Groups Projects
Commit 29d1a3b2 authored by abuts's avatar abuts
Browse files

Merge pull request #469 from mantidproject/11124_add_class_RemoteJobManagerFactory

Add class RemoteJobManagerFactory (+ ComputeResourceInfo)
parents 1ffd2722 273fa605
No related branches found
No related tags found
No related merge requests found
Showing
with 915 additions and 14 deletions
......@@ -106,6 +106,7 @@ set ( SRC_FILES
src/PropertyManagerDataService.cpp
src/PropertyNexus.cpp
src/RefAxis.cpp
src/RemoteJobManagerFactory.cpp
src/Run.cpp
src/Sample.cpp
src/SampleEnvironment.cpp
......@@ -271,6 +272,7 @@ set ( INC_FILES
inc/MantidAPI/PropertyManagerDataService.h
inc/MantidAPI/PropertyNexus.h
inc/MantidAPI/RefAxis.h
inc/MantidAPI/RemoteJobManagerFactory.h
inc/MantidAPI/Run.h
inc/MantidAPI/Sample.h
inc/MantidAPI/SampleEnvironment.h
......@@ -367,6 +369,7 @@ set ( TEST_FILES
ProjectionTest.h
PropertyManagerDataServiceTest.h
PropertyNexusTest.h
RemoteJobManagerFactoryTest.h
RunTest.h
SampleEnvironmentTest.h
SampleShapeValidatorTest.h
......
......@@ -137,7 +137,7 @@ public:
* @param numNodes number of nodes to use (optional and dependent on
* implementation and compute resource)
*
* @parm coresPerNode number of cores to use in each node (optional
* @param coresPerNode number of cores to use in each node (optional
* and dependent on implemenation and compute resource)
*
* @return jobID string for the job started (if successful).
......
#ifndef MANTID_API_REMOTEJOBMANAGERFACTORY_H_
#define MANTID_API_REMOTEJOBMANAGERFACTORY_H_
#include "MantidAPI/DllConfig.h"
#include "MantidAPI/IRemoteJobManager.h"
#include "MantidKernel/DynamicFactory.h"
#include "MantidKernel/SingletonHolder.h"
namespace Mantid {
namespace API {
/**
The RemoteJobManagerFactory handles the creation of remote job
managers specialised for different types of compute resources (for
different underlying job schedulers, web services, front-ends,
etc.). Through the create method of this class a shared pointer to a
remote job manager object can be obtained for a particular compute
resource.
The remote job managers built by this factory know how to start and
stop jobs, upload/download files, etc. for the compute resource
specified when creating the job manager (as long as the compute
resource is found for the current facility in the facilities
definition file).
Remote job manager classes must be registered/subscribe using the
macro DECLARE_REMOTEJOBMANAGER (the same way you use DECLARE_ALGORITHM
for algorithms and remote algorithms).
As the algorithm, workspace and other factories in Mantid, this
factory is implemented as a singleton class. Typical usages:
Mantid::API::IRemoteJob|Manager_sptr jobManager =
Mantid::API::RemoteJobManagerFactory::Instance().create("Fermi");
Mantid::API::IRemoteJob|Manager_sptr jobManager =
Mantid::API::RemoteJobManagerFactory::Instance().create("SCARF@STFC");
Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
This file is part of Mantid.
Mantid 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.
Mantid 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/>.
File change history is stored at: <https://github.com/mantidproject/mantid>.
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class MANTID_API_DLL RemoteJobManagerFactoryImpl
: public Kernel::DynamicFactory<IRemoteJobManager> {
public:
/// Create a remote job manager that will know how to use the
/// underlying mechanism that suits the compute resource passed
IRemoteJobManager_sptr create(const std::string &computeResourceName) const;
/// alternative (lower level) create where the specific type of
/// manager and base URL are directly given
IRemoteJobManager_sptr create(const std::string baseURL,
const std::string jobManagerType) const;
private:
/// So that the singleton can be created (cons/destructor are private)
friend struct Mantid::Kernel::CreateUsingNew<RemoteJobManagerFactoryImpl>;
/// Private Constructor for singleton class
RemoteJobManagerFactoryImpl();
/// Disallow copy construction
RemoteJobManagerFactoryImpl(const RemoteJobManagerFactoryImpl &);
/// Disallow assignment
RemoteJobManagerFactoryImpl &operator=(const RemoteJobManagerFactoryImpl &);
/// Private Destructor
virtual ~RemoteJobManagerFactoryImpl();
// Unhide the inherited create method but make it private
using Kernel::DynamicFactory<IRemoteJobManager>::create;
};
/// Forward declaration of a specialisation of SingletonHolder for
/// RemoteJobManagerFactoryImpl (needed for dllexport) and a typedef for it.
#ifdef _WIN32
// this breaks new namespace declaraion rules; need to find a better fix
template class MANTID_API_DLL
Mantid::Kernel::SingletonHolder<RemoteJobManagerFactoryImpl>;
#endif /* _WIN32 */
// The factory is just a specialisation of SingletonHolder
typedef MANTID_API_DLL Mantid::Kernel::SingletonHolder<
RemoteJobManagerFactoryImpl> RemoteJobManagerFactory;
} // namespace API
} // namespace Mantid
/* Macro to register (remote job manager) classes into the factory. As
* with the equivalent macros of the workspace factory or the
* algorithm factory, this creates a global object in an anonymous
* namespace. The object itself does nothing, but the comma operator
* is used in the call to its constructor to effect a call to the
* factory's subscribe method.
*
* You need to use this in every remote job manager. For example:
* DECLARE_REMOTEJOBMANAGER(MantidWebServiceAPI)
* DECLARE_REMOTEJOBMANAGER(SCARFLSFJobManager)
*/
#define DECLARE_REMOTEJOBMANAGER(classname) \
namespace { \
Mantid::Kernel::RegistrationHelper register_ws_##classname( \
((Mantid::API::RemoteJobManagerFactory::Instance().subscribe<classname>( \
#classname)), \
0)); \
}
#endif // MANTID_API_REMOTEJOBMANAGERFACTORY_H_
#include "MantidAPI/RemoteJobManagerFactory.h"
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/FacilityInfo.h"
#include "MantidKernel/Logger.h"
namespace Mantid {
namespace API {
namespace {
/// static logger object
Kernel::Logger g_log("RemoteJobManagerFactory");
}
/// Private constructor, singleton class
RemoteJobManagerFactoryImpl::RemoteJobManagerFactoryImpl()
: Mantid::Kernel::DynamicFactory<IRemoteJobManager>() {
g_log.debug() << "RemoteJobManager factory created." << std::endl;
}
/**
* Private destructor, prevent client code from using this.
*/
RemoteJobManagerFactoryImpl::~RemoteJobManagerFactoryImpl() {}
/**
* Create a remote algorithm with the underlying mechanism that suits
* the compute resource passed.
*
* @param computeResourceName Name of a (remote) compute resource
*
* @throw std::invalid_argument If no resource is found by the name
* given (compute resources are looked up in the facilities definition
* (XML) file for the current facility.
*/
IRemoteJobManager_sptr RemoteJobManagerFactoryImpl::create(
const std::string &computeResourceName) const {
IRemoteJobManager_sptr jm;
if (computeResourceName.empty())
return jm;
Mantid::Kernel::ComputeResourceInfo cr =
Mantid::Kernel::ConfigService::Instance().getFacility().computeResource(
computeResourceName);
// this is the default. It could be "MantidWebServiceAPI", "LSF",
// "SCARFLSF", "MOAB", etc.
std::string type = "MantidWebServiceAPIJobManager";
std::string fdfType = cr.remoteJobManagerType();
if (!fdfType.empty())
type = fdfType;
return create(cr.baseURL(), type);
}
/**
* Lower level create method that makes a remote algorithm given a
* base URL and the type of remote job manager.
*
* @param baseURL URL where the resource is accessible
*
* @param jobManagerType Type/class that can handle this remote
* compute resource (string names as used in the facilities definition
* file, for example: MantidWebServiceAPIJobManager).
*
* @throw std::invalid_argument If there is an issue with the URL or
* the type (for example the type is not recognized).
*/
Mantid::API::IRemoteJobManager_sptr
RemoteJobManagerFactoryImpl::create(const std::string baseURL,
const std::string jobManagerType) const {
Mantid::API::IRemoteJobManager_sptr jm;
// use the inherited/generic create method
try {
jm = this->create(jobManagerType);
} catch (Kernel::Exception::NotFoundError &e) {
throw Kernel::Exception::NotFoundError(
"RemoteJobManagerFactory: failed to create a remote job manager of "
"type (class) '" +
jobManagerType + "' with base URL " + baseURL +
". Error description: " + e.what(),
jobManagerType);
}
return jm;
}
} // namespace API
} // Namespace Mantid
#ifndef REMOTEJOBMANAGERFACTORYTEST_H_
#define REMOTEJOBMANAGERFACTORYTEST_H_
#include "MantidAPI/RemoteJobManagerFactory.h"
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/FacilityInfo.h"
using namespace Mantid::API;
// Just a minimal implementation of IRemoteJobManager, sufficient for the
// factory
class TestJM : public IRemoteJobManager {
public:
virtual void authenticate(const std::string &username,
const std::string &password) {
UNUSED_ARG(username);
UNUSED_ARG(password);
}
virtual std::string
submitRemoteJob(const std::string &transactionID, const std::string &runnable,
const std::string &param, const std::string &taskName = "",
const int numNodes = 1, const int coresPerNode = 1) {
UNUSED_ARG(transactionID);
UNUSED_ARG(runnable);
UNUSED_ARG(param);
UNUSED_ARG(taskName);
UNUSED_ARG(numNodes);
UNUSED_ARG(coresPerNode);
return "";
}
virtual void downloadRemoteFile(const std::string &transactionID,
const std::string &remoteFileName,
const std::string &localFileName) {
UNUSED_ARG(transactionID);
UNUSED_ARG(remoteFileName);
UNUSED_ARG(localFileName);
}
virtual std::vector<RemoteJobInfo> queryAllRemoteJobs() const {
return std::vector<RemoteJobInfo>();
}
virtual std::vector<std::string>
queryRemoteFile(const std::string &transactionID) const {
UNUSED_ARG(transactionID);
return std::vector<std::string>();
}
virtual RemoteJobInfo queryRemoteJob(const std::string &jobID) const {
UNUSED_ARG(jobID);
return RemoteJobInfo();
}
virtual std::string startRemoteTransaction() { return ""; }
virtual void stopRemoteTransaction(const std::string &transactionID) {
UNUSED_ARG(transactionID);
}
virtual void abortRemoteJob(const std::string &jobID) { UNUSED_ARG(jobID); }
virtual void uploadRemoteFile(const std::string &transactionID,
const std::string &remoteFileName,
const std::string &localFileName) {
UNUSED_ARG(transactionID);
UNUSED_ARG(remoteFileName);
UNUSED_ARG(localFileName);
}
};
class RemoteJobManagerFactoryTest : public CxxTest::TestSuite {
public:
void test_unsubscribed() {
IRemoteJobManager_sptr jobManager;
TS_ASSERT_THROWS(
jobManager = RemoteJobManagerFactory::Instance().create("Inexistent"),
std::runtime_error);
TS_ASSERT_THROWS(jobManager =
RemoteJobManagerFactory::Instance().create("TestJM"),
std::runtime_error);
}
// minimal positive test
void test_createTestJM() {
RemoteJobManagerFactory::Instance().subscribe<TestJM>("TestJM");
// throws not found cause it is not in facilities.xml, but otherwise fine
TS_ASSERT_THROWS(
jm = Mantid::API::RemoteJobManagerFactory::Instance().create("TestJM"),
Mantid::Kernel::Exception::NotFoundError);
}
// this must fail, resource not found in the current facility
void test_createAlienResource() {
// save facility, do this before any changes
const Mantid::Kernel::FacilityInfo &prevFac =
Mantid::Kernel::ConfigService::Instance().getFacility();
Mantid::Kernel::ConfigService::Instance().setFacility("ISIS");
TS_ASSERT_THROWS(
jm = Mantid::API::RemoteJobManagerFactory::Instance().create("Fermi"),
Mantid::Kernel::Exception::NotFoundError);
Mantid::Kernel::ConfigService::Instance().setFacility("SNS");
TS_ASSERT_THROWS(
Mantid::API::IRemoteJobManager_sptr jobManager =
Mantid::API::RemoteJobManagerFactory::Instance().create(
"SCARF@STFC"),
Mantid::Kernel::Exception::NotFoundError);
// restore facility, always do this at the end
Mantid::Kernel::ConfigService::Instance().setFacility(prevFac.name());
}
// a simple positive test
void test_createRemoteManagers() {
// save facility, do this before any changes
const Mantid::Kernel::FacilityInfo &prevFac =
Mantid::Kernel::ConfigService::Instance().getFacility();
Mantid::Kernel::ConfigService::Instance().setFacility("SNS");
// TODO: at the moment these two create throw a NotFoundError
// because the RemoteJobManager classes are missing and have not
// done a DECLARE_REMOTEJOBMANAGER. Change this test when that is
// done (ticket #11126 etc.)
TS_ASSERT_THROWS(
Mantid::API::IRemoteJobManager_sptr jobManager =
Mantid::API::RemoteJobManagerFactory::Instance().create("Fermi"),
Mantid::Kernel::Exception::NotFoundError);
Mantid::Kernel::ConfigService::Instance().setFacility("ISIS");
TS_ASSERT_THROWS(
Mantid::API::IRemoteJobManager_sptr jobManager =
Mantid::API::RemoteJobManagerFactory::Instance().create(
"SCARF@STFC"),
Mantid::Kernel::Exception::NotFoundError);
// restore facility, always do this at the end
Mantid::Kernel::ConfigService::Instance().setFacility(prevFac.name());
}
private:
Mantid::API::IRemoteJobManager_sptr jm;
};
#endif /* REMOTEJOBMANAGERFACTORYTEST_H_ */
......@@ -8,6 +8,7 @@ set ( SRC_FILES
src/CPUTimer.cpp
src/CatalogInfo.cpp
src/CompositeValidator.cpp
src/ComputeResourceInfo.cpp
src/ConfigService.cpp
src/ChecksumHelper.cpp
src/DataItem.cpp
......@@ -128,6 +129,7 @@ set ( INC_FILES
inc/MantidKernel/Cache.h
inc/MantidKernel/CatalogInfo.h
inc/MantidKernel/CompositeValidator.h
inc/MantidKernel/ComputeResourceInfo.h
inc/MantidKernel/ConfigService.h
inc/MantidKernel/ChecksumHelper.h
inc/MantidKernel/DataItem.h
......@@ -264,6 +266,7 @@ set ( TEST_FILES
CacheTest.h
CatalogInfoTest.h
CompositeValidatorTest.h
ComputeResourceInfoTest.h
ConfigServiceTest.h
ChecksumHelperTest.h
DataServiceTest.h
......
#ifndef MANTID_KERNEL_COMPUTERESOURCEINFO_H_
#define MANTID_KERNEL_COMPUTERESOURCEINFO_H_
#include <string>
#include "MantidKernel/DllConfig.h"
namespace Poco {
namespace XML {
class Element;
}
}
namespace Mantid {
namespace Kernel {
class FacilityInfo;
/**
ComputeResourceInfo holds information about / represents a compute
resource present in a facility.
At the moment (remote) compute resources are defined by their name,
the URL they can be accessed at, and the type of remote job manager
that they use/require (Mantid web service API, LSF, etc.).
Copyright &copy; 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
This file is part of Mantid.
Mantid 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.
Mantid 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/>.
File change history is stored at: <https://github.com/mantidproject/mantid>.
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class MANTID_KERNEL_DLL ComputeResourceInfo {
public:
/// constructor - from facility info and the element for this resource
ComputeResourceInfo(const FacilityInfo *f, const Poco::XML::Element *elem);
/// Equality operator
bool operator==(const ComputeResourceInfo &rhs) const;
/// Name of the compute resource
std::string name() const;
/// Base URL the compute resource
std::string baseURL() const ;
/// Type/class of remote job manager required to handle this resource
std::string remoteJobManagerType() const;
/// The facility where this compute resource is avalable
const FacilityInfo &facility() const;
private:
const FacilityInfo *m_facility; ///< Facility
std::string m_name; ///< Cluster/resource name
std::string m_baseURL; ///< access URL (first authentication, etc.)
std::string m_managerType; ///< specific remote job manager class
};
/// output to stream operator for compute resource info objects
MANTID_KERNEL_DLL std::ostream &
operator<<(std::ostream &buffer, const ComputeResourceInfo &cr);
} // namespace Kernel
} // namespace Mantid
#endif /* MANTID_KERNEL_COMPUTERESOURCEINFO_H_ */
......@@ -6,6 +6,7 @@
//----------------------------------------------------------------------
#include "MantidKernel/DllConfig.h"
#include "MantidKernel/CatalogInfo.h"
#include "MantidKernel/ComputeResourceInfo.h"
#include "MantidKernel/InstrumentInfo.h"
#include "MantidKernel/RemoteJobManager.h"
#ifndef Q_MOC_RUN
......@@ -80,7 +81,13 @@ public:
std::vector<InstrumentInfo> instruments(const std::string &tech) const;
/// Returns instruments with given name
const InstrumentInfo &instrument(std::string iName = "") const;
/// Returns a vector of the available compute resources
/// Returns a vector of available compute resources
std::vector<ComputeResourceInfo> computeResInfos() const;
/// Returns a compute resource identified by name
const ComputeResourceInfo &computeResource(const std::string &name) const;
/// Returns a vector of the names of the available compute resources
std::vector<std::string> computeResources() const;
/// Returns the RemoteJobManager for the named compute resource
boost::shared_ptr<RemoteJobManager>
......@@ -113,12 +120,18 @@ private:
std::vector<InstrumentInfo>
m_instruments; ///< list of instruments of this facility
std::string m_liveListener; ///< name of the default live listener
std::vector<ComputeResourceInfo> m_computeResInfos; ///< (remote) compute
/// resources available in
/// this facility
// TODO: remove RemoteJobManager form here (trac ticket #11373)
typedef std::map<std::string, boost::shared_ptr<RemoteJobManager>>
ComputeResourcesMap;
ComputeResourcesMap m_computeResources; ///< list of compute resources
///(clusters, etc...) available at
/// this facility
// (Sorted by their names)
/// this facility
// (Sorted by their names)
};
} // namespace Kernel
......
#include "MantidKernel/ComputeResourceInfo.h"
#include "MantidKernel/FacilityInfo.h"
#include "MantidKernel/Logger.h"
#include <Poco/DOM/AutoPtr.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeList.h>
#include <Poco/DOM/Text.h>
namespace Mantid {
namespace Kernel {
namespace {
// static logger object
Logger g_log("ComputeResourceInfo");
}
/**
* Construct a compute resource from information found in a facilities
* definition file.
*
* @param fac Facility where this (remote) compute resource is available
* @param elem A (Poco::XML::) Element to read the data from
*
* @throw std::runtime_error if name or required attributes are not
* found
*/
ComputeResourceInfo::ComputeResourceInfo(const FacilityInfo *fac,
const Poco::XML::Element *elem)
: m_facility(fac) {
m_name = elem->getAttribute("name");
if (m_name.empty()) {
std::string elemStr = "";
if (elem)
elemStr = elem->innerText();
throw std::runtime_error(
"The compute resource name is not defined, at element: " + elemStr);
}
// default: Mantid web service API:
// http://www.mantidproject.org/Remote_Job_Submission_API
m_managerType = "MantidWebServiceAPIJobManager";
std::string type = elem->getAttribute("JobManagerType");
if (!type.empty()) {
m_managerType = type;
}
const std::string baseTag = "baseURL";
Poco::AutoPtr<Poco::XML::NodeList> nl = elem->getElementsByTagName(baseTag);
if (!nl || nl->length() != 1 || !nl->item(0) || !nl->item(0)->childNodes()) {
g_log.error("Failed to get base URL for remote compute resource '" +
m_name + "'");
throw std::runtime_error("Remote compute resources must have exactly one "
"baseURL tag. It was not found for the resource "
"'" +
m_name + "'");
} else {
nl = nl->item(0)->childNodes();
if (nl->length() > 0) {
Poco::XML::Text *txt = dynamic_cast<Poco::XML::Text *>(nl->item(0));
if (txt) {
m_baseURL = txt->getData();
} else {
g_log.error("Failed to get base URL for remote compute resource '" +
m_name + "'. The " + baseTag + " tag seems empty!");
throw std::runtime_error(
"Remote compute resources must have exactly one "
"baseURL tag containing a URL string. A tag was found for the "
"resource "
"'" +
m_name + "', but it seems empty!");
}
}
}
}
/**
* Equality operator. Two different resources cannot have the same name
*
* @param rhs object to compare this with
*
* @return True if the objects (names) are equal
*/
bool ComputeResourceInfo::operator==(const ComputeResourceInfo &rhs) const {
return (this->name() == rhs.name());
}
std::string ComputeResourceInfo::name() const { return m_name; }
std::string ComputeResourceInfo::baseURL() const { return m_baseURL; }
std::string ComputeResourceInfo::remoteJobManagerType() const {
return m_managerType;
}
const FacilityInfo &ComputeResourceInfo::facility() const {
return *m_facility;
}
/**
* Prints the instrument name into an output stream
*
* @param buffer an output stream being written to
* @param cr a ComputeResourceInfo object to print
*
* @return reference to the output stream being written to
*/
std::ostream &operator<<(std::ostream &buffer, const ComputeResourceInfo &cr) {
buffer << "'" + cr.name() + "', at '" + cr.baseURL() + "', of type '" +
cr.remoteJobManagerType() + "'";
return buffer;
}
} // namespace Kernel
} // namespace Mantid
......@@ -154,10 +154,24 @@ void FacilityInfo::fillComputeResources(const Poco::XML::Element *elem) {
for (unsigned long i = 0; i < n; i++) {
Poco::XML::Element *elem =
dynamic_cast<Poco::XML::Element *>(pNL_compute->item(i));
std::string name = elem->getAttribute("name");
m_computeResources.insert(std::make_pair(
name, boost::shared_ptr<RemoteJobManager>(new RemoteJobManager(elem))));
if (elem) {
try {
ComputeResourceInfo cr(this, elem);
m_computeResInfos.push_back(cr);
g_log.debug() << "Compute resource found: " << cr << std::endl;
} catch (...) { // next resource...
}
std::string name = elem->getAttribute("name");
// TODO: this is a bit of duplicate effort at the moment, until
// RemoteJobManager goes away from here (then this would be
// removed), see header for details.
m_computeResources.insert(std::make_pair(
name,
boost::shared_ptr<RemoteJobManager>(new RemoteJobManager(elem))));
}
}
}
......@@ -202,14 +216,22 @@ const InstrumentInfo &FacilityInfo::instrument(std::string iName) const {
}
/**
* Returns a list of instruments of given technique
* @param tech :: Technique name
* @return a list of instrument information objects
* Get the vector of available compute resources
* @return vector of ComputeResourInfo for the current facility
*/
std::vector<ComputeResourceInfo> FacilityInfo::computeResInfos() const {
return m_computeResInfos;
}
/**
* Returns a list of instruments of given technique
* @param tech :: Technique name
* @return a list of instrument information objects
*/
std::vector<InstrumentInfo>
FacilityInfo::instruments(const std::string &tech) const {
std::vector<InstrumentInfo> out;
std::vector<InstrumentInfo>::const_iterator it = m_instruments.begin();
auto it = m_instruments.begin();
for (; it != m_instruments.end(); ++it) {
if (it->techniques().count(tech)) {
out.push_back(*it);
......@@ -219,7 +241,7 @@ FacilityInfo::instruments(const std::string &tech) const {
}
/**
* Returns a vector of the available compute resources
* Returns a vector of the names of the available compute resources
* @return vector of strings of the compute resource names
*/
std::vector<std::string> FacilityInfo::computeResources() const {
......@@ -233,6 +255,39 @@ std::vector<std::string> FacilityInfo::computeResources() const {
return names;
}
/**
* Get a compute resource by name
*
* @param name Name as specified in the facilities definition file
*
* @return the named compute resource
*
* @throws NotFoundError if the resource is not found/available.
*/
const ComputeResourceInfo &
FacilityInfo::computeResource(const std::string &name) const {
if (name.empty()) {
g_log.debug("Cannot find a compute resource without name "
"(empty).");
throw Exception::NotFoundError("FacilityInfo, empty compute resource name",
name);
}
auto it = m_computeResInfos.begin();
for (; it != m_computeResInfos.end(); ++it) {
if (it->name() == name) {
g_log.debug() << "Compute resource '" << name << "' found at facility "
<< this->name() << "." << std::endl;
return *it;
}
}
g_log.debug() << "Could not find requested compute resource: " << name
<< " in facility " << this->name() << "." << std::endl;
throw Exception::NotFoundError("FacilityInfo, missing compute resource",
name);
}
/**
* Returns a reference to the requested remote job manager
* @param name :: Name of the cluster we want to submit jobs to
......
......@@ -7,10 +7,10 @@
#include "MantidKernel/Logger.h"
#include "MantidKernel/Strings.h"
#include <Poco/DOM/AutoPtr.h>
#include <Poco/DOM/Element.h>
#include <Poco/DOM/NodeList.h>
#include <Poco/DOM/Text.h>
#include <Poco/DOM/AutoPtr.h>
#include <boost/lexical_cast.hpp>
......
#ifndef COMPUTERESOURCEINFOTEST_H_
#define COMPUTERESOURCEINFOTEST_H_
#include "MantidKernel/Exception.h"
#include "MantidKernel/FacilityInfo.h"
#include <Poco/DOM/AutoPtr.h>
#include <Poco/DOM/Document.h>
#include <Poco/DOM/DOMParser.h>
#include <Poco/XML/XMLException.h>
using namespace Mantid::Kernel;
class ComputeResourceInfoTest : public CxxTest::TestSuite {
public:
void test_allMissing() {
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS_NOTHING(fac =
createCRInfoInMinimalFacility(simpleInstStr));
TS_ASSERT(fac);
std::vector<ComputeResourceInfo> cri;
TS_ASSERT_THROWS_NOTHING(cri = fac->computeResInfos());
TS_ASSERT_EQUALS(cri.size(), 0);
delete fac;
fac = NULL;
TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(
"<computeResource fooAtt=\"barVal\"/>"),
std::runtime_error);
TS_ASSERT(!fac);
delete fac;
}
void test_noURLTag() {
const std::string crTxt = "<computeResource name=\"foo\">"
"<u>" +
fermiURL + "</u>"
"</computeResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(crTxt),
std::runtime_error);
TS_ASSERT(!fac);
delete fac;
}
void test_wrongXML() {
const std::string crTxt = "<computeResource name=\"foo\">"
"<u_foo>" +
fermiURL + "</u_bar>"
"</compResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(crTxt),
Poco::XML::XMLException);
TS_ASSERT(!fac);
delete fac;
}
void test_normalFermi() {
const std::string fermi = "<computeResource name=\"" + fermiName +
"\">"
"<baseURL>" +
fermiURL + "</baseURL>"
"</computeResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS_NOTHING(fac = createCRInfoInMinimalFacility(fermi));
TS_ASSERT(fac);
TS_ASSERT_EQUALS(fac->name(), this->testFacilityName);
std::vector<ComputeResourceInfo> cri;
TS_ASSERT_THROWS_NOTHING(cri = fac->computeResInfos());
TS_ASSERT_EQUALS(cri.size(), 1);
ComputeResourceInfo cr = fac->computeResInfos().front();
TS_ASSERT_THROWS(ComputeResourceInfo fail = fac->computeResource(scarfName),
Mantid::Kernel::Exception::NotFoundError);
ComputeResourceInfo cr2 = fac->computeResource(fermiName);
TS_ASSERT_EQUALS(cr, cr2);
TS_ASSERT_EQUALS(cr, cri.front());
TS_ASSERT_EQUALS(cr2, cri.front());
TS_ASSERT_EQUALS(cr.name(), fermiName);
TS_ASSERT_EQUALS(cr2.name(), fermiName);
TS_ASSERT_EQUALS(cr.baseURL(), fermiURL);
TS_ASSERT_EQUALS(cr2.baseURL(), fermiURL);
TS_ASSERT_EQUALS(cr.remoteJobManagerType(), defaultType);
TS_ASSERT_EQUALS(cr2.remoteJobManagerType(), defaultType);
TS_ASSERT_EQUALS(cr.facility().name(), fac->name());
TS_ASSERT_EQUALS(cr2.facility().name(), fac->name());
}
void test_brokenFermi() {
// wrong 'baseURL' tag
const std::string fermi = "<computeResource name=\"" + fermiName + "\">"
"<URL>" +
fermiURL + "</URL>"
"</computeResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(fermi),
std::runtime_error);
TS_ASSERT(!fac);
delete fac;
}
void test_normalSCARF() {
const std::string scarf = "<computeResource name=\"" + scarfName +
"\" JobManagerType=\"" + scarfType + "\">"
"<baseURL>" +
scarfURL + "</baseURL>"
"</computeResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS_NOTHING(fac = createCRInfoInMinimalFacility(scarf));
TS_ASSERT(fac);
TS_ASSERT_EQUALS(fac->name(), this->testFacilityName);
std::vector<ComputeResourceInfo> cri;
TS_ASSERT_THROWS_NOTHING(cri = fac->computeResInfos());
TS_ASSERT_EQUALS(cri.size(), 1);
ComputeResourceInfo cr = fac->computeResInfos().front();
TS_ASSERT_THROWS(ComputeResourceInfo fail = fac->computeResource("inexistent!"),
Mantid::Kernel::Exception::NotFoundError);
ComputeResourceInfo cr2 = fac->computeResource(scarfName);
TS_ASSERT_EQUALS(cr, cr2);
TS_ASSERT_EQUALS(cri.front(), cr);
TS_ASSERT_EQUALS(cri.front(), cr2);
TS_ASSERT_EQUALS(scarfName, cr.name());
TS_ASSERT_EQUALS(scarfName, cr2.name());
TS_ASSERT_EQUALS(scarfURL, cr.baseURL());
TS_ASSERT_EQUALS(scarfURL, cr2.baseURL());
TS_ASSERT_EQUALS(scarfType, cr.remoteJobManagerType());
TS_ASSERT_EQUALS(scarfType, cr2.remoteJobManagerType());
TS_ASSERT_EQUALS(fac->name(), cr.facility().name());
TS_ASSERT_EQUALS(fac->name(), cr2.facility().name());
delete fac;
}
void test_brokenSCARF() {
const std::string type = "SCARFLSFJobManager";
const std::string err = "<computeResource foo=\"" + scarfName +
"\" JobManagerType=\"" + type + "\">"
"<URL>" +
scarfURL + "</URL>"
"</computeResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS(fac = createCRInfoInMinimalFacility(err),
std::runtime_error);
TS_ASSERT(!fac);
delete fac;
}
void test_equals() {
const std::string otherName = "other";
const std::string otherURL = "www.example.com/foo/baz";
const std::string thirdName = "third";
const std::string rep = "<computeResource name=\"" + fermiName +
"\">"
"<baseURL>" +
fermiURL + "</baseURL>"
"</computeResource>"
"<computeResource name=\"" +
otherName + "\">"
"<baseURL>" +
otherURL + "</baseURL>"
"</computeResource>"
"<computeResource name=\"" +
thirdName + "\">"
"<baseURL>" +
fermiURL + "</baseURL>"
"</computeResource>"
"<computeResource name=\"" +
fermiName + "\">"
"<baseURL>" +
fermiURL + "</baseURL>"
"</computeResource>";
FacilityInfo *fac = NULL;
TS_ASSERT_THROWS_NOTHING(fac = createCRInfoInMinimalFacility(rep));
TS_ASSERT(fac);
TS_ASSERT_EQUALS(fac->computeResources().size(), 3);
TS_ASSERT_EQUALS(fac->computeResInfos().size(), 4);
// compare names
TS_ASSERT(fac->computeResources()[0] == fac->computeResources()[0]);
TS_ASSERT(!(fac->computeResources()[0] == fac->computeResources()[1]));
TS_ASSERT(!(fac->computeResources()[0] == fac->computeResources()[2]));
TS_ASSERT(!(fac->computeResources()[1] == fac->computeResources()[2]));
// compare full comp resource info
TS_ASSERT(fac->computeResInfos()[0] == fac->computeResInfos()[0]);
TS_ASSERT(!(fac->computeResInfos()[0] == fac->computeResInfos()[1]));
TS_ASSERT(!(fac->computeResInfos()[0] == fac->computeResInfos()[2]));
TS_ASSERT(!(fac->computeResInfos()[1] == fac->computeResInfos()[2]));
TS_ASSERT(!(fac->computeResInfos()[2] == fac->computeResInfos()[3]));
TS_ASSERT(fac->computeResInfos()[0] == fac->computeResInfos()[3]);
// compare comp resource info retrieved by names
TS_ASSERT(
!(fac->computeResource(fermiName) == fac->computeResource(otherName)));
TS_ASSERT(
!(fac->computeResource(fermiName) == fac->computeResource(thirdName)));
TS_ASSERT(
!(fac->computeResource(otherName) == fac->computeResource(thirdName)));
delete fac;
}
private:
/// make a minimal facilities file/xml string includin the compute resource
/// passed
FacilityInfo *createCRInfoInMinimalFacility(const std::string &crStr) {
const std::string xmlStr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<facilities>"
" <facility name=\"" +
testFacilityName +
"\" FileExtensions=\".xyz\">" + simpleInstStr +
crStr + " </facility>"
"</facilities>";
return createFacility(xmlStr);
}
FacilityInfo *createFacility(const std::string &xml) {
Poco::XML::DOMParser parser;
Poco::AutoPtr<Poco::XML::Document> pDoc = parser.parseString(xml);
Poco::XML::Element *pRootElem = pDoc->documentElement();
Poco::XML::Element *elem = pRootElem->getChildElement("facility");
return new FacilityInfo(elem);
}
private:
// a minimal instrument to create a facility info
static const std::string simpleInstStr;
// default remote job manager type
static const std::string defaultType;
static const std::string testFacilityName;
static const std::string fermiName;
static const std::string fermiURL;
static const std::string scarfName;
static const std::string scarfURL;
static const std::string scarfType;
};
const std::string ComputeResourceInfoTest::simpleInstStr =
"<instrument name=\"AnInst\">"
" <technique>Measuring Stuff</technique>"
"</instrument>";
const std::string ComputeResourceInfoTest::defaultType =
"MantidWebServiceAPIJobManager";
const std::string ComputeResourceInfoTest::testFacilityName = "ATestFacility";
const std::string ComputeResourceInfoTest::fermiURL =
"https://fermi.ornl.gov/MantidRemote";
const std::string ComputeResourceInfoTest::fermiName = "Fermi";
const std::string ComputeResourceInfoTest::scarfURL =
"https://portal.scarf.rl.ac.uk";
const std::string ComputeResourceInfoTest::scarfName = "SCARF@STFC";
const std::string ComputeResourceInfoTest::scarfType = "SCARFLSFJobManager";
#endif // COMPUTERESOURCEINFOTEST_H_
......@@ -6,7 +6,7 @@
<archiveSearch plugin="ISISDataSearch" />
</archive>
<computeResource name="SCARF@STFC">
<computeResource name="SCARF@STFC" JobManagerType="SCARFLSFJobManager">
<baseURL>https://portal.scarf.rl.ac.uk</baseURL>
</computeResource>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment