Compare commits
11 Commits
Examplar-1
...
Examplar-1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b2225f3e4 | ||
|
|
6af1082852 | ||
|
|
9d5af160c5 | ||
|
|
da50f152f2 | ||
|
|
7404f07dc5 | ||
|
|
a50293a217 | ||
|
|
660745d7d5 | ||
|
|
c37b6e1a9e | ||
|
|
50478d58ed | ||
|
|
109d227166 | ||
|
|
14d526d95c |
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(ftests)
|
||||
project(examplar)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++1z -O0 -DDEBUG=1")
|
||||
set(SOURCE_FILES examplar.cpp src/loaders/loaders.cpp src/loaders/loaders.h src/json/jsoncpp.cpp src/loaders/JSON_Loader.cpp src/loaders/JSON_Loader.h src/loaders/helpers.cpp src/loaders/helpers.h src/loaders/Suite.cpp src/loaders/Suite.h src/loaders/Plan.cpp src/loaders/Plan.h src/loaders/Conf.cpp src/loaders/Conf.h src/loaders/Unit.cpp src/loaders/Unit.h src/loaders/Task.cpp src/loaders/Task.h src/sproc/Sproc.cpp src/sproc/Sproc.h)
|
||||
|
||||
add_executable(ftests ${SOURCE_FILES})
|
||||
add_executable(examplar ${SOURCE_FILES})
|
||||
@@ -2,10 +2,10 @@
|
||||
"units": [
|
||||
{
|
||||
"name": "independent test 1",
|
||||
"target": "/usr/bin/false",
|
||||
"target": "/usr/bin/true",
|
||||
"rectifier": "/usr/bin/true",
|
||||
"active": true,
|
||||
"required": false,
|
||||
"required": true,
|
||||
"rectify": true
|
||||
},
|
||||
{
|
||||
@@ -26,10 +26,10 @@
|
||||
},
|
||||
{
|
||||
"name": "dependent test",
|
||||
"target": "/usr/bin/true",
|
||||
"rectifier": "/usr/bin/false",
|
||||
"target": "/usr/bin/false",
|
||||
"rectifier": "/usr/bin/true",
|
||||
"active": true,
|
||||
"required": false,
|
||||
"required": true,
|
||||
"rectify": true
|
||||
}
|
||||
]
|
||||
|
||||
20
conf/units/dependent_tests.units
Normal file
20
conf/units/dependent_tests.units
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"units": [
|
||||
{
|
||||
"name": "A DEFINITION THAT IS NOT USED",
|
||||
"target": "/usr/bin/dialog --yesno test 50 50",
|
||||
"rectifier": "/usr/bin/false",
|
||||
"active": true,
|
||||
"required": true,
|
||||
"rectify": true
|
||||
},
|
||||
{
|
||||
"name": "dependent test",
|
||||
"target": "/usr/bin/false",
|
||||
"rectifier": "/usr/bin/true",
|
||||
"active": true,
|
||||
"required": true,
|
||||
"rectify": true
|
||||
}
|
||||
]
|
||||
}
|
||||
60
design/Target Execution Flow.txt
Normal file
60
design/Target Execution Flow.txt
Normal file
@@ -0,0 +1,60 @@
|
||||
# Logic Tree for Examplar Task Execution
|
||||
|
||||
Examplar - An automation and testing framework.
|
||||
|
||||
© SURRO INDUSTRIES and Chris Punches, 2017.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
## Key:
|
||||
-Actions are labled by indices in a zero-indexed array 'a'.
|
||||
-Decisions are labeled by indices in a zero-indexed array 'd'.
|
||||
-Decisions have two possible states, TRUE or FALSE (0 or 1 respectively).
|
||||
-Decision determinations are labeled with the decision label and a subspecifier.
|
||||
|
||||
## Diagram:
|
||||
|
||||
a[0] Execute Target
|
||||
d[0] Error Code Check
|
||||
d[0].0 ZERO
|
||||
a[1] NEXT
|
||||
d[0].1 NON-ZERO
|
||||
d[1] Rectify Check
|
||||
d[1].0 FALSE
|
||||
d[2] Required Check
|
||||
d[2].0 FALSE
|
||||
a[2] NEXT
|
||||
d[2].1 TRUE
|
||||
a[3] EXCEPTION
|
||||
d[1].1 TRUE
|
||||
a[4] Execute Rectifier
|
||||
d[3] Error Code Check
|
||||
d[3].1 NON-ZERO
|
||||
d[4] Required Check
|
||||
d[4].0 FALSE
|
||||
a[5] NEXT
|
||||
d[4].1 TRUE
|
||||
a[6] EXCEPTION
|
||||
d[3].0 ZERO
|
||||
a[7] Re-Execute Target
|
||||
d[5] Error Code Check
|
||||
d[5].0 ZERO
|
||||
a[8] NEXT
|
||||
d[5].1 NON-ZERO
|
||||
d[6] Required Check
|
||||
d[6].0 FALSE
|
||||
a[9] NEXT
|
||||
d[6].1 TRUE
|
||||
a[10] EXCEPTION
|
||||
|
||||
65
examplar.cpp
65
examplar.cpp
@@ -17,17 +17,65 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "src/json/json.h"
|
||||
#include "src/loaders/loaders.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
int main( )
|
||||
/*
|
||||
* TODO Commandline switches
|
||||
*/
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
bool verbose = true;
|
||||
printf("examplar [ -h ] [ -v ] [ -c CONFIG_PATH ]");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main( int argc, char * argv[] )
|
||||
{
|
||||
int flags, opt;
|
||||
bool verbose = false;
|
||||
bool show_help = false;
|
||||
std::string config_path = "/etc/Examplar/config.json";
|
||||
|
||||
// commandline switches:
|
||||
// -h help
|
||||
// -v verbose
|
||||
// -c CONFIG_FILE_PATH -- defaults to '/etc/Examplar/config.json'
|
||||
|
||||
while ( ( opt = getopt( argc, argv, "hvc:" ) ) != -1 )
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
case 'h':
|
||||
show_help = true;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
case 'c':
|
||||
config_path = std::string(optarg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( show_help == true )
|
||||
{
|
||||
print_usage();
|
||||
}
|
||||
|
||||
setlogmask( LOG_UPTO( LOG_INFO ) );
|
||||
|
||||
openlog( "Examplar", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_PERROR | LOG_LOCAL1 );
|
||||
|
||||
// A Plan is made up of Tasks, and a Suite is made up of Units.
|
||||
// A Plan declares what units are executed and a Suite declares the definitions of those units.
|
||||
Conf configuration = Conf("/home/phanes/development/internal/Examplar/conf/config.json", verbose );
|
||||
Conf configuration = Conf(config_path, verbose );
|
||||
|
||||
// load the configuration file which contains filepaths to definitions of a plan and definitions of units.
|
||||
std::string definitions_file = configuration.get_units_path();
|
||||
@@ -43,12 +91,19 @@ int main( )
|
||||
|
||||
std::cout << "Ready to execute all tasks in Plan." << std::endl;
|
||||
|
||||
try {
|
||||
try
|
||||
{
|
||||
plan.execute( verbose );
|
||||
}
|
||||
catch ( std::exception& e) {
|
||||
|
||||
catch ( std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
syslog( LOG_ERR, e.what() );
|
||||
closelog();
|
||||
return 1;
|
||||
}
|
||||
|
||||
closelog();
|
||||
return 0;
|
||||
}
|
||||
@@ -19,13 +19,52 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Suite.h"
|
||||
#include <dirent.h>
|
||||
|
||||
/// Suite_InvalidUnitMember - Exception thrown when a Suite tries to access a contained Unit's value that is not
|
||||
/// present in the Unit.
|
||||
class Suite_InvalidUnitMember: public std::runtime_error { public:
|
||||
// TODO rework this to accept the name of the member not able to be fetched.
|
||||
Suite_InvalidUnitMember(): std::runtime_error("Suite: Attempted to access a member of a Unit that is not set.") {}
|
||||
class SuiteException: public std::exception
|
||||
{
|
||||
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 SuiteException(const char* message):
|
||||
msg_(message)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor (C++ STL strings).
|
||||
* @param message The error message.
|
||||
*/
|
||||
explicit SuiteException(const std::string& message):
|
||||
msg_(message)
|
||||
{}
|
||||
|
||||
/** Destructor.
|
||||
* Virtual to allow for subclassing.
|
||||
*/
|
||||
virtual ~SuiteException() 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_;
|
||||
};
|
||||
|
||||
|
||||
@@ -42,20 +81,88 @@ class Suite_InvalidUnitMember: public std::runtime_error { public:
|
||||
/// if the implementor so desires.
|
||||
Suite::Suite(): JSON_Loader() {};
|
||||
|
||||
|
||||
bool is_file( std::string path)
|
||||
{
|
||||
struct stat buf;
|
||||
stat( path.c_str(), &buf );
|
||||
return S_ISREG(buf.st_mode);
|
||||
}
|
||||
|
||||
bool is_dir( std::string path )
|
||||
{
|
||||
struct stat buf;
|
||||
stat( path.c_str(), &buf );
|
||||
return S_ISDIR(buf.st_mode);
|
||||
}
|
||||
|
||||
void get_units_from_dir( std::vector<std::string> * files, std::string path )
|
||||
{
|
||||
DIR* dirFile = opendir( path.c_str() );
|
||||
if ( dirFile )
|
||||
{
|
||||
std::string entry;
|
||||
|
||||
struct dirent* hFile;
|
||||
errno = 0;
|
||||
while (( hFile = readdir( dirFile )) != NULL )
|
||||
{
|
||||
if ( !strcmp( hFile->d_name, "." )) continue;
|
||||
if ( !strcmp( hFile->d_name, ".." )) continue;
|
||||
|
||||
// hidden files
|
||||
if ( hFile->d_name[0] == '.' ) continue;
|
||||
|
||||
// dirFile.name is the name of the file. Do whatever string comparison
|
||||
// you want here. Something like:
|
||||
if ( strstr( hFile->d_name, ".units" ))
|
||||
{
|
||||
std::string full_path = path + hFile->d_name;
|
||||
files->push_back( full_path );
|
||||
}
|
||||
}
|
||||
closedir( dirFile );
|
||||
} else {
|
||||
std::cout << "file not found" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Suite::load_units_file - Uses the json_root buffer on each run to append intact Units as they're
|
||||
/// deserialized from the provided file.
|
||||
///
|
||||
/// \param filename - The file to pull the JSON-formatted units from.
|
||||
/// \param units_path - The file to pull the JSON-formatted units from.
|
||||
/// \param verbose - Whether to print verbose output to STDOUT.
|
||||
void Suite::load_units_file( std::string filename, bool verbose )
|
||||
void Suite::load_units_file( std::string units_path, bool verbose )
|
||||
{
|
||||
std::vector<std::string> unit_files;
|
||||
|
||||
if ( is_dir( units_path ) )
|
||||
{
|
||||
// we have a directory path. find all files ending in *.units and load them into a vector<std::string>
|
||||
get_units_from_dir( &unit_files, units_path );
|
||||
}
|
||||
|
||||
if ( is_file( units_path ) )
|
||||
{
|
||||
unit_files.push_back( units_path );
|
||||
}
|
||||
|
||||
std::ostringstream infostring;
|
||||
infostring << "Unit files found: " << unit_files.size() << std::endl;
|
||||
syslog(LOG_INFO, infostring.str().c_str() );
|
||||
std::cerr << infostring.str();
|
||||
|
||||
for ( int i = 0; i < unit_files.size(); i++ )
|
||||
{
|
||||
// will use json_root buffer on each run to append to this->units vector as valid units are found.
|
||||
this->load_json_file( filename, verbose );
|
||||
this->load_json_file( unit_files[i], verbose );
|
||||
|
||||
// staging buffer
|
||||
Json::Value jbuff;
|
||||
|
||||
// fill the jbuff staging buffer with a json::value object in the supplied filename
|
||||
// fill the jbuff staging buffer with a json::value object in the supplied units_path
|
||||
if ( this->get_serialized( jbuff, "units", verbose ) == 0)
|
||||
{
|
||||
this->json_root = jbuff;
|
||||
@@ -72,10 +179,17 @@ void Suite::load_units_file( std::string filename, bool verbose )
|
||||
// append to this->units
|
||||
this->units.push_back( tmp_U );
|
||||
if ( verbose ) {
|
||||
std::cout << "Added unit \"" << tmp_U.get_name() << "\" to Suite." << std::endl;
|
||||
std::ostringstream infostring;
|
||||
infostring << "Added unit \"" << tmp_U.get_name() << "\" to Suite." << std::endl;
|
||||
syslog(LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// Suite::get_unit - returns a contained Unit identified by name attribute.
|
||||
@@ -99,8 +213,11 @@ void Suite::get_unit(Unit & result, std::string provided_name)
|
||||
|
||||
if (! foundMatch )
|
||||
{
|
||||
std::cerr << "Unit name \"" << provided_name << "\" was referenced but not defined!" << std::endl;
|
||||
throw Suite_InvalidUnitMember();
|
||||
std::ostringstream infostring;
|
||||
infostring << "Unit name \"" << provided_name << "\" was referenced but not defined!" << std::endl;
|
||||
syslog(LOG_ERR, infostring.str().c_str() );
|
||||
std::cerr << infostring.str();
|
||||
throw SuiteException( infostring.str() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
#include "Unit.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class Suite: public JSON_Loader
|
||||
{
|
||||
protected:
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "Task.h"
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include "../sproc/Sproc.h"
|
||||
|
||||
/// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON.
|
||||
@@ -35,18 +36,49 @@ public:
|
||||
Task_NotReady(): std::runtime_error("Task: Attempted to access a unit of a Task that is not defined.") {}
|
||||
};
|
||||
|
||||
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed.
|
||||
class Task_RequiredButFailedTask: public std::runtime_error {
|
||||
|
||||
/// Task_RequiredButFailedTask - Exception thrown when a Task fails but should not.
|
||||
class TaskException: public std::exception
|
||||
{
|
||||
public:
|
||||
Task_RequiredButFailedTask(): std::runtime_error("Task: Attempted to execute a Task that failed and was required.") {}
|
||||
/** 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 TaskException(const char* message):
|
||||
msg_(message)
|
||||
{
|
||||
}
|
||||
|
||||
/** Constructor (C++ STL strings).
|
||||
* @param message The error message.
|
||||
*/
|
||||
explicit TaskException(const std::string& message):
|
||||
msg_(message)
|
||||
{}
|
||||
|
||||
/** Destructor.
|
||||
* Virtual to allow for subclassing.
|
||||
*/
|
||||
virtual ~TaskException() 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_;
|
||||
};
|
||||
|
||||
/// Task_RequiredButFailedTask - Exception thrown when a Task is failed but required, and rectification also failed but
|
||||
/// returned with a zero exit code (dont try to fool the check).
|
||||
class Task_RequiredButRectifierDoesNotHeal: public std::runtime_error {
|
||||
public:
|
||||
Task_RequiredButRectifierDoesNotHeal(): std::runtime_error("Task: The rectification script was executed and reported success, but did not actually heal the faulty condition of the Task target.") {}
|
||||
};
|
||||
|
||||
/// Task::Task() - Constructor for the Task class. The Task is the building block of a Plan indicating of which Unit to
|
||||
/// execute, and its dependencies on other units to have already been completed successfully.
|
||||
@@ -81,8 +113,12 @@ void Task::load_root(Json::Value loader_root, bool verbose )
|
||||
if ( des_dep_root[i].asString() != "" ) {
|
||||
this->dependencies.push_back( des_dep_root[i].asString() );
|
||||
if ( verbose ) {
|
||||
std::cout << "Added dependency \"" << des_dep_root[i].asString()
|
||||
<< "\" to task \"" << this->get_name() << "\"." << std::endl;
|
||||
std::ostringstream infostring;
|
||||
infostring << "Added dependency \"" << des_dep_root[i].asString() << "\" to task \""
|
||||
<< this->get_name() << "\"." << std::endl;
|
||||
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,8 +138,12 @@ void Task::load_definition( Unit selected_unit, bool verbose )
|
||||
{
|
||||
this->definition = selected_unit;
|
||||
if ( verbose ) {
|
||||
std::cout << "Loaded definition \"" << selected_unit.get_name() << "\" for task \""
|
||||
std::ostringstream infostring;
|
||||
infostring << "Loaded definition \"" << selected_unit.get_name() << "\" for task \""
|
||||
<< this->get_name() << "\"." << std::endl;
|
||||
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
}
|
||||
this->defined = true;
|
||||
}
|
||||
@@ -134,16 +174,24 @@ bool Task::has_definition()
|
||||
return this->defined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Task::execute - execute a task's unit definition.
|
||||
/// See the design document for what flow control needs to look like here.
|
||||
/// \param verbose - Verbosity level - not implemented yet.
|
||||
void Task::execute( bool verbose )
|
||||
{
|
||||
// DUFFING - If Examplar is broken it's probably going to be in this block.
|
||||
// Somebody come clean this up, eh?
|
||||
|
||||
// PREWORK
|
||||
// throw if unit not coupled to all necessary values since Task is stateful (yes, stateful is okay)
|
||||
if (! this->has_definition() ) {
|
||||
std::ostringstream infostring;
|
||||
if ( ! this->has_definition() )
|
||||
{
|
||||
throw Task_NotReady();
|
||||
}
|
||||
|
||||
@@ -156,81 +204,209 @@ void Task::execute( bool verbose )
|
||||
std::string target_command = this->definition.get_target();
|
||||
|
||||
// if we're in verbose mode, do some verbose things
|
||||
if ( verbose ) {
|
||||
std::cout << "\tUsing unit \"" << task_name << "\"." << std::endl;
|
||||
std::cout << "\tExecuting target \"" << target_command << "\"." << std::endl;
|
||||
if ( verbose )
|
||||
{
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tUsing unit \"" << task_name << "\"." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
|
||||
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tExecuting target \"" << target_command << "\"." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
}
|
||||
|
||||
// execute target
|
||||
// a[0] execute target
|
||||
int return_code = Sproc::execute( target_command );
|
||||
|
||||
// d[0] check exit code of target
|
||||
if (return_code == 0) {
|
||||
// Zero d[0] return from target execution, good to return
|
||||
// **********************************************
|
||||
// d[0] Error Code Check
|
||||
// **********************************************
|
||||
if ( return_code == 0 )
|
||||
{
|
||||
// d[0].0 ZERO
|
||||
|
||||
if ( verbose ) {
|
||||
std::cout << "\tTarget " << task_name << " succeeded." << std::endl;
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tTarget " << task_name << " succeeded. Marking as complete." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
}
|
||||
this->mark_complete();
|
||||
// next
|
||||
} else {
|
||||
// Non-Zero d[0] from initial target execution, get to d[1]
|
||||
std::cout << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl;
|
||||
|
||||
// check if rectify pattern is enabled d[1]
|
||||
if ( this->definition.get_rectify() ) {
|
||||
// yes d[1]
|
||||
std::cout << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl;
|
||||
// execute RECTIFIER
|
||||
// a[1] NEXT
|
||||
return;
|
||||
}
|
||||
|
||||
if ( return_code != 0 )
|
||||
{
|
||||
// d[0].1 NON-ZERO
|
||||
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tTarget \"" << task_name << "\" failed with exit code " << return_code << "." << std::endl;
|
||||
|
||||
syslog(LOG_ERR, infostring.str().c_str() );
|
||||
std::cerr << infostring.str();
|
||||
|
||||
// **********************************************
|
||||
// d[1] Rectify Check
|
||||
// **********************************************
|
||||
if (! this->definition.get_rectify() )
|
||||
{
|
||||
// d[1].0 FALSE
|
||||
|
||||
// **********************************************
|
||||
// d[2] Required Check
|
||||
// **********************************************
|
||||
if (! this->definition.get_required() )
|
||||
{
|
||||
// d[2].0 FALSE
|
||||
// a[2] NEXT
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl;
|
||||
syslog(LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this->definition.get_required() )
|
||||
{
|
||||
// d[2].1 TRUE
|
||||
// a[3] EXCEPTION
|
||||
throw TaskException("Task \"" + task_name + "\" is required, and failed, and rectification is not enabled.");
|
||||
}
|
||||
// **********************************************
|
||||
// end - d[2] Required Check
|
||||
// **********************************************
|
||||
}
|
||||
|
||||
|
||||
if ( this->definition.get_rectify() )
|
||||
{
|
||||
// d[1].1 TRUE (Rectify Check)
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tRectification pattern is enabled for \"" << task_name << "\"." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
|
||||
// a[4] Execute RECTIFIER
|
||||
std::string rectifier_command = this->definition.get_rectifier();
|
||||
std::cout << "\tExecuting rectification: " << rectifier_command << "." << std::endl;
|
||||
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tExecuting rectification: " << rectifier_command << "." << std::endl;
|
||||
syslog(LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
|
||||
int rectifier_error = Sproc::execute( rectifier_command );
|
||||
|
||||
// d[3] check exit code of rectifier
|
||||
if (rectifier_error) {
|
||||
//d[3] non-zero
|
||||
|
||||
std::cout << "\tRectification of \"" << task_name << "\" failed with exit code "
|
||||
// **********************************************
|
||||
// d[3] Error Code Check for Rectifier
|
||||
// **********************************************
|
||||
if ( rectifier_error != 0 )
|
||||
{
|
||||
// d[3].1 Non-Zero
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tRectification of \"" << task_name << "\" failed with exit code "
|
||||
<< rectifier_error << "." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
|
||||
// d[2] check if REQUIRED
|
||||
if ( this->definition.get_required() ) {
|
||||
// d[2] yes
|
||||
// halt/exception
|
||||
throw Task_RequiredButFailedTask();
|
||||
}
|
||||
// d[2] no
|
||||
// next
|
||||
}
|
||||
// d[3] zero
|
||||
std::cout << infostring.str();
|
||||
|
||||
// **********************************************
|
||||
// d[4] Required Check
|
||||
// **********************************************
|
||||
if ( ! this->definition.get_required() ) {
|
||||
// d[4].0 FALSE
|
||||
// a[5] NEXT
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl;
|
||||
syslog(LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this->definition.get_required() )
|
||||
{
|
||||
// d[4].1 TRUE
|
||||
// a[6] EXCEPTION
|
||||
throw TaskException("Task \"" + task_name + "\" is required, and failed, then rectified but rectification failed.");
|
||||
}
|
||||
// **********************************************
|
||||
// end - d[4] Required Check
|
||||
// **********************************************
|
||||
}
|
||||
|
||||
// d[3] check exit code of rectifier
|
||||
if ( rectifier_error == 0 )
|
||||
{
|
||||
// d[3].0 Zero
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tRectification returned successfully." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
|
||||
// a[7] Re-execute Target
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tRe-Executing target \"" << this->definition.get_target() << "\"." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
|
||||
// execute target
|
||||
std::cout << "\tRe-Executing target \"" << this->definition.get_target() << "\"." << std::endl;
|
||||
int retry_code = Sproc::execute( target_command );
|
||||
|
||||
// d[4] exit code of target retry
|
||||
if (retry_code == 0) {
|
||||
// d[4] zero
|
||||
// **********************************************
|
||||
// d[5] Error Code Check
|
||||
// **********************************************
|
||||
if ( retry_code == 0 )
|
||||
{
|
||||
// d[5].0 ZERO
|
||||
// a[8] NEXT
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tRe-execution was successful." << std::endl;
|
||||
syslog( LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
return;
|
||||
}
|
||||
// d[4] non-zero
|
||||
// d[5] required check
|
||||
if ( this->definition.get_required() ) {
|
||||
// d[5] yes
|
||||
std::cout << "\tTask \"" << task_name << "\" is required but rectification did not heal." << std::endl;
|
||||
throw Task_RequiredButRectifierDoesNotHeal();
|
||||
|
||||
if ( retry_code != 0 )
|
||||
{
|
||||
// d[5].1 NON-ZERO
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tRe-execution failed with exit code " << retry_code << "." << std::endl;
|
||||
syslog(LOG_ERR, infostring.str().c_str() );
|
||||
std::cerr << infostring.str();
|
||||
|
||||
// **********************************************
|
||||
// d[6] Required Check
|
||||
// **********************************************
|
||||
if ( ! this->definition.get_required() )
|
||||
{
|
||||
// d[6].0 FALSE
|
||||
// a[9] NEXT
|
||||
infostring = std::ostringstream();
|
||||
infostring << "\tThis task is not required to continue the plan. Moving on." << std::endl;
|
||||
syslog(LOG_INFO, infostring.str().c_str() );
|
||||
std::cout << infostring.str();
|
||||
|
||||
return;
|
||||
}
|
||||
// d[5] no
|
||||
// next
|
||||
|
||||
if ( this->definition.get_required() )
|
||||
{
|
||||
// d[6].1 TRUE
|
||||
// a[10] EXCEPTION
|
||||
throw TaskException("Task \"" + task_name + "\" is required, and failed, then rectified but rectifier did not heal the condition causing the target to fail. Cannot proceed with Plan.");
|
||||
}
|
||||
// no d[1]
|
||||
std::cout << "\tRectification is not enabled for \"" << task_name << "\"." << std::endl;
|
||||
// required d[2]
|
||||
if ( this->definition.get_required() ) {
|
||||
// d[2] yes
|
||||
// This is executing.....
|
||||
std::cout << "\tThis task is required to continue the plan." << std::endl;
|
||||
// but these are NOT executing?????
|
||||
throw Task_RequiredButFailedTask();
|
||||
} // d[2] no
|
||||
std::cout << "\tThis task is not required to continue the plan." << std::endl;
|
||||
// **********************************************
|
||||
// end - d[6] Required Check
|
||||
// **********************************************
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// **********************************************
|
||||
// end d[1] Rectify Check
|
||||
// **********************************************
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
class Task
|
||||
{
|
||||
|
||||
protected:
|
||||
// the name of this task
|
||||
std::string name;
|
||||
|
||||
Reference in New Issue
Block a user