implemented execution context. needs thoroughly tested.

master
Phanes 2017-12-07 22:37:42 -05:00
parent 9d89f5ad6a
commit 46e56b8d6f
10 changed files with 196 additions and 36 deletions

View File

@ -1,5 +1,7 @@
{ {
"units_path": "/home/phanes/development/internal/Examplar/conf/units/all_test.units", "execution_context_override": true,
"plan_path": "/home/phanes/development/internal/Examplar/conf/plans/test.plan", "execution_context": "/home/phanes/development/internal/Examplar/conf/",
"config_version": "1" "units_path": "units/all_test.units",
"plan_path": "plans/test.plan",
"config_version": "2"
} }

View File

@ -23,8 +23,8 @@
#include "src/loaders/loaders.h" #include "src/loaders/loaders.h"
#include <unistd.h> #include <unistd.h>
#include <getopt.h> #include <getopt.h>
#include <syslog.h> #include <syslog.h>
#include "src/loaders/helpers.h"
/* /*
* TODO Commandline switches * TODO Commandline switches
@ -32,34 +32,45 @@
void print_usage() void print_usage()
{ {
printf("examplar [ -h | --help ] [ -v | --verbose ] [ -c | --config CONFIG_PATH ]\n\n"); printf("examplar [ -h | --help ] [ -v | --verbose ] [ -e | --execution-context EXECUTION_CONTEXT ][ -c | --config CONFIG_PATH ]\n\n");
} }
int main( int argc, char * argv[] ) int main( int argc, char * argv[] )
{ {
int flags, opt; int flags, opt;
bool verbose = false; bool verbose = false;
bool show_help = false; bool show_help = false;
// indicator of whether examplar should use a commandline argument for overriding the context
// instead of what's supplied in the conf file
bool cli_context_supplied = false;
std::string config_path = "/etc/Examplar/config.json"; std::string config_path = "/etc/Examplar/config.json";
std::string execution_context;
// commandline switches: // commandline switches:
// -h help // -h help
// -v verbose // -v verbose
// -c CONFIG_FILE_PATH -- defaults to '/etc/Examplar/config.json' // -c CONFIG_FILE_PATH -- defaults to '/etc/Examplar/config.json'
// -e EXECUTION_CONTEXT -- current working directory when executing unit targets
while (1) while (1)
{ {
static struct option long_options[] = static struct option long_options[] =
{ {
{"verbose", no_argument, 0, 'v'}, {"verbose", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"config", required_argument, 0, 'c'}, {"config", required_argument, 0, 'c'},
{"execution-context", required_argument, 0, 'e'},
{0, 0} {0, 0}
}; };
int option_index = 0; int option_index = 0;
opt = getopt_long (argc, argv, "vhc:", opt = getopt_long (argc, argv, "vhec:", long_options, &option_index);
long_options, &option_index);
if (opt == -1) if (opt == -1)
break; break;
@ -80,6 +91,10 @@ int main( int argc, char * argv[] )
case '?': case '?':
print_usage(); print_usage();
exit(1); exit(1);
case 'e':
cli_context_supplied = true;
execution_context = std::string(optarg);
break;
default: default:
break; break;
} }
@ -99,14 +114,33 @@ int main( int argc, char * argv[] )
// A Plan declares what units are executed and a Suite declares the definitions of those units. // A Plan declares what units are executed and a Suite declares the definitions of those units.
Conf configuration = Conf(config_path, verbose ); Conf configuration = Conf(config_path, verbose );
// load the configuration file which contains filepaths to definitions of a plan and definitions of units. // if the user set this option as a commandline argument
if ( cli_context_supplied == true )
{
// override the conf file's specified execution context
configuration.set_execution_context( execution_context );
}
// check if context override
if ( configuration.has_context_override() )
{
// if so, set the CWD.
chdir( configuration.get_execution_context().c_str() );
std::ostringstream infostring;
infostring << "Execution context: " << get_working_path() << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
}
// load the filepaths to definitions of a plan and definitions of units.
std::string definitions_file = configuration.get_units_path(); std::string definitions_file = configuration.get_units_path();
std::string plan_file = configuration.get_plan_path(); std::string plan_file = configuration.get_plan_path();
Suite available_definitions; Suite available_definitions;
available_definitions.load_units_file( definitions_file, verbose ); available_definitions.load_units_file( definitions_file, verbose );
Plan plan; Plan plan( &configuration );
plan.load_plan_file( plan_file, verbose ); plan.load_plan_file( plan_file, verbose );
plan.load_definitions( available_definitions, verbose ); plan.load_definitions( available_definitions, verbose );

View File

@ -19,17 +19,48 @@
*/ */
#include "Conf.h" #include "Conf.h"
/// CONF_PLANPATH_INVALID - Exception thrown when the Conf type can not load the supplied path for the Plan definition /// ConfigLoadException - General exception handler for the Conf class.
/// file. class ConfigLoadException: public std::exception
class CONF_PLANPATH_INVALID: public std::runtime_error { public: {
CONF_PLANPATH_INVALID(): std::runtime_error("conf: The supplied path for the plan definition file is invalid.") {} public:
/** Constructor (C strings).
* @param message C-style string error message.
* The string contents are copied upon construction.
* Hence, responsibility for deleting the char* lies
* with the caller.
*/
explicit ConfigLoadException(const char* message):
msg_(message)
{
}
/** Constructor (C++ STL strings).
* @param message The error message.
*/
explicit ConfigLoadException(const std::string& message):
msg_(message)
{}
/** Destructor.
* Virtual to allow for subclassing.
*/
virtual ~ConfigLoadException() throw (){}
/** Returns a pointer to the (constant) error description.
* @return A pointer to a const char*. The underlying memory
* is in posession of the Exception object. Callers must
* not attempt to free the memory.
*/
virtual const char* what() const throw (){
return msg_.c_str();
}
protected:
/** Error message.
*/
std::string msg_;
}; };
/// CONF_UNITSPATH_INVALID - Exception thrown when the Conf type can not load the supplied path for the Unit definition
/// files.
class CONF_UNITSPATH_INVALID: public std::runtime_error { public:
CONF_UNITSPATH_INVALID(): std::runtime_error("conf: The supplied path for the unit definition file is invalid.") {}
};
/// Conf::Conf - Constructor for Conf type. Loads the configuration for the application. /// Conf::Conf - Constructor for Conf type. Loads the configuration for the application.
/// TODO Expand to detect when a directory path is supplied for units_path or plan_path and import all Tasks and Units. /// TODO Expand to detect when a directory path is supplied for units_path or plan_path and import all Tasks and Units.
@ -37,18 +68,67 @@ class CONF_UNITSPATH_INVALID: public std::runtime_error { public:
/// \param filename - The filename to load the configuration from. /// \param filename - The filename to load the configuration from.
Conf::Conf( std::string filename, bool verbose ): JSON_Loader() Conf::Conf( std::string filename, bool verbose ): JSON_Loader()
{ {
// prepare context spaghetti
this->override_context = false;
// load the conf file. // load the conf file.
this->load_json_file( filename, verbose ); this->load_json_file( filename, verbose );
if (this->get_serialized(this->config_version, "config_version" ,true) != 0)
{
throw ConfigLoadException("config_version string is not set in the config file supplied: " + filename);
}
if ( this->config_version.asString() != VERSION_STRING )
{
throw ConfigLoadException("config_version string expected was " + std::string(VERSION_STRING) + " in: " + filename);
}
// find the path to the plan file // find the path to the plan file
if (this->get_serialized(this->plan_path, "plan_path", true) != 0 ) { throw CONF_PLANPATH_INVALID(); } if (this->get_serialized(this->plan_path, "plan_path", true) != 0 )
{
throw ConfigLoadException("plan_path string is not set in the config file supplied:" + filename);
}
// find the path to the unit definitions file // find the path to the unit definitions file
if (this->get_serialized(this->units_path, "units_path", true) != 0 ) { throw CONF_UNITSPATH_INVALID(); } if (this->get_serialized(this->units_path, "units_path", true) != 0 )
{
throw ConfigLoadException("units_path string is not set in the config file supplied: " + filename);
}
if ( this->get_serialized(this->override_execution_context, "execution_context_override", true) != 0 )
{
throw ConfigLoadException("execution_context_override boolean is not set in the config file supplied: " + filename);
} else {
this->override_context = true;
}
if ( this->get_serialized(this->execution_context, "execution_context", true) != 0 )
{
throw ConfigLoadException("execution_context string is not set in the config file supplied: " + filename);
} else {
this->execution_context_literal = this->execution_context.asString();
}
}; };
/// Conf::has_context_override - Specifies whether or not the override context function is enabled in the conf file.
bool Conf::has_context_override() {
return this->override_execution_context.asBool();
}
/// Conf::get_execution_context - Specifies the path to the current working directory to set for all unit executions.
std::string Conf::get_execution_context() {
return this->execution_context_literal;
}
/// Conf::get_plan_path - Retrieves the path to the Plan definition file from the application configuration file. /// Conf::get_plan_path - Retrieves the path to the Plan definition file from the application configuration file.
std::string Conf::get_plan_path() { return this->plan_path.asString(); } std::string Conf::get_plan_path() { return this->plan_path.asString(); }
/// Conf::get_units_path - Retrieves the path to the Unit definition file from the application configuration file. /// Conf::get_units_path - Retrieves the path to the Unit definition file from the application configuration file.
std::string Conf::get_units_path() { return this->units_path.asString(); } std::string Conf::get_units_path() { return this->units_path.asString(); }
/// Conf::set_execution_context- Sets the execution context.
void Conf::set_execution_context( std::string execution_context )
{
this->execution_context_literal = execution_context;
}

View File

@ -21,17 +21,40 @@
#ifndef FTESTS_CONF_H #ifndef FTESTS_CONF_H
#define FTESTS_CONF_H #define FTESTS_CONF_H
#include "JSON_Loader.h" #include "JSON_Loader.h"
#include <exception>
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
# define IMPL_CONFIG_VERSION 2
# define VERSION_STRING STRINGIZE(IMPL_CONFIG_VERSION)
class Conf: public JSON_Loader class Conf: public JSON_Loader
{ {
private: private:
Json::Value plan_path; Json::Value plan_path;
Json::Value units_path; Json::Value units_path;
Json::Value execution_context;
Json::Value config_version;
// flag to indicate if execution context should be overriden in config file
// if set to true Examplar should use whats in the config file for current working directory
// if set to false, Examplar should use the current working directory at time of execution
Json::Value override_execution_context;
bool override_context;
std::string execution_context_literal;
public: public:
Conf( std::string filename, bool verbose ); Conf( std::string filename, bool verbose );
std::string get_plan_path(); std::string get_plan_path();
std::string get_units_path(); std::string get_units_path();
bool has_context_override();
std::string get_execution_context();
void set_execution_context( std::string );
}; };
#endif //FTESTS_CONF_H #endif //FTESTS_CONF_H

View File

@ -120,7 +120,10 @@ protected:
/// Plan::Plan() - Constructor for Plan class. A Plan is a managed container for a Task vector. These tasks reference /// Plan::Plan() - Constructor for Plan class. A Plan is a managed container for a Task vector. These tasks reference
/// Units that are defined in the Units files (Suite). If Units are definitions, Tasks are selections of those /// Units that are defined in the Units files (Suite). If Units are definitions, Tasks are selections of those
/// definitions to execute, and if Units together form a Suite, Tasks together form a Plan. /// definitions to execute, and if Units together form a Suite, Tasks together form a Plan.
Plan::Plan(): JSON_Loader() {}; Plan::Plan( Conf * configuration ): JSON_Loader()
{
this->configuration = configuration;
};
/// Plan::load_plan_file - Uses the json_root buffer on each run to append intact Units as they're deserialized from /// Plan::load_plan_file - Uses the json_root buffer on each run to append intact Units as they're deserialized from
/// the provided file. /// the provided file.
@ -259,7 +262,7 @@ void Plan::execute( bool verbose )
std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl; std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl;
} }
try { try {
this->tasks[i].execute( verbose ); this->tasks[i].execute( this->configuration, verbose );
} }
catch (std::exception& e) { catch (std::exception& e) {
throw Plan_Task_GeneralExecutionException( "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() ); throw Plan_Task_GeneralExecutionException( "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() );

View File

@ -25,15 +25,17 @@
#include "../json/json.h" #include "../json/json.h"
#include "JSON_Loader.h" #include "JSON_Loader.h"
#include "Task.h" #include "Task.h"
#include "Conf.h"
class Plan: public JSON_Loader class Plan: public JSON_Loader
{ {
private: private:
// storage for the tasks that make up the plan // storage for the tasks that make up the plan
std::vector<Task> tasks; std::vector<Task> tasks;
Conf * configuration;
public: public:
Plan(); Plan( Conf * configuration );
// append this->tasks from JSON file // append this->tasks from JSON file
void load_plan_file( std::string filename, bool verbose ); void load_plan_file( std::string filename, bool verbose );

View File

@ -19,10 +19,10 @@
*/ */
#include "Task.h" #include "Task.h"
#include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <syslog.h> #include <syslog.h>
#include "../sproc/Sproc.h" #include "../sproc/Sproc.h"
#include "helpers.h"
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON. /// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
class Task_InvalidDataStructure: public std::runtime_error { class Task_InvalidDataStructure: public std::runtime_error {
@ -174,15 +174,10 @@ bool Task::has_definition()
return this->defined; return this->defined;
} }
/// Task::execute - execute a task's unit definition. /// Task::execute - execute a task's unit definition.
/// See the design document for what flow control needs to look like here. /// See the design document for what flow control needs to look like here.
/// \param verbose - Verbosity level - not implemented yet. /// \param verbose - Verbosity level - not implemented yet.
void Task::execute( bool verbose ) void Task::execute( Conf * configuration, bool verbose )
{ {
// DUFFING - If Examplar is broken it's probably going to be in this block. // DUFFING - If Examplar is broken it's probably going to be in this block.
// Somebody come clean this up, eh? // Somebody come clean this up, eh?
@ -199,18 +194,28 @@ void Task::execute( bool verbose )
std::string task_name = this->definition.get_name(); std::string task_name = this->definition.get_name();
// END PREWORK // END PREWORK
// get the target execution command // get the target execution command
std::string target_command = this->definition.get_target(); std::string target_command = this->definition.get_target();
// if we're in verbose mode, do some verbose things // if we're in verbose mode, do some verbose things
if ( verbose ) if ( verbose )
{ {
infostring = std::ostringstream(); infostring = std::ostringstream();
infostring << "\tUsing unit \"" << task_name << "\"." << std::endl; infostring << "\tUsing unit \"" << task_name << "\"." << std::endl;
syslog( LOG_INFO, infostring.str().c_str() ); syslog( LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str(); std::cout << infostring.str();
// check if context override
if ( configuration->has_context_override() )
{
// if so, set the CWD.
chdir( configuration->get_execution_context().c_str() );
infostring = std::ostringstream();
infostring << "\tExecution context: " << get_working_path() << std::endl;
syslog(LOG_INFO, infostring.str().c_str() );
std::cout << infostring.str();
}
infostring = std::ostringstream(); infostring = std::ostringstream();
infostring << "\tExecuting target \"" << target_command << "\"." << std::endl; infostring << "\tExecuting target \"" << target_command << "\"." << std::endl;

View File

@ -21,9 +21,11 @@
#ifndef FTESTS_TASK_H #ifndef FTESTS_TASK_H
#define FTESTS_TASK_H #define FTESTS_TASK_H
#include <string> #include <string>
#include <unistd.h>
#include "../json/json.h" #include "../json/json.h"
#include "Unit.h" #include "Unit.h"
#include "Suite.h" #include "Suite.h"
#include "Conf.h"
class Task class Task
{ {
@ -62,7 +64,7 @@ class Task
std::string get_name(); std::string get_name();
// execute this task's definition // execute this task's definition
void execute( bool verbose ); void execute( Conf * configuration, bool verbose );
void mark_complete(); void mark_complete();

View File

@ -24,4 +24,10 @@ bool exists(const std::string& name)
{ {
struct stat buffer; struct stat buffer;
return (stat (name.c_str(), &buffer) == 0); return (stat (name.c_str(), &buffer) == 0);
}
std::string get_working_path()
{
char temp[MAXPATHLEN];
return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") );
} }

View File

@ -22,9 +22,12 @@
#define FTESTS_HELPERS_H #define FTESTS_HELPERS_H
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
bool exists (const std::string& name); bool exists (const std::string& name);
std::string get_working_path();
#endif //FTESTS_HELPERS_H #endif //FTESTS_HELPERS_H