From 361ab7fcc87aaf6dd11aa7f13d88edb8da799e0d Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Mon, 19 Jun 2017 10:07:37 -0400 Subject: [PATCH 1/8] Added ability to launch Docker images from GPP --- GPP/GPP.prf.xml | 8 +- GPP/cpp/GPP.cpp | 189 +++++++++++++++++++++++++++++----------- GPP/cpp/GPP.h | 4 +- GPP/cpp/GPP_base.cpp | 8 ++ GPP/cpp/GPP_base.h | 1 + GPP/cpp/Makefile.am.ide | 53 ++++++----- 6 files changed, 183 insertions(+), 80 deletions(-) diff --git a/GPP/GPP.prf.xml b/GPP/GPP.prf.xml index 51dfb675b..2634f3764 100644 --- a/GPP/GPP.prf.xml +++ b/GPP/GPP.prf.xml @@ -582,6 +582,10 @@ THRESHOLD_NOT_EXCEEDED: The measured value no longer exceeds the configured thr - - + + Absolute path to the omniORB configuration file that will be provided to the docker images being launched (if any). + /etc/omniORB.cfg + + + diff --git a/GPP/cpp/GPP.cpp b/GPP/cpp/GPP.cpp index 94f52e612..3bbdcd84a 100644 --- a/GPP/cpp/GPP.cpp +++ b/GPP/cpp/GPP.cpp @@ -1007,6 +1007,38 @@ void GPP_i::releaseObject() throw (CORBA::SystemException, CF::LifeCycle::Releas GPP_base::releaseObject(); } +// Find the executable name in the path variable and returns the path (or empty string, if not found). +std::string GPP_i::find_exec(const char* name) { + DIR *dir; + struct dirent *ent; + std::string search_bin(name); + + std::string path(getenv( "PATH" )); + std::string target; + bool found = false; + while (not found) { + size_t sub = path.find(":"); + if (path.size() == 0) + break; + std::string substr = path.substr(0, sub); + if ((dir = opendir (substr.c_str())) != NULL) { + while ((ent = readdir (dir)) != NULL) { + std::string filename(ent->d_name); + if (filename == search_bin) { + target.append(substr+"/"+filename); + found = true; + break; + } + } + closedir (dir); + } + if (sub != std::string::npos) + path = path.substr(sub+1, std::string::npos); + else + path.clear(); + } + return target; +} CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF::Properties& options, const CF::Properties& parameters) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, @@ -1068,32 +1100,9 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: std::string ld_lib_path(getenv("LD_LIBRARY_PATH")); setenv("GPP_LD_LIBRARY_PATH",ld_lib_path.c_str(),1); - DIR *dir; - struct dirent *ent; - std::string search_bin("screen"); - - std::string path(getenv( "PATH" )); - bool foundScreen = false; - while (not foundScreen) { - size_t sub = path.find(":"); - if (path.size() == 0) - break; - std::string substr = path.substr(0, sub); - if ((dir = opendir (substr.c_str())) != NULL) { - while ((ent = readdir (dir)) != NULL) { - std::string filename(ent->d_name); - if (filename == search_bin) { - prepend_args.push_back(substr+"/"+filename); - foundScreen = true; - break; - } - } - closedir (dir); - } - if (sub != std::string::npos) - path = path.substr(sub+1, std::string::npos); - else - path.clear(); + std::string target = GPP_i::find_exec("screen"); + if (!target.empty()) { + prepend_args.push_back(target); } prepend_args.push_back("-D"); prepend_args.push_back("-m"); @@ -1113,9 +1122,73 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: prepend_args.push_back(waveform_name+"."+name_binding); } } + bool useDocker = false; + if (tmp_params.find("__DOCKER_IMAGE__") != tmp_params.end()) { + std::string image_name = tmp_params["__DOCKER_IMAGE__"].toString(); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component specified a Docker image: " << image_name); + + std::string target = GPP_i::find_exec("docker"); + if (!target.empty()) { + // Verify the image exists + char buffer[128]; + std::string result = ""; + std::string docker_query = target + " images -q " + image_name; + FILE* pipe = popen(docker_query.c_str(), "r"); + if (!pipe) + throw CF::ExecutableDevice::ExecuteFail(CF::CF_EINVAL, "Could not run popen"); + try { + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) { + result += buffer; + } + } + } catch (...) { + pclose (pipe); + throw; + } + pclose(pipe); + if (result.empty()) { + CF::Properties invalidParameters; + invalidParameters.length(invalidParameters.length() + 1); + invalidParameters[invalidParameters.length() - 1].id = "__DOCKER_IMAGE__"; + invalidParameters[invalidParameters.length() - 1].value <<= image_name.c_str(); + throw CF::ExecutableDevice::InvalidParameters(invalidParameters); + } + + // Remove the ':' from the container name + std::string container_name(component_id); + std::replace(container_name.begin(), container_name.end(), ':', '-'); + + prepend_args.push_back(target); + prepend_args.push_back("run"); + prepend_args.push_back("--sig-proxy=true"); + prepend_args.push_back("--rm"); + prepend_args.push_back("--name"); + prepend_args.push_back(container_name); + prepend_args.push_back("--net=host"); + prepend_args.push_back("-v"); + prepend_args.push_back(docker_omniorb_cfg+":/etc/omniORB.cfg"); // Overload omniORB.cfg in the container + + // Additional arguments + if (tmp_params.find("__DOCKER_ARGS__") != tmp_params.end()) { + std::string docker_args_raw = tmp_params["__DOCKER_ARGS__"].toString(); + std::vector docker_args; + boost::split(docker_args, docker_args_raw, boost::is_any_of(" ") ); + BOOST_FOREACH( const std::string& arg, docker_args ) { + prepend_args.push_back(arg); + } + } + + // Finally, the image name + prepend_args.push_back(image_name); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component will launch within a Docker container using this image: " << image_name); + + useDocker = true; + } + } CF::ExecutableDevice::ProcessID_Type ret_pid; try { - ret_pid = do_execute(name, options, tmp_params, prepend_args); + ret_pid = do_execute(name, options, tmp_params, prepend_args, useDocker); addProcess(ret_pid, app_id, component_id, reservation_value); } catch ( ... ) { throw; @@ -1129,7 +1202,7 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: /* execute ***************************************************************** - executes a process on the device ************************************************************************* */ -CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, const std::vector prepend_args) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail) +CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, const std::vector prepend_args, const bool use_docker) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail) { CF::Properties invalidOptions; std::string path; @@ -1215,7 +1288,14 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const logFile += "/valgrind.%p.log"; args.push_back(logFile); } - args.push_back(path); + + if (use_docker) { + // docker container will come up at its own $SDRROOT + // 'name' is prefixed by /, so we prefix it with '.' here + args.push_back("." + std::string(name)); + } else { + args.push_back(path); + } LOG_DEBUG(GPP_i, "Building param list for process " << path); for (CORBA::ULong i = 0; i < parameters.length(); ++i) { @@ -1227,13 +1307,17 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const LOG_DEBUG(GPP_i, "Forking process " << path); + std::string full_command; std::vector argv(args.size() + 1, NULL); for (std::size_t i = 0; i < args.size(); ++i) { // const_cast because execv does not modify values in argv[]. // See: http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html argv[i] = const_cast (args[i].c_str()); + full_command.append(args[i] + " "); } + LOG_DEBUG(GPP_i, __FUNCTION__ << "Full command executed: " << full_command); + rh_logger::LevelPtr lvl = GPP_i::__logger->getLevel(); // setup to capture stdout and stderr from children. @@ -1315,33 +1399,32 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const // Run executable - while(true) - { - if (strcmp(argv[0], "valgrind") == 0) { - // Find valgrind in the path - returnval = execvp(argv[0], &argv[0]); - } else { - returnval = execv(argv[0], &argv[0]); - } - - num_retries--; - if( num_retries <= 0 || errno!=ETXTBSY) - break; - - // Only retry on "text file busy" error - LOG_WARN(GPP_i, "execv() failed, retrying... (cmd=" << path << " msg=\"" << strerror(errno) << "\" retries=" << num_retries << ")"); - usleep(100000); - } + while (true) { + if (strcmp(argv[0], "valgrind") == 0) { + // Find valgrind in the path + returnval = execvp(argv[0], &argv[0]); + } else { + returnval = execv(argv[0], &argv[0]); + } + + num_retries--; + if( num_retries <= 0 || errno!=ETXTBSY) + break; + + // Only retry on "text file busy" error + LOG_WARN(GPP_i, "execv() failed, retrying... (cmd=" << path << " msg=\"" << strerror(errno) << "\" retries=" << num_retries << ")"); + usleep(100000); + } - if( returnval ) { - LOG_ERROR(GPP_i, "Error when calling execv() (cmd=" << path << " errno=" << errno << " msg=\"" << strerror(errno) << "\")"); - ossie::corba::OrbShutdown(true); - } + if( returnval ) { + LOG_ERROR(GPP_i, "Error when calling execv() (cmd=" << path << " errno=" << errno << " msg=\"" << strerror(errno) << "\")"); + ossie::corba::OrbShutdown(true); + } - LOG_DEBUG(GPP_i, "Exiting FAILED subprocess:" << returnval ); - exit(returnval); + LOG_DEBUG(GPP_i, "Exiting FAILED subprocess:" << returnval ); + exit(returnval); } - else if (pid < 0 ){ + else if (pid < 0 ) { LOG_ERROR(GPP_i, "Error forking child process (errno: " << errno << " msg=\"" << strerror(errno) << "\")" ); switch (errno) { case E2BIG: diff --git a/GPP/cpp/GPP.h b/GPP/cpp/GPP.h index 1f11efb9b..8ba21afc1 100644 --- a/GPP/cpp/GPP.h +++ b/GPP/cpp/GPP.h @@ -92,9 +92,11 @@ class GPP_i : public GPP_base CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail); + static std::string find_exec(const char* name); CF::ExecutableDevice::ProcessID_Type do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, - const std::vector prepend_args) + const std::vector prepend_args, + const bool use_docker) throw (CF::ExecutableDevice::ExecuteFail, CF::InvalidFileName, CF::ExecutableDevice::InvalidOptions, CF::ExecutableDevice::InvalidParameters, diff --git a/GPP/cpp/GPP_base.cpp b/GPP/cpp/GPP_base.cpp index e9a3df80c..ebb513161 100644 --- a/GPP/cpp/GPP_base.cpp +++ b/GPP/cpp/GPP_base.cpp @@ -181,6 +181,14 @@ void GPP_base::loadProperties() "external", "property"); + addProperty(docker_omniorb_cfg, + "docker_omniorb_cfg", + "docker_omniorb_cfg", + "readonly", + "/etc/omniORB.cfg", + "external", + "property"); + addProperty(mcastnicInterface, "", "DCE:4e416acc-3144-47eb-9e38-97f1d24f7700", diff --git a/GPP/cpp/GPP_base.h b/GPP/cpp/GPP_base.h index 5809f2c19..5d4d80f39 100644 --- a/GPP/cpp/GPP_base.h +++ b/GPP/cpp/GPP_base.h @@ -54,6 +54,7 @@ class GPP_base : public ExecutableDevice_impl, protected ThreadedComponent std::string os_version; std::string hostName; std::string componentOutputLog; + std::string docker_omniorb_cfg; bool useScreen; advanced_struct advanced; diff --git a/GPP/cpp/Makefile.am.ide b/GPP/cpp/Makefile.am.ide index 9404e22f8..2961c05d5 100644 --- a/GPP/cpp/Makefile.am.ide +++ b/GPP/cpp/Makefile.am.ide @@ -13,36 +13,39 @@ redhawk_SOURCES_auto += NicFacade.cpp redhawk_SOURCES_auto += NicFacade.h redhawk_SOURCES_auto += NicInterfaceFilter.cpp redhawk_SOURCES_auto += NicInterfaceFilter.h +redhawk_SOURCES_auto += affinity_struct.h redhawk_SOURCES_auto += main.cpp -redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.cpp -redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.h +redhawk_SOURCES_auto += parsers/Parser.h +redhawk_SOURCES_auto += parsers/ParserExceptions.h +redhawk_SOURCES_auto += parsers/PidProcStatParser.cpp +redhawk_SOURCES_auto += parsers/PidProcStatParser.h +redhawk_SOURCES_auto += parsers/ProcMeminfoParser.cpp +redhawk_SOURCES_auto += parsers/ProcMeminfoParser.h +redhawk_SOURCES_auto += parsers/ProcStatFileParser.cpp +redhawk_SOURCES_auto += parsers/ProcStatFileParser.h +redhawk_SOURCES_auto += parsers/ProcStatParser.cpp +redhawk_SOURCES_auto += parsers/ProcStatParser.h +redhawk_SOURCES_auto += reports/CpuThresholdMonitor.cpp +redhawk_SOURCES_auto += reports/CpuThresholdMonitor.h redhawk_SOURCES_auto += reports/FreeMemoryThresholdMonitor.cpp redhawk_SOURCES_auto += reports/FreeMemoryThresholdMonitor.h +redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.cpp +redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.h redhawk_SOURCES_auto += reports/Reporting.h -redhawk_SOURCES_auto += reports/ThresholdMonitor.h redhawk_SOURCES_auto += reports/SystemMonitorReporting.cpp redhawk_SOURCES_auto += reports/SystemMonitorReporting.h -redhawk_SOURCES_auto += reports/CpuThresholdMonitor.cpp -redhawk_SOURCES_auto += reports/CpuThresholdMonitor.h -redhawk_SOURCES_auto += parsers/ProcStatFileParser.cpp -redhawk_SOURCES_auto += parsers/ProcStatFileParser.h -redhawk_SOURCES_auto += parsers/PidProcStatParser.cpp -redhawk_SOURCES_auto += parsers/PidProcStatParser.h -redhawk_SOURCES_auto += parsers/ProcStatParser.cpp -redhawk_SOURCES_auto += parsers/ProcStatParser.h -redhawk_SOURCES_auto += parsers/ProcMeminfoParser.cpp -redhawk_SOURCES_auto += parsers/ProcMeminfoParser.h -redhawk_SOURCES_auto += states/NicState.cpp -redhawk_SOURCES_auto += states/NicState.h -redhawk_SOURCES_auto += states/State.h +redhawk_SOURCES_auto += reports/ThresholdMonitor.h redhawk_SOURCES_auto += states/CpuState.cpp redhawk_SOURCES_auto += states/CpuState.h -redhawk_SOURCES_auto += states/ProcStat.cpp -redhawk_SOURCES_auto += states/ProcStat.h -redhawk_SOURCES_auto += states/ProcMeminfo.cpp -redhawk_SOURCES_auto += states/ProcMeminfo.h redhawk_SOURCES_auto += states/Limits.cpp redhawk_SOURCES_auto += states/Limits.h +redhawk_SOURCES_auto += states/NicState.cpp +redhawk_SOURCES_auto += states/NicState.h +redhawk_SOURCES_auto += states/ProcMeminfo.cpp +redhawk_SOURCES_auto += states/ProcMeminfo.h +redhawk_SOURCES_auto += states/ProcStat.cpp +redhawk_SOURCES_auto += states/ProcStat.h +redhawk_SOURCES_auto += states/State.h redhawk_SOURCES_auto += statistics/CpuUsageAccumulator.cpp redhawk_SOURCES_auto += statistics/CpuUsageAccumulator.h redhawk_SOURCES_auto += statistics/CpuUsageStats.cpp @@ -51,12 +54,9 @@ redhawk_SOURCES_auto += statistics/NicAccumulator.cpp redhawk_SOURCES_auto += statistics/NicAccumulator.h redhawk_SOURCES_auto += statistics/Statistics.h redhawk_SOURCES_auto += struct_props.h -redhawk_SOURCES_auto += utils/affinity.cpp -redhawk_SOURCES_auto += utils/affinity.h -redhawk_SOURCES_auto += utils/popen.cpp -redhawk_SOURCES_auto += utils/popen.h redhawk_SOURCES_auto += utils/CmdlineExecutor.cpp redhawk_SOURCES_auto += utils/CmdlineExecutor.h +redhawk_SOURCES_auto += utils/ConversionWrapper.h redhawk_SOURCES_auto += utils/EnvironmentPathParser.cpp redhawk_SOURCES_auto += utils/EnvironmentPathParser.h redhawk_SOURCES_auto += utils/EventDispatcher.h @@ -67,3 +67,8 @@ redhawk_SOURCES_auto += utils/OverridableSingleton.h redhawk_SOURCES_auto += utils/ReferenceWrapper.h redhawk_SOURCES_auto += utils/SymlinkReader.cpp redhawk_SOURCES_auto += utils/SymlinkReader.h +redhawk_SOURCES_auto += utils/Updateable.h +redhawk_SOURCES_auto += utils/affinity.cpp +redhawk_SOURCES_auto += utils/affinity.h +redhawk_SOURCES_auto += utils/popen.cpp +redhawk_SOURCES_auto += utils/popen.h From 7523f312aa86be3d1c5bc2c7cf1cca523cd9f547 Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Fri, 23 Jun 2017 07:42:57 -0400 Subject: [PATCH 2/8] Added allocation properties for checking if images and/or volumes are available at the GPP --- GPP/GPP.prf.xml | 14 +- GPP/cpp/GPP.cpp | 379 ++++++++++++++++++++++++------------------- GPP/cpp/GPP.h | 10 ++ GPP/cpp/GPP_base.cpp | 18 +- GPP/cpp/GPP_base.h | 2 + 5 files changed, 251 insertions(+), 172 deletions(-) diff --git a/GPP/GPP.prf.xml b/GPP/GPP.prf.xml index 2634f3764..5b6483387 100644 --- a/GPP/GPP.prf.xml +++ b/GPP/GPP.prf.xml @@ -582,10 +582,22 @@ THRESHOLD_NOT_EXCEEDED: The measured value no longer exceeds the configured thr - + Absolute path to the omniORB configuration file that will be provided to the docker images being launched (if any). /etc/omniORB.cfg + + Docker Image to load + + + + + + Docker Volume to load + + + + diff --git a/GPP/cpp/GPP.cpp b/GPP/cpp/GPP.cpp index 3bbdcd84a..b124310fe 100644 --- a/GPP/cpp/GPP.cpp +++ b/GPP/cpp/GPP.cpp @@ -248,7 +248,7 @@ class FindApp : public std::binary_function< GPP_i::component_description, std:: }; inline bool operator== (const GPP_i::component_description& s1, - const GPP_i::component_description& s2) { + const GPP_i::component_description& s2) { if (s1.appName!=s2.appName) return false; if (s1.identifier!=s2.identifier) @@ -493,6 +493,10 @@ void GPP_i::_init() { //setAllocationImpl("diskCapacity", this, &GPP_i::allocate_diskCapacity, &GPP_i::deallocate_diskCapacity); + // check for docker elements + setAllocationImpl("DCE:c38d28a6-351d-4aa4-a9ba-3cea51966838", this, &GPP_i::allocate_docker_image, &GPP_i::deallocate_docker_image); + setAllocationImpl("DCE:47a581c8-e31f-4284-a3ef-6d8b98385835", this, &GPP_i::allocate_docker_volume, &GPP_i::deallocate_docker_volume); + } @@ -964,7 +968,7 @@ void GPP_i::thresholds_changed(const thresholds_struct *ov, const thresholds_str if ( ov->mem_free != nv->mem_free ) { LOG_DEBUG(GPP_i, __FUNCTION__ << " THRESHOLDS.MEM_FREE CHANGED old/new " << ov->mem_free << "/" << nv->mem_free ); WriteLock wlock(pidLock); - int64_t init_mem_free = (int64_t) memInitVirtFree; + int64_t init_mem_free = (int64_t) memInitVirtFree; // type cast required for correct calc on 32bit os memInitCapacityPercent = (double)( (int64_t)init_mem_free - (int64_t)(nv->mem_free*thresh_mem_free_units) )/ (double) init_mem_free; if ( memInitCapacityPercent < 0.0 ) memInitCapacityPercent = 100.0; @@ -1037,9 +1041,65 @@ std::string GPP_i::find_exec(const char* name) { else path.clear(); } - return target; + return target; +} + +// Generic docker caller +bool GPP_i::check_docker(const std::string ¶ms) { + bool retval = false; + + std::string docker = GPP_i::find_exec("docker"); + + if (!docker.empty()) { + // Verify the image exists + char buffer[128]; + std::string result = ""; + std::string docker_query = docker + " " + params; + FILE* pipe = popen(docker_query.c_str(), "r"); + if (!pipe) + throw CF::ExecutableDevice::ExecuteFail(CF::CF_EINVAL, "Could not run popen"); + try { + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) { + result += buffer; + } + } + } catch (...) { + pclose (pipe); + throw; + } + pclose(pipe); + + retval = !result.empty(); + } + return retval; +} + +// Check for a docker image tagged as value +bool GPP_i::check_docker_image(const std::string &value) { + return check_docker("images -q " + value); } +// Check for a docker volume named value +// TODO: Be less hackey. :-| +bool GPP_i::check_docker_volume(const std::string &value) { + std::string grep = GPP_i::find_exec("grep"); + return check_docker("volumes ls -q | " + grep + " " + value); +} + +bool GPP_i::allocate_docker_image(const std::string &value) { + return check_docker_image(value); +} + +void GPP_i::deallocate_docker_image(const std::string &value) { } + +bool GPP_i::allocate_docker_volume(const std::string &value) { + return check_docker_volume(value); +} + +void GPP_i::deallocate_docker_volume(const std::string &value) { } + + CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF::Properties& options, const CF::Properties& parameters) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, @@ -1066,15 +1126,15 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: redhawk::PropertyMap& tmp_params = redhawk::PropertyMap::cast(variable_parameters); float reservation_value = -1; if (tmp_params.find("RH::GPP::MODIFIED_CPU_RESERVATION_VALUE") != tmp_params.end()) { - double reservation_value_d; - if (!tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value)) { - if (tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value_d)) { - reservation_value = reservation_value_d; - } else { - reservation_value = -1; - } + double reservation_value_d; + if (!tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value)) { + if (tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value_d)) { + reservation_value = reservation_value_d; + } else { + reservation_value = -1; } - tmp_params.erase("RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"); + } + tmp_params.erase("RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"); } naming_context_ior = tmp_params["NAMING_CONTEXT_IOR"].toString(); std::string app_id; @@ -1083,115 +1143,96 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: CF::Application_var _app = CF::Application::_nil(); CORBA::Object_var obj = ossie::corba::Orb()->string_to_object(naming_context_ior.c_str()); if (CORBA::is_nil(obj)) { - LOG_WARN(GPP_i, "Invalid application registrar IOR"); + LOG_WARN(GPP_i, "Invalid application registrar IOR"); } else { - CF::ApplicationRegistrar_var _appRegistrar = CF::ApplicationRegistrar::_nil(); - _appRegistrar = CF::ApplicationRegistrar::_narrow(obj); - if (CORBA::is_nil(_appRegistrar)) { - LOG_WARN(GPP_i, "Invalid application registrar IOR"); - } else { - _app = _appRegistrar->app(); - if (not CORBA::is_nil(_app)) { - app_id = ossie::corba::returnString(_app->identifier()); - } + CF::ApplicationRegistrar_var _appRegistrar = CF::ApplicationRegistrar::_nil(); + _appRegistrar = CF::ApplicationRegistrar::_narrow(obj); + if (CORBA::is_nil(_appRegistrar)) { + LOG_WARN(GPP_i, "Invalid application registrar IOR"); + } else { + _app = _appRegistrar->app(); + if (not CORBA::is_nil(_app)) { + app_id = ossie::corba::returnString(_app->identifier()); } + } } if (useScreen) { - std::string ld_lib_path(getenv("LD_LIBRARY_PATH")); - setenv("GPP_LD_LIBRARY_PATH",ld_lib_path.c_str(),1); - - std::string target = GPP_i::find_exec("screen"); - if (!target.empty()) { - prepend_args.push_back(target); - } - prepend_args.push_back("-D"); - prepend_args.push_back("-m"); - prepend_args.push_back("-c"); - prepend_args.push_back(binary_location+"gpp.screenrc"); - if ((not component_id.empty()) and (not name_binding.empty())) { - if (component_id.find("DCE:") != std::string::npos) { - component_id = component_id.substr(4, std::string::npos); - } - size_t waveform_boundary = component_id.find(":"); - std::string component_inst_id, waveform_name; - component_inst_id = component_id.substr(0, waveform_boundary); - waveform_name = component_id.substr(waveform_boundary+1, std::string::npos); - prepend_args.push_back("-S"); - prepend_args.push_back(waveform_name+"."+name_binding); - prepend_args.push_back("-t"); - prepend_args.push_back(waveform_name+"."+name_binding); + std::string ld_lib_path(getenv("LD_LIBRARY_PATH")); + setenv("GPP_LD_LIBRARY_PATH",ld_lib_path.c_str(),1); + + std::string target = GPP_i::find_exec("screen"); + if (!target.empty()) { + prepend_args.push_back(target); + } + prepend_args.push_back("-D"); + prepend_args.push_back("-m"); + prepend_args.push_back("-c"); + prepend_args.push_back(binary_location+"gpp.screenrc"); + if ((not component_id.empty()) and (not name_binding.empty())) { + if (component_id.find("DCE:") != std::string::npos) { + component_id = component_id.substr(4, std::string::npos); } + size_t waveform_boundary = component_id.find(":"); + std::string component_inst_id, waveform_name; + component_inst_id = component_id.substr(0, waveform_boundary); + waveform_name = component_id.substr(waveform_boundary+1, std::string::npos); + prepend_args.push_back("-S"); + prepend_args.push_back(waveform_name+"."+name_binding); + prepend_args.push_back("-t"); + prepend_args.push_back(waveform_name+"."+name_binding); + } } bool useDocker = false; if (tmp_params.find("__DOCKER_IMAGE__") != tmp_params.end()) { std::string image_name = tmp_params["__DOCKER_IMAGE__"].toString(); - LOG_DEBUG(GPP_i, __FUNCTION__ << "Component specified a Docker image: " << image_name); - - std::string target = GPP_i::find_exec("docker"); - if (!target.empty()) { - // Verify the image exists - char buffer[128]; - std::string result = ""; - std::string docker_query = target + " images -q " + image_name; - FILE* pipe = popen(docker_query.c_str(), "r"); - if (!pipe) - throw CF::ExecutableDevice::ExecuteFail(CF::CF_EINVAL, "Could not run popen"); - try { - while (!feof(pipe)) { - if (fgets(buffer, 128, pipe) != NULL) { - result += buffer; - } - } - } catch (...) { - pclose (pipe); - throw; - } - pclose(pipe); - if (result.empty()) { - CF::Properties invalidParameters; - invalidParameters.length(invalidParameters.length() + 1); - invalidParameters[invalidParameters.length() - 1].id = "__DOCKER_IMAGE__"; - invalidParameters[invalidParameters.length() - 1].value <<= image_name.c_str(); - throw CF::ExecutableDevice::InvalidParameters(invalidParameters); - } - - // Remove the ':' from the container name - std::string container_name(component_id); - std::replace(container_name.begin(), container_name.end(), ':', '-'); - - prepend_args.push_back(target); - prepend_args.push_back("run"); - prepend_args.push_back("--sig-proxy=true"); - prepend_args.push_back("--rm"); - prepend_args.push_back("--name"); - prepend_args.push_back(container_name); - prepend_args.push_back("--net=host"); - prepend_args.push_back("-v"); - prepend_args.push_back(docker_omniorb_cfg+":/etc/omniORB.cfg"); // Overload omniORB.cfg in the container - - // Additional arguments - if (tmp_params.find("__DOCKER_ARGS__") != tmp_params.end()) { - std::string docker_args_raw = tmp_params["__DOCKER_ARGS__"].toString(); - std::vector docker_args; - boost::split(docker_args, docker_args_raw, boost::is_any_of(" ") ); - BOOST_FOREACH( const std::string& arg, docker_args ) { - prepend_args.push_back(arg); - } - } - - // Finally, the image name - prepend_args.push_back(image_name); - LOG_DEBUG(GPP_i, __FUNCTION__ << "Component will launch within a Docker container using this image: " << image_name); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component specified a Docker image: " << image_name); + + // Check for the docker image + if (!check_docker_image(image_name)) { + CF::Properties invalidParameters; + invalidParameters.length(invalidParameters.length() + 1); + invalidParameters[invalidParameters.length() - 1].id = "__DOCKER_IMAGE__"; + invalidParameters[invalidParameters.length() - 1].value <<= image_name.c_str(); + throw CF::ExecutableDevice::InvalidParameters(invalidParameters); + } - useDocker = true; + // Remove the ':' from the container name + std::string container_name(component_id); + std::replace(container_name.begin(), container_name.end(), ':', '-'); + + std::string docker = GPP_i::find_exec("docker"); + prepend_args.push_back(docker); + prepend_args.push_back("run"); + prepend_args.push_back("--sig-proxy=true"); + prepend_args.push_back("--rm"); + prepend_args.push_back("--name"); + prepend_args.push_back(container_name); + prepend_args.push_back("--net=host"); + prepend_args.push_back("-v"); + prepend_args.push_back(docker_omniorb_cfg+":/etc/omniORB.cfg"); // Overload omniORB.cfg in the container + + // Additional arguments + if (tmp_params.find("__DOCKER_ARGS__") != tmp_params.end()) { + std::string docker_args_raw = tmp_params["__DOCKER_ARGS__"].toString(); + std::vector docker_args; + boost::split(docker_args, docker_args_raw, boost::is_any_of(" ") ); + BOOST_FOREACH( const std::string& arg, docker_args ) { + prepend_args.push_back(arg); } + } + + // Finally, the image name + prepend_args.push_back(image_name); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component will launch within a Docker container using this image: " << image_name); + + useDocker = true; } CF::ExecutableDevice::ProcessID_Type ret_pid; try { - ret_pid = do_execute(name, options, tmp_params, prepend_args, useDocker); - addProcess(ret_pid, app_id, component_id, reservation_value); + ret_pid = do_execute(name, options, tmp_params, prepend_args, useDocker); + addProcess(ret_pid, app_id, component_id, reservation_value); } catch ( ... ) { - throw; + throw; } return ret_pid; } @@ -1204,52 +1245,50 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: ************************************************************************* */ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, const std::vector prepend_args, const bool use_docker) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail) { - CF::Properties invalidOptions; - std::string path; - char* tmp; - - // throw and error if name does not begin with a / - if (strncmp(name, "/", 1) != 0) - throw CF::InvalidFileName(CF::CF_EINVAL, "Filename must be absolute"); - if (isLocked()) - throw CF::Device::InvalidState("System is locked down"); - if (isDisabled()) - throw CF::Device::InvalidState("System is disabled"); - - //process options and throw InvalidOptions errors if they are not ULong - for (CORBA::ULong i = 0; i < options.length(); ++i) { - if (options[i].id == CF::ExecutableDevice::PRIORITY_ID) { - CORBA::TypeCode_var atype = options[i].value.type(); - if (atype->kind() != CORBA::tk_ulong) { - invalidOptions.length(invalidOptions.length() + 1); - invalidOptions[invalidOptions.length() - 1].id = options[i].id; - invalidOptions[invalidOptions.length() - 1].value - = options[i].value; - } else - LOG_WARN(GPP_i, "Received a PRIORITY_ID execute option...ignoring.") - } - if (options[i].id == CF::ExecutableDevice::STACK_SIZE_ID) { - CORBA::TypeCode_var atype = options[i].value.type(); - if (atype->kind() != CORBA::tk_ulong) { - invalidOptions.length(invalidOptions.length() + 1); - invalidOptions[invalidOptions.length() - 1].id = options[i].id; - invalidOptions[invalidOptions.length() - 1].value - = options[i].value; - } else - LOG_WARN(GPP_i, "Received a STACK_SIZE_ID execute option...ignoring.") - } - } + CF::Properties invalidOptions; + std::string path; + char* tmp; + + // throw and error if name does not begin with a / + if (strncmp(name, "/", 1) != 0) + throw CF::InvalidFileName(CF::CF_EINVAL, "Filename must be absolute"); + if (isLocked()) + throw CF::Device::InvalidState("System is locked down"); + if (isDisabled()) + throw CF::Device::InvalidState("System is disabled"); + + //process options and throw InvalidOptions errors if they are not ULong + for (CORBA::ULong i = 0; i < options.length(); ++i) { + if (options[i].id == CF::ExecutableDevice::PRIORITY_ID) { + CORBA::TypeCode_var atype = options[i].value.type(); + if (atype->kind() != CORBA::tk_ulong) { + invalidOptions.length(invalidOptions.length() + 1); + invalidOptions[invalidOptions.length() - 1].id = options[i].id; + invalidOptions[invalidOptions.length() - 1].value = options[i].value; + } else + LOG_WARN(GPP_i, "Received a PRIORITY_ID execute option...ignoring.") + } + if (options[i].id == CF::ExecutableDevice::STACK_SIZE_ID) { + CORBA::TypeCode_var atype = options[i].value.type(); + if (atype->kind() != CORBA::tk_ulong) { + invalidOptions.length(invalidOptions.length() + 1); + invalidOptions[invalidOptions.length() - 1].id = options[i].id; + invalidOptions[invalidOptions.length() - 1].value = options[i].value; + } else + LOG_WARN(GPP_i, "Received a STACK_SIZE_ID execute option...ignoring.") + } + } - if (invalidOptions.length() > 0) { - throw CF::ExecutableDevice::InvalidOptions(invalidOptions); - } + if (invalidOptions.length() > 0) { + throw CF::ExecutableDevice::InvalidOptions(invalidOptions); + } - // retrieve current working directory - tmp = getcwd(NULL, 200); - if (tmp != NULL) { - path = std::string(tmp); - free(tmp); - } + // retrieve current working directory + tmp = getcwd(NULL, 200); + if (tmp != NULL) { + path = std::string(tmp); + free(tmp); + } // append relative path of the executable path.append(name); @@ -1290,11 +1329,11 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const } if (use_docker) { - // docker container will come up at its own $SDRROOT - // 'name' is prefixed by /, so we prefix it with '.' here - args.push_back("." + std::string(name)); + // docker container will come up at its own $SDRROOT + // 'name' is prefixed by /, so we prefix it with '.' here + args.push_back("." + std::string(name)); } else { - args.push_back(path); + args.push_back(path); } LOG_DEBUG(GPP_i, "Building param list for process " << path); @@ -1400,25 +1439,25 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const // Run executable while (true) { - if (strcmp(argv[0], "valgrind") == 0) { - // Find valgrind in the path - returnval = execvp(argv[0], &argv[0]); - } else { - returnval = execv(argv[0], &argv[0]); - } - - num_retries--; - if( num_retries <= 0 || errno!=ETXTBSY) - break; - - // Only retry on "text file busy" error - LOG_WARN(GPP_i, "execv() failed, retrying... (cmd=" << path << " msg=\"" << strerror(errno) << "\" retries=" << num_retries << ")"); - usleep(100000); + if (strcmp(argv[0], "valgrind") == 0) { + // Find valgrind in the path + returnval = execvp(argv[0], &argv[0]); + } else { + returnval = execv(argv[0], &argv[0]); + } + + num_retries--; + if( num_retries <= 0 || errno!=ETXTBSY) + break; + + // Only retry on "text file busy" error + LOG_WARN(GPP_i, "execv() failed, retrying... (cmd=" << path << " msg=\"" << strerror(errno) << "\" retries=" << num_retries << ")"); + usleep(100000); } if( returnval ) { - LOG_ERROR(GPP_i, "Error when calling execv() (cmd=" << path << " errno=" << errno << " msg=\"" << strerror(errno) << "\")"); - ossie::corba::OrbShutdown(true); + LOG_ERROR(GPP_i, "Error when calling execv() (cmd=" << path << " errno=" << errno << " msg=\"" << strerror(errno) << "\")"); + ossie::corba::OrbShutdown(true); } LOG_DEBUG(GPP_i, "Exiting FAILED subprocess:" << returnval ); @@ -2907,7 +2946,7 @@ int GPP_i::_get_deploy_on_partition() { double m_idle_thresh = iter->idle_threshold + ( iter->idle_cap_mod * n_reservations) + (float)loadCapacity/(float)iter->cpus.size(); RH_NL_DEBUG("GPP", " Looking for execute partition (processor socket:" << iter->id << ") IDLE: actual/avg/threshold limit/modified " << - iter->get_idle_percent() << "/" << iter->get_idle_average() << "/" << iter->idle_threshold << "/" << m_idle_thresh ); + iter->get_idle_percent() << "/" << iter->get_idle_average() << "/" << iter->idle_threshold << "/" << m_idle_thresh ); if ( iter->get_idle_percent() > m_idle_thresh ) { psoc=iter->id; break; diff --git a/GPP/cpp/GPP.h b/GPP/cpp/GPP.h index 8ba21afc1..ad34f6dcb 100644 --- a/GPP/cpp/GPP.h +++ b/GPP/cpp/GPP.h @@ -103,6 +103,16 @@ class GPP_i : public GPP_base CF::ExecutableDevice::InvalidFunction, CF::Device::InvalidState, CORBA::SystemException); + bool check_docker(const std::string ¶ms); + bool check_docker_image(const std::string &value); + bool check_docker_volume(const std::string &value); + + bool allocate_docker_image(const std::string &value); + void deallocate_docker_image(const std::string &value); + + bool allocate_docker_volume(const std::string &value); + void deallocate_docker_volume(const std::string &value); + void terminate (CF::ExecutableDevice::ProcessID_Type processId) throw (CORBA::SystemException, CF::ExecutableDevice::InvalidProcess, CF::Device::InvalidState); diff --git a/GPP/cpp/GPP_base.cpp b/GPP/cpp/GPP_base.cpp index ebb513161..2e103b8a6 100644 --- a/GPP/cpp/GPP_base.cpp +++ b/GPP/cpp/GPP_base.cpp @@ -182,13 +182,29 @@ void GPP_base::loadProperties() "property"); addProperty(docker_omniorb_cfg, - "docker_omniorb_cfg", + "DCE:0b5c1a83-7226-4705-a3be-eff5a8a9f38a", "docker_omniorb_cfg", "readonly", "/etc/omniORB.cfg", "external", "property"); + addProperty(docker_image, + "DCE:c38d28a6-351d-4aa4-a9ba-3cea51966838", + "docker_image", + "readwrite", + "", + "eq", + "allocation"); + + addProperty(docker_volume, + "DCE:DCE:47a581c8-e31f-4284-a3ef-6d8b98385835", + "docker_volume", + "readwrite", + "", + "eq", + "allocation"); + addProperty(mcastnicInterface, "", "DCE:4e416acc-3144-47eb-9e38-97f1d24f7700", diff --git a/GPP/cpp/GPP_base.h b/GPP/cpp/GPP_base.h index 5d4d80f39..1aefab973 100644 --- a/GPP/cpp/GPP_base.h +++ b/GPP/cpp/GPP_base.h @@ -55,6 +55,8 @@ class GPP_base : public ExecutableDevice_impl, protected ThreadedComponent std::string hostName; std::string componentOutputLog; std::string docker_omniorb_cfg; + std::string docker_image; + std::string docker_volume; bool useScreen; advanced_struct advanced; From 4de6976592e9c88d2effeeeab62ad7b3b794fe8a Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Mon, 19 Jun 2017 10:07:37 -0400 Subject: [PATCH 3/8] Added ability to launch Docker images from GPP --- GPP/GPP.prf.xml | 8 ++- GPP/cpp/GPP.cpp | 144 +++++++++++++++++++++++++++++++--------- GPP/cpp/GPP.h | 4 +- GPP/cpp/GPP_base.cpp | 8 +++ GPP/cpp/GPP_base.h | 1 + GPP/cpp/Makefile.am.ide | 53 ++++++++------- 6 files changed, 161 insertions(+), 57 deletions(-) diff --git a/GPP/GPP.prf.xml b/GPP/GPP.prf.xml index 51dfb675b..2634f3764 100644 --- a/GPP/GPP.prf.xml +++ b/GPP/GPP.prf.xml @@ -582,6 +582,10 @@ THRESHOLD_NOT_EXCEEDED: The measured value no longer exceeds the configured thr - - + + Absolute path to the omniORB configuration file that will be provided to the docker images being launched (if any). + /etc/omniORB.cfg + + + diff --git a/GPP/cpp/GPP.cpp b/GPP/cpp/GPP.cpp index 38bbebfad..1f481aced 100644 --- a/GPP/cpp/GPP.cpp +++ b/GPP/cpp/GPP.cpp @@ -1056,6 +1056,38 @@ void GPP_i::releaseObject() throw (CORBA::SystemException, CF::LifeCycle::Releas GPP_base::releaseObject(); } +// Find the executable name in the path variable and returns the path (or empty string, if not found). +std::string GPP_i::find_exec(const char* name) { + DIR *dir; + struct dirent *ent; + std::string search_bin(name); + + std::string path(getenv( "PATH" )); + std::string target; + bool found = false; + while (not found) { + size_t sub = path.find(":"); + if (path.size() == 0) + break; + std::string substr = path.substr(0, sub); + if ((dir = opendir (substr.c_str())) != NULL) { + while ((ent = readdir (dir)) != NULL) { + std::string filename(ent->d_name); + if (filename == search_bin) { + target.append(substr+"/"+filename); + found = true; + break; + } + } + closedir (dir); + } + if (sub != std::string::npos) + path = path.substr(sub+1, std::string::npos); + else + path.clear(); + } + return target; +} CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF::Properties& options, const CF::Properties& parameters) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, @@ -1117,32 +1149,9 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: std::string ld_lib_path(getenv("LD_LIBRARY_PATH")); setenv("GPP_LD_LIBRARY_PATH",ld_lib_path.c_str(),1); - DIR *dir; - struct dirent *ent; - std::string search_bin("screen"); - - std::string path(getenv( "PATH" )); - bool foundScreen = false; - while (not foundScreen) { - size_t sub = path.find(":"); - if (path.size() == 0) - break; - std::string substr = path.substr(0, sub); - if ((dir = opendir (substr.c_str())) != NULL) { - while ((ent = readdir (dir)) != NULL) { - std::string filename(ent->d_name); - if (filename == search_bin) { - prepend_args.push_back(substr+"/"+filename); - foundScreen = true; - break; - } - } - closedir (dir); - } - if (sub != std::string::npos) - path = path.substr(sub+1, std::string::npos); - else - path.clear(); + std::string target = GPP_i::find_exec("screen"); + if (!target.empty()) { + prepend_args.push_back(target); } prepend_args.push_back("-D"); prepend_args.push_back("-m"); @@ -1162,9 +1171,73 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: prepend_args.push_back(waveform_name+"."+name_binding); } } + bool useDocker = false; + if (tmp_params.find("__DOCKER_IMAGE__") != tmp_params.end()) { + std::string image_name = tmp_params["__DOCKER_IMAGE__"].toString(); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component specified a Docker image: " << image_name); + + std::string target = GPP_i::find_exec("docker"); + if (!target.empty()) { + // Verify the image exists + char buffer[128]; + std::string result = ""; + std::string docker_query = target + " images -q " + image_name; + FILE* pipe = popen(docker_query.c_str(), "r"); + if (!pipe) + throw CF::ExecutableDevice::ExecuteFail(CF::CF_EINVAL, "Could not run popen"); + try { + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) { + result += buffer; + } + } + } catch (...) { + pclose (pipe); + throw; + } + pclose(pipe); + if (result.empty()) { + CF::Properties invalidParameters; + invalidParameters.length(invalidParameters.length() + 1); + invalidParameters[invalidParameters.length() - 1].id = "__DOCKER_IMAGE__"; + invalidParameters[invalidParameters.length() - 1].value <<= image_name.c_str(); + throw CF::ExecutableDevice::InvalidParameters(invalidParameters); + } + + // Remove the ':' from the container name + std::string container_name(component_id); + std::replace(container_name.begin(), container_name.end(), ':', '-'); + + prepend_args.push_back(target); + prepend_args.push_back("run"); + prepend_args.push_back("--sig-proxy=true"); + prepend_args.push_back("--rm"); + prepend_args.push_back("--name"); + prepend_args.push_back(container_name); + prepend_args.push_back("--net=host"); + prepend_args.push_back("-v"); + prepend_args.push_back(docker_omniorb_cfg+":/etc/omniORB.cfg"); // Overload omniORB.cfg in the container + + // Additional arguments + if (tmp_params.find("__DOCKER_ARGS__") != tmp_params.end()) { + std::string docker_args_raw = tmp_params["__DOCKER_ARGS__"].toString(); + std::vector docker_args; + boost::split(docker_args, docker_args_raw, boost::is_any_of(" ") ); + BOOST_FOREACH( const std::string& arg, docker_args ) { + prepend_args.push_back(arg); + } + } + + // Finally, the image name + prepend_args.push_back(image_name); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component will launch within a Docker container using this image: " << image_name); + + useDocker = true; + } + } CF::ExecutableDevice::ProcessID_Type ret_pid; try { - ret_pid = do_execute(name, options, tmp_params, prepend_args); + ret_pid = do_execute(name, options, tmp_params, prepend_args, useDocker); addProcess(ret_pid, app_id, component_id, reservation_value); } catch ( ... ) { throw; @@ -1178,7 +1251,7 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: /* execute ***************************************************************** - executes a process on the device ************************************************************************* */ -CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, const std::vector prepend_args) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail) +CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, const std::vector prepend_args, const bool use_docker) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail) { CF::Properties invalidOptions; std::string path; @@ -1264,7 +1337,14 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const logFile += "/valgrind.%p.log"; args.push_back(logFile); } - args.push_back(path); + + if (use_docker) { + // docker container will come up at its own $SDRROOT + // 'name' is prefixed by /, so we prefix it with '.' here + args.push_back("." + std::string(name)); + } else { + args.push_back(path); + } LOG_DEBUG(GPP_i, "Building param list for process " << path); for (CORBA::ULong i = 0; i < parameters.length(); ++i) { @@ -1276,13 +1356,17 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const LOG_DEBUG(GPP_i, "Forking process " << path); + std::string full_command; std::vector argv(args.size() + 1, NULL); for (std::size_t i = 0; i < args.size(); ++i) { // const_cast because execv does not modify values in argv[]. // See: http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html argv[i] = const_cast (args[i].c_str()); + full_command.append(args[i] + " "); } + LOG_DEBUG(GPP_i, __FUNCTION__ << "Full command executed: " << full_command); + rh_logger::LevelPtr lvl = GPP_i::__logger->getLevel(); // setup to capture stdout and stderr from children. @@ -1390,7 +1474,7 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const RH_ERROR(__logger, "Exiting FAILED subprocess:" << returnval ); exit(returnval); } - else if (pid < 0 ){ + else if (pid < 0 ) { LOG_ERROR(GPP_i, "Error forking child process (errno: " << errno << " msg=\"" << strerror(errno) << "\")" ); switch (errno) { case E2BIG: diff --git a/GPP/cpp/GPP.h b/GPP/cpp/GPP.h index 85e57456d..c3fbf99c3 100644 --- a/GPP/cpp/GPP.h +++ b/GPP/cpp/GPP.h @@ -92,9 +92,11 @@ class GPP_i : public GPP_base CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail); + static std::string find_exec(const char* name); CF::ExecutableDevice::ProcessID_Type do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, - const std::vector prepend_args) + const std::vector prepend_args, + const bool use_docker) throw (CF::ExecutableDevice::ExecuteFail, CF::InvalidFileName, CF::ExecutableDevice::InvalidOptions, CF::ExecutableDevice::InvalidParameters, diff --git a/GPP/cpp/GPP_base.cpp b/GPP/cpp/GPP_base.cpp index e9a3df80c..ebb513161 100644 --- a/GPP/cpp/GPP_base.cpp +++ b/GPP/cpp/GPP_base.cpp @@ -181,6 +181,14 @@ void GPP_base::loadProperties() "external", "property"); + addProperty(docker_omniorb_cfg, + "docker_omniorb_cfg", + "docker_omniorb_cfg", + "readonly", + "/etc/omniORB.cfg", + "external", + "property"); + addProperty(mcastnicInterface, "", "DCE:4e416acc-3144-47eb-9e38-97f1d24f7700", diff --git a/GPP/cpp/GPP_base.h b/GPP/cpp/GPP_base.h index 5809f2c19..5d4d80f39 100644 --- a/GPP/cpp/GPP_base.h +++ b/GPP/cpp/GPP_base.h @@ -54,6 +54,7 @@ class GPP_base : public ExecutableDevice_impl, protected ThreadedComponent std::string os_version; std::string hostName; std::string componentOutputLog; + std::string docker_omniorb_cfg; bool useScreen; advanced_struct advanced; diff --git a/GPP/cpp/Makefile.am.ide b/GPP/cpp/Makefile.am.ide index 9404e22f8..2961c05d5 100644 --- a/GPP/cpp/Makefile.am.ide +++ b/GPP/cpp/Makefile.am.ide @@ -13,36 +13,39 @@ redhawk_SOURCES_auto += NicFacade.cpp redhawk_SOURCES_auto += NicFacade.h redhawk_SOURCES_auto += NicInterfaceFilter.cpp redhawk_SOURCES_auto += NicInterfaceFilter.h +redhawk_SOURCES_auto += affinity_struct.h redhawk_SOURCES_auto += main.cpp -redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.cpp -redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.h +redhawk_SOURCES_auto += parsers/Parser.h +redhawk_SOURCES_auto += parsers/ParserExceptions.h +redhawk_SOURCES_auto += parsers/PidProcStatParser.cpp +redhawk_SOURCES_auto += parsers/PidProcStatParser.h +redhawk_SOURCES_auto += parsers/ProcMeminfoParser.cpp +redhawk_SOURCES_auto += parsers/ProcMeminfoParser.h +redhawk_SOURCES_auto += parsers/ProcStatFileParser.cpp +redhawk_SOURCES_auto += parsers/ProcStatFileParser.h +redhawk_SOURCES_auto += parsers/ProcStatParser.cpp +redhawk_SOURCES_auto += parsers/ProcStatParser.h +redhawk_SOURCES_auto += reports/CpuThresholdMonitor.cpp +redhawk_SOURCES_auto += reports/CpuThresholdMonitor.h redhawk_SOURCES_auto += reports/FreeMemoryThresholdMonitor.cpp redhawk_SOURCES_auto += reports/FreeMemoryThresholdMonitor.h +redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.cpp +redhawk_SOURCES_auto += reports/NicThroughputThresholdMonitor.h redhawk_SOURCES_auto += reports/Reporting.h -redhawk_SOURCES_auto += reports/ThresholdMonitor.h redhawk_SOURCES_auto += reports/SystemMonitorReporting.cpp redhawk_SOURCES_auto += reports/SystemMonitorReporting.h -redhawk_SOURCES_auto += reports/CpuThresholdMonitor.cpp -redhawk_SOURCES_auto += reports/CpuThresholdMonitor.h -redhawk_SOURCES_auto += parsers/ProcStatFileParser.cpp -redhawk_SOURCES_auto += parsers/ProcStatFileParser.h -redhawk_SOURCES_auto += parsers/PidProcStatParser.cpp -redhawk_SOURCES_auto += parsers/PidProcStatParser.h -redhawk_SOURCES_auto += parsers/ProcStatParser.cpp -redhawk_SOURCES_auto += parsers/ProcStatParser.h -redhawk_SOURCES_auto += parsers/ProcMeminfoParser.cpp -redhawk_SOURCES_auto += parsers/ProcMeminfoParser.h -redhawk_SOURCES_auto += states/NicState.cpp -redhawk_SOURCES_auto += states/NicState.h -redhawk_SOURCES_auto += states/State.h +redhawk_SOURCES_auto += reports/ThresholdMonitor.h redhawk_SOURCES_auto += states/CpuState.cpp redhawk_SOURCES_auto += states/CpuState.h -redhawk_SOURCES_auto += states/ProcStat.cpp -redhawk_SOURCES_auto += states/ProcStat.h -redhawk_SOURCES_auto += states/ProcMeminfo.cpp -redhawk_SOURCES_auto += states/ProcMeminfo.h redhawk_SOURCES_auto += states/Limits.cpp redhawk_SOURCES_auto += states/Limits.h +redhawk_SOURCES_auto += states/NicState.cpp +redhawk_SOURCES_auto += states/NicState.h +redhawk_SOURCES_auto += states/ProcMeminfo.cpp +redhawk_SOURCES_auto += states/ProcMeminfo.h +redhawk_SOURCES_auto += states/ProcStat.cpp +redhawk_SOURCES_auto += states/ProcStat.h +redhawk_SOURCES_auto += states/State.h redhawk_SOURCES_auto += statistics/CpuUsageAccumulator.cpp redhawk_SOURCES_auto += statistics/CpuUsageAccumulator.h redhawk_SOURCES_auto += statistics/CpuUsageStats.cpp @@ -51,12 +54,9 @@ redhawk_SOURCES_auto += statistics/NicAccumulator.cpp redhawk_SOURCES_auto += statistics/NicAccumulator.h redhawk_SOURCES_auto += statistics/Statistics.h redhawk_SOURCES_auto += struct_props.h -redhawk_SOURCES_auto += utils/affinity.cpp -redhawk_SOURCES_auto += utils/affinity.h -redhawk_SOURCES_auto += utils/popen.cpp -redhawk_SOURCES_auto += utils/popen.h redhawk_SOURCES_auto += utils/CmdlineExecutor.cpp redhawk_SOURCES_auto += utils/CmdlineExecutor.h +redhawk_SOURCES_auto += utils/ConversionWrapper.h redhawk_SOURCES_auto += utils/EnvironmentPathParser.cpp redhawk_SOURCES_auto += utils/EnvironmentPathParser.h redhawk_SOURCES_auto += utils/EventDispatcher.h @@ -67,3 +67,8 @@ redhawk_SOURCES_auto += utils/OverridableSingleton.h redhawk_SOURCES_auto += utils/ReferenceWrapper.h redhawk_SOURCES_auto += utils/SymlinkReader.cpp redhawk_SOURCES_auto += utils/SymlinkReader.h +redhawk_SOURCES_auto += utils/Updateable.h +redhawk_SOURCES_auto += utils/affinity.cpp +redhawk_SOURCES_auto += utils/affinity.h +redhawk_SOURCES_auto += utils/popen.cpp +redhawk_SOURCES_auto += utils/popen.h From b737914948c2ce49dc2bfa16a038d663dacbfb06 Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Fri, 23 Jun 2017 07:42:57 -0400 Subject: [PATCH 4/8] Added allocation properties for checking if images and/or volumes are available at the GPP --- GPP/GPP.prf.xml | 14 +- GPP/cpp/GPP.cpp | 379 ++++++++++++++++++++++++------------------- GPP/cpp/GPP.h | 10 ++ GPP/cpp/GPP_base.cpp | 18 +- GPP/cpp/GPP_base.h | 2 + 5 files changed, 251 insertions(+), 172 deletions(-) diff --git a/GPP/GPP.prf.xml b/GPP/GPP.prf.xml index 2634f3764..5b6483387 100644 --- a/GPP/GPP.prf.xml +++ b/GPP/GPP.prf.xml @@ -582,10 +582,22 @@ THRESHOLD_NOT_EXCEEDED: The measured value no longer exceeds the configured thr - + Absolute path to the omniORB configuration file that will be provided to the docker images being launched (if any). /etc/omniORB.cfg + + Docker Image to load + + + + + + Docker Volume to load + + + + diff --git a/GPP/cpp/GPP.cpp b/GPP/cpp/GPP.cpp index 8d48f1aa5..404983f68 100644 --- a/GPP/cpp/GPP.cpp +++ b/GPP/cpp/GPP.cpp @@ -248,7 +248,7 @@ class FindApp : public std::binary_function< GPP_i::component_description, std:: }; inline bool operator== (const GPP_i::component_description& s1, - const GPP_i::component_description& s2) { + const GPP_i::component_description& s2) { if (s1.appName!=s2.appName) return false; if (s1.identifier!=s2.identifier) @@ -496,6 +496,10 @@ void GPP_i::_init() { //setAllocationImpl("diskCapacity", this, &GPP_i::allocate_diskCapacity, &GPP_i::deallocate_diskCapacity); + // check for docker elements + setAllocationImpl("DCE:c38d28a6-351d-4aa4-a9ba-3cea51966838", this, &GPP_i::allocate_docker_image, &GPP_i::deallocate_docker_image); + setAllocationImpl("DCE:47a581c8-e31f-4284-a3ef-6d8b98385835", this, &GPP_i::allocate_docker_volume, &GPP_i::deallocate_docker_volume); + } @@ -1011,7 +1015,7 @@ void GPP_i::thresholds_changed(const thresholds_struct *ov, const thresholds_str if ( !(nv->mem_free < 0 ) && ov->mem_free != nv->mem_free ) { LOG_DEBUG(GPP_i, __FUNCTION__ << " THRESHOLDS.MEM_FREE CHANGED old/new " << ov->mem_free << "/" << nv->mem_free ); WriteLock wlock(pidLock); - int64_t init_mem_free = (int64_t) memInitVirtFree; + int64_t init_mem_free = (int64_t) memInitVirtFree; // type cast required for correct calc on 32bit os memInitCapacityPercent = (double)( (int64_t)init_mem_free - (int64_t)(nv->mem_free*thresh_mem_free_units) )/ (double) init_mem_free; if ( memInitCapacityPercent < 0.0 ) memInitCapacityPercent = 100.0; @@ -1086,9 +1090,65 @@ std::string GPP_i::find_exec(const char* name) { else path.clear(); } - return target; + return target; +} + +// Generic docker caller +bool GPP_i::check_docker(const std::string ¶ms) { + bool retval = false; + + std::string docker = GPP_i::find_exec("docker"); + + if (!docker.empty()) { + // Verify the image exists + char buffer[128]; + std::string result = ""; + std::string docker_query = docker + " " + params; + FILE* pipe = popen(docker_query.c_str(), "r"); + if (!pipe) + throw CF::ExecutableDevice::ExecuteFail(CF::CF_EINVAL, "Could not run popen"); + try { + while (!feof(pipe)) { + if (fgets(buffer, 128, pipe) != NULL) { + result += buffer; + } + } + } catch (...) { + pclose (pipe); + throw; + } + pclose(pipe); + + retval = !result.empty(); + } + return retval; +} + +// Check for a docker image tagged as value +bool GPP_i::check_docker_image(const std::string &value) { + return check_docker("images -q " + value); } +// Check for a docker volume named value +// TODO: Be less hackey. :-| +bool GPP_i::check_docker_volume(const std::string &value) { + std::string grep = GPP_i::find_exec("grep"); + return check_docker("volumes ls -q | " + grep + " " + value); +} + +bool GPP_i::allocate_docker_image(const std::string &value) { + return check_docker_image(value); +} + +void GPP_i::deallocate_docker_image(const std::string &value) { } + +bool GPP_i::allocate_docker_volume(const std::string &value) { + return check_docker_volume(value); +} + +void GPP_i::deallocate_docker_volume(const std::string &value) { } + + CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF::Properties& options, const CF::Properties& parameters) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, @@ -1115,15 +1175,15 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: redhawk::PropertyMap& tmp_params = redhawk::PropertyMap::cast(variable_parameters); float reservation_value = -1; if (tmp_params.find("RH::GPP::MODIFIED_CPU_RESERVATION_VALUE") != tmp_params.end()) { - double reservation_value_d; - if (!tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value)) { - if (tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value_d)) { - reservation_value = reservation_value_d; - } else { - reservation_value = -1; - } + double reservation_value_d; + if (!tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value)) { + if (tmp_params["RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"].getValue(reservation_value_d)) { + reservation_value = reservation_value_d; + } else { + reservation_value = -1; } - tmp_params.erase("RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"); + } + tmp_params.erase("RH::GPP::MODIFIED_CPU_RESERVATION_VALUE"); } naming_context_ior = tmp_params["NAMING_CONTEXT_IOR"].toString(); std::string app_id; @@ -1132,115 +1192,96 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: CF::Application_var _app = CF::Application::_nil(); CORBA::Object_var obj = ossie::corba::Orb()->string_to_object(naming_context_ior.c_str()); if (CORBA::is_nil(obj)) { - LOG_WARN(GPP_i, "Invalid application registrar IOR"); + LOG_WARN(GPP_i, "Invalid application registrar IOR"); } else { - CF::ApplicationRegistrar_var _appRegistrar = CF::ApplicationRegistrar::_nil(); - _appRegistrar = CF::ApplicationRegistrar::_narrow(obj); - if (CORBA::is_nil(_appRegistrar)) { - LOG_WARN(GPP_i, "Invalid application registrar IOR"); - } else { - _app = _appRegistrar->app(); - if (not CORBA::is_nil(_app)) { - app_id = ossie::corba::returnString(_app->identifier()); - } + CF::ApplicationRegistrar_var _appRegistrar = CF::ApplicationRegistrar::_nil(); + _appRegistrar = CF::ApplicationRegistrar::_narrow(obj); + if (CORBA::is_nil(_appRegistrar)) { + LOG_WARN(GPP_i, "Invalid application registrar IOR"); + } else { + _app = _appRegistrar->app(); + if (not CORBA::is_nil(_app)) { + app_id = ossie::corba::returnString(_app->identifier()); } + } } if (useScreen) { - std::string ld_lib_path(getenv("LD_LIBRARY_PATH")); - setenv("GPP_LD_LIBRARY_PATH",ld_lib_path.c_str(),1); - - std::string target = GPP_i::find_exec("screen"); - if (!target.empty()) { - prepend_args.push_back(target); - } - prepend_args.push_back("-D"); - prepend_args.push_back("-m"); - prepend_args.push_back("-c"); - prepend_args.push_back(binary_location+"gpp.screenrc"); - if ((not component_id.empty()) and (not name_binding.empty())) { - if (component_id.find("DCE:") != std::string::npos) { - component_id = component_id.substr(4, std::string::npos); - } - size_t waveform_boundary = component_id.find(":"); - std::string component_inst_id, waveform_name; - component_inst_id = component_id.substr(0, waveform_boundary); - waveform_name = component_id.substr(waveform_boundary+1, std::string::npos); - prepend_args.push_back("-S"); - prepend_args.push_back(waveform_name+"."+name_binding); - prepend_args.push_back("-t"); - prepend_args.push_back(waveform_name+"."+name_binding); + std::string ld_lib_path(getenv("LD_LIBRARY_PATH")); + setenv("GPP_LD_LIBRARY_PATH",ld_lib_path.c_str(),1); + + std::string target = GPP_i::find_exec("screen"); + if (!target.empty()) { + prepend_args.push_back(target); + } + prepend_args.push_back("-D"); + prepend_args.push_back("-m"); + prepend_args.push_back("-c"); + prepend_args.push_back(binary_location+"gpp.screenrc"); + if ((not component_id.empty()) and (not name_binding.empty())) { + if (component_id.find("DCE:") != std::string::npos) { + component_id = component_id.substr(4, std::string::npos); } + size_t waveform_boundary = component_id.find(":"); + std::string component_inst_id, waveform_name; + component_inst_id = component_id.substr(0, waveform_boundary); + waveform_name = component_id.substr(waveform_boundary+1, std::string::npos); + prepend_args.push_back("-S"); + prepend_args.push_back(waveform_name+"."+name_binding); + prepend_args.push_back("-t"); + prepend_args.push_back(waveform_name+"."+name_binding); + } } bool useDocker = false; if (tmp_params.find("__DOCKER_IMAGE__") != tmp_params.end()) { std::string image_name = tmp_params["__DOCKER_IMAGE__"].toString(); - LOG_DEBUG(GPP_i, __FUNCTION__ << "Component specified a Docker image: " << image_name); - - std::string target = GPP_i::find_exec("docker"); - if (!target.empty()) { - // Verify the image exists - char buffer[128]; - std::string result = ""; - std::string docker_query = target + " images -q " + image_name; - FILE* pipe = popen(docker_query.c_str(), "r"); - if (!pipe) - throw CF::ExecutableDevice::ExecuteFail(CF::CF_EINVAL, "Could not run popen"); - try { - while (!feof(pipe)) { - if (fgets(buffer, 128, pipe) != NULL) { - result += buffer; - } - } - } catch (...) { - pclose (pipe); - throw; - } - pclose(pipe); - if (result.empty()) { - CF::Properties invalidParameters; - invalidParameters.length(invalidParameters.length() + 1); - invalidParameters[invalidParameters.length() - 1].id = "__DOCKER_IMAGE__"; - invalidParameters[invalidParameters.length() - 1].value <<= image_name.c_str(); - throw CF::ExecutableDevice::InvalidParameters(invalidParameters); - } - - // Remove the ':' from the container name - std::string container_name(component_id); - std::replace(container_name.begin(), container_name.end(), ':', '-'); - - prepend_args.push_back(target); - prepend_args.push_back("run"); - prepend_args.push_back("--sig-proxy=true"); - prepend_args.push_back("--rm"); - prepend_args.push_back("--name"); - prepend_args.push_back(container_name); - prepend_args.push_back("--net=host"); - prepend_args.push_back("-v"); - prepend_args.push_back(docker_omniorb_cfg+":/etc/omniORB.cfg"); // Overload omniORB.cfg in the container - - // Additional arguments - if (tmp_params.find("__DOCKER_ARGS__") != tmp_params.end()) { - std::string docker_args_raw = tmp_params["__DOCKER_ARGS__"].toString(); - std::vector docker_args; - boost::split(docker_args, docker_args_raw, boost::is_any_of(" ") ); - BOOST_FOREACH( const std::string& arg, docker_args ) { - prepend_args.push_back(arg); - } - } - - // Finally, the image name - prepend_args.push_back(image_name); - LOG_DEBUG(GPP_i, __FUNCTION__ << "Component will launch within a Docker container using this image: " << image_name); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component specified a Docker image: " << image_name); + + // Check for the docker image + if (!check_docker_image(image_name)) { + CF::Properties invalidParameters; + invalidParameters.length(invalidParameters.length() + 1); + invalidParameters[invalidParameters.length() - 1].id = "__DOCKER_IMAGE__"; + invalidParameters[invalidParameters.length() - 1].value <<= image_name.c_str(); + throw CF::ExecutableDevice::InvalidParameters(invalidParameters); + } - useDocker = true; + // Remove the ':' from the container name + std::string container_name(component_id); + std::replace(container_name.begin(), container_name.end(), ':', '-'); + + std::string docker = GPP_i::find_exec("docker"); + prepend_args.push_back(docker); + prepend_args.push_back("run"); + prepend_args.push_back("--sig-proxy=true"); + prepend_args.push_back("--rm"); + prepend_args.push_back("--name"); + prepend_args.push_back(container_name); + prepend_args.push_back("--net=host"); + prepend_args.push_back("-v"); + prepend_args.push_back(docker_omniorb_cfg+":/etc/omniORB.cfg"); // Overload omniORB.cfg in the container + + // Additional arguments + if (tmp_params.find("__DOCKER_ARGS__") != tmp_params.end()) { + std::string docker_args_raw = tmp_params["__DOCKER_ARGS__"].toString(); + std::vector docker_args; + boost::split(docker_args, docker_args_raw, boost::is_any_of(" ") ); + BOOST_FOREACH( const std::string& arg, docker_args ) { + prepend_args.push_back(arg); } + } + + // Finally, the image name + prepend_args.push_back(image_name); + LOG_DEBUG(GPP_i, __FUNCTION__ << "Component will launch within a Docker container using this image: " << image_name); + + useDocker = true; } CF::ExecutableDevice::ProcessID_Type ret_pid; try { - ret_pid = do_execute(name, options, tmp_params, prepend_args, useDocker); - addProcess(ret_pid, app_id, component_id, reservation_value); + ret_pid = do_execute(name, options, tmp_params, prepend_args, useDocker); + addProcess(ret_pid, app_id, component_id, reservation_value); } catch ( ... ) { - throw; + throw; } return ret_pid; } @@ -1253,52 +1294,50 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::execute (const char* name, const CF: ************************************************************************* */ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const CF::Properties& options, const CF::Properties& parameters, const std::vector prepend_args, const bool use_docker) throw (CORBA::SystemException, CF::Device::InvalidState, CF::ExecutableDevice::InvalidFunction, CF::ExecutableDevice::InvalidParameters, CF::ExecutableDevice::InvalidOptions, CF::InvalidFileName, CF::ExecutableDevice::ExecuteFail) { - CF::Properties invalidOptions; - std::string path; - char* tmp; - - // throw and error if name does not begin with a / - if (strncmp(name, "/", 1) != 0) - throw CF::InvalidFileName(CF::CF_EINVAL, "Filename must be absolute"); - if (isLocked()) - throw CF::Device::InvalidState("System is locked down"); - if (isDisabled()) - throw CF::Device::InvalidState("System is disabled"); - - //process options and throw InvalidOptions errors if they are not ULong - for (CORBA::ULong i = 0; i < options.length(); ++i) { - if (options[i].id == CF::ExecutableDevice::PRIORITY_ID) { - CORBA::TypeCode_var atype = options[i].value.type(); - if (atype->kind() != CORBA::tk_ulong) { - invalidOptions.length(invalidOptions.length() + 1); - invalidOptions[invalidOptions.length() - 1].id = options[i].id; - invalidOptions[invalidOptions.length() - 1].value - = options[i].value; - } else - LOG_WARN(GPP_i, "Received a PRIORITY_ID execute option...ignoring.") - } - if (options[i].id == CF::ExecutableDevice::STACK_SIZE_ID) { - CORBA::TypeCode_var atype = options[i].value.type(); - if (atype->kind() != CORBA::tk_ulong) { - invalidOptions.length(invalidOptions.length() + 1); - invalidOptions[invalidOptions.length() - 1].id = options[i].id; - invalidOptions[invalidOptions.length() - 1].value - = options[i].value; - } else - LOG_WARN(GPP_i, "Received a STACK_SIZE_ID execute option...ignoring.") - } - } + CF::Properties invalidOptions; + std::string path; + char* tmp; + + // throw and error if name does not begin with a / + if (strncmp(name, "/", 1) != 0) + throw CF::InvalidFileName(CF::CF_EINVAL, "Filename must be absolute"); + if (isLocked()) + throw CF::Device::InvalidState("System is locked down"); + if (isDisabled()) + throw CF::Device::InvalidState("System is disabled"); + + //process options and throw InvalidOptions errors if they are not ULong + for (CORBA::ULong i = 0; i < options.length(); ++i) { + if (options[i].id == CF::ExecutableDevice::PRIORITY_ID) { + CORBA::TypeCode_var atype = options[i].value.type(); + if (atype->kind() != CORBA::tk_ulong) { + invalidOptions.length(invalidOptions.length() + 1); + invalidOptions[invalidOptions.length() - 1].id = options[i].id; + invalidOptions[invalidOptions.length() - 1].value = options[i].value; + } else + LOG_WARN(GPP_i, "Received a PRIORITY_ID execute option...ignoring.") + } + if (options[i].id == CF::ExecutableDevice::STACK_SIZE_ID) { + CORBA::TypeCode_var atype = options[i].value.type(); + if (atype->kind() != CORBA::tk_ulong) { + invalidOptions.length(invalidOptions.length() + 1); + invalidOptions[invalidOptions.length() - 1].id = options[i].id; + invalidOptions[invalidOptions.length() - 1].value = options[i].value; + } else + LOG_WARN(GPP_i, "Received a STACK_SIZE_ID execute option...ignoring.") + } + } - if (invalidOptions.length() > 0) { - throw CF::ExecutableDevice::InvalidOptions(invalidOptions); - } + if (invalidOptions.length() > 0) { + throw CF::ExecutableDevice::InvalidOptions(invalidOptions); + } - // retrieve current working directory - tmp = getcwd(NULL, 200); - if (tmp != NULL) { - path = std::string(tmp); - free(tmp); - } + // retrieve current working directory + tmp = getcwd(NULL, 200); + if (tmp != NULL) { + path = std::string(tmp); + free(tmp); + } // append relative path of the executable path.append(name); @@ -1339,11 +1378,11 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const } if (use_docker) { - // docker container will come up at its own $SDRROOT - // 'name' is prefixed by /, so we prefix it with '.' here - args.push_back("." + std::string(name)); + // docker container will come up at its own $SDRROOT + // 'name' is prefixed by /, so we prefix it with '.' here + args.push_back("." + std::string(name)); } else { - args.push_back(path); + args.push_back(path); } LOG_DEBUG(GPP_i, "Building param list for process " << path); @@ -1449,25 +1488,25 @@ CF::ExecutableDevice::ProcessID_Type GPP_i::do_execute (const char* name, const // Run executable while (true) { - if (strcmp(argv[0], "valgrind") == 0) { - // Find valgrind in the path - returnval = execvp(argv[0], &argv[0]); - } else { - returnval = execv(argv[0], &argv[0]); - } - - num_retries--; - if( num_retries <= 0 || errno!=ETXTBSY) - break; - - // Only retry on "text file busy" error - LOG_WARN(GPP_i, "execv() failed, retrying... (cmd=" << path << " msg=\"" << strerror(errno) << "\" retries=" << num_retries << ")"); - usleep(100000); + if (strcmp(argv[0], "valgrind") == 0) { + // Find valgrind in the path + returnval = execvp(argv[0], &argv[0]); + } else { + returnval = execv(argv[0], &argv[0]); + } + + num_retries--; + if( num_retries <= 0 || errno!=ETXTBSY) + break; + + // Only retry on "text file busy" error + LOG_WARN(GPP_i, "execv() failed, retrying... (cmd=" << path << " msg=\"" << strerror(errno) << "\" retries=" << num_retries << ")"); + usleep(100000); } if( returnval ) { - LOG_ERROR(GPP_i, "Error when calling execv() (cmd=" << path << " errno=" << errno << " msg=\"" << strerror(errno) << "\")"); - ossie::corba::OrbShutdown(true); + LOG_ERROR(GPP_i, "Error when calling execv() (cmd=" << path << " errno=" << errno << " msg=\"" << strerror(errno) << "\")"); + ossie::corba::OrbShutdown(true); } LOG_DEBUG(GPP_i, "Exiting FAILED subprocess:" << returnval ); @@ -2959,7 +2998,7 @@ int GPP_i::_get_deploy_on_partition() { double m_idle_thresh = iter->idle_threshold + ( iter->idle_cap_mod * n_reservations) + (float)loadCapacity/(float)iter->cpus.size(); RH_NL_DEBUG("GPP", " Looking for execute partition (processor socket:" << iter->id << ") IDLE: actual/avg/threshold limit/modified " << - iter->get_idle_percent() << "/" << iter->get_idle_average() << "/" << iter->idle_threshold << "/" << m_idle_thresh ); + iter->get_idle_percent() << "/" << iter->get_idle_average() << "/" << iter->idle_threshold << "/" << m_idle_thresh ); if ( iter->get_idle_percent() > m_idle_thresh ) { psoc=iter->id; break; diff --git a/GPP/cpp/GPP.h b/GPP/cpp/GPP.h index c3fbf99c3..623e31baf 100644 --- a/GPP/cpp/GPP.h +++ b/GPP/cpp/GPP.h @@ -103,6 +103,16 @@ class GPP_i : public GPP_base CF::ExecutableDevice::InvalidFunction, CF::Device::InvalidState, CORBA::SystemException); + bool check_docker(const std::string ¶ms); + bool check_docker_image(const std::string &value); + bool check_docker_volume(const std::string &value); + + bool allocate_docker_image(const std::string &value); + void deallocate_docker_image(const std::string &value); + + bool allocate_docker_volume(const std::string &value); + void deallocate_docker_volume(const std::string &value); + void terminate (CF::ExecutableDevice::ProcessID_Type processId) throw (CORBA::SystemException, CF::ExecutableDevice::InvalidProcess, CF::Device::InvalidState); diff --git a/GPP/cpp/GPP_base.cpp b/GPP/cpp/GPP_base.cpp index ebb513161..2e103b8a6 100644 --- a/GPP/cpp/GPP_base.cpp +++ b/GPP/cpp/GPP_base.cpp @@ -182,13 +182,29 @@ void GPP_base::loadProperties() "property"); addProperty(docker_omniorb_cfg, - "docker_omniorb_cfg", + "DCE:0b5c1a83-7226-4705-a3be-eff5a8a9f38a", "docker_omniorb_cfg", "readonly", "/etc/omniORB.cfg", "external", "property"); + addProperty(docker_image, + "DCE:c38d28a6-351d-4aa4-a9ba-3cea51966838", + "docker_image", + "readwrite", + "", + "eq", + "allocation"); + + addProperty(docker_volume, + "DCE:DCE:47a581c8-e31f-4284-a3ef-6d8b98385835", + "docker_volume", + "readwrite", + "", + "eq", + "allocation"); + addProperty(mcastnicInterface, "", "DCE:4e416acc-3144-47eb-9e38-97f1d24f7700", diff --git a/GPP/cpp/GPP_base.h b/GPP/cpp/GPP_base.h index 5d4d80f39..1aefab973 100644 --- a/GPP/cpp/GPP_base.h +++ b/GPP/cpp/GPP_base.h @@ -55,6 +55,8 @@ class GPP_base : public ExecutableDevice_impl, protected ThreadedComponent std::string hostName; std::string componentOutputLog; std::string docker_omniorb_cfg; + std::string docker_image; + std::string docker_volume; bool useScreen; advanced_struct advanced; From 7f58d748710bc0ca6f0ab0024365c46435a208ed Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Thu, 24 Aug 2017 08:25:15 -0400 Subject: [PATCH 5/8] Base class ID for docker_volume was wrong. Closes #3 --- GPP/cpp/GPP_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPP/cpp/GPP_base.cpp b/GPP/cpp/GPP_base.cpp index 2e103b8a6..584aeea47 100644 --- a/GPP/cpp/GPP_base.cpp +++ b/GPP/cpp/GPP_base.cpp @@ -198,7 +198,7 @@ void GPP_base::loadProperties() "allocation"); addProperty(docker_volume, - "DCE:DCE:47a581c8-e31f-4284-a3ef-6d8b98385835", + "DCE:47a581c8-e31f-4284-a3ef-6d8b98385835", "docker_volume", "readwrite", "", From 5db9554f743625690e7d75da6ea1cc07cb6389f3 Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Thu, 24 Aug 2017 08:51:49 -0400 Subject: [PATCH 6/8] Corrected docker_volume -related command. Fixes #4. --- GPP/cpp/GPP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPP/cpp/GPP.cpp b/GPP/cpp/GPP.cpp index 404983f68..072a475b2 100644 --- a/GPP/cpp/GPP.cpp +++ b/GPP/cpp/GPP.cpp @@ -1133,7 +1133,7 @@ bool GPP_i::check_docker_image(const std::string &value) { // TODO: Be less hackey. :-| bool GPP_i::check_docker_volume(const std::string &value) { std::string grep = GPP_i::find_exec("grep"); - return check_docker("volumes ls -q | " + grep + " " + value); + return check_docker("volume ls -q | " + grep + " " + value); } bool GPP_i::allocate_docker_image(const std::string &value) { From 26b48d4ed9e46ed32f00565dc6a22f22d5bbfefd Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Thu, 24 Aug 2017 08:52:26 -0400 Subject: [PATCH 7/8] Added object files to gitignore. --- GPP/cpp/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/GPP/cpp/.gitignore b/GPP/cpp/.gitignore index bc1a67473..76c749e19 100644 --- a/GPP/cpp/.gitignore +++ b/GPP/cpp/.gitignore @@ -11,3 +11,4 @@ configure depcomp install-sh missing +*.o From 5940b54d8dd96baeefc118c71b38a29b247875de Mon Sep 17 00:00:00 2001 From: Thomas Goodwin Date: Thu, 24 Aug 2017 09:58:12 -0400 Subject: [PATCH 8/8] The `docker_image` and `docker_volume` properties should have been marked external so that Components can use them as property references. --- GPP/GPP.prf.xml | 4 ++-- GPP/cpp/GPP_base.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/GPP/GPP.prf.xml b/GPP/GPP.prf.xml index 5b6483387..e6c400b67 100644 --- a/GPP/GPP.prf.xml +++ b/GPP/GPP.prf.xml @@ -592,12 +592,12 @@ THRESHOLD_NOT_EXCEEDED: The measured value no longer exceeds the configured thr Docker Image to load - + Docker Volume to load - + diff --git a/GPP/cpp/GPP_base.cpp b/GPP/cpp/GPP_base.cpp index 584aeea47..1a409d904 100644 --- a/GPP/cpp/GPP_base.cpp +++ b/GPP/cpp/GPP_base.cpp @@ -194,7 +194,7 @@ void GPP_base::loadProperties() "docker_image", "readwrite", "", - "eq", + "external", "allocation"); addProperty(docker_volume, @@ -202,7 +202,7 @@ void GPP_base::loadProperties() "docker_volume", "readwrite", "", - "eq", + "external", "allocation"); addProperty(mcastnicInterface,