Commit 83beb192 authored by Swann Perarnau's avatar Swann Perarnau

Merge branch 'exec' into 'master'

Add support for command execution in argo_nodeos_config

See merge request !1
parents a8937eb2 f805c49b
......@@ -30,3 +30,13 @@
# Debug files
*.dSYM/
Makefile
Makefile.in
aclocal.m4
autom4te.cache
config.log
config.status
configure
libtool
m4
.deps
argo_nodeos_config
config.h
config.h.in
stamp-h1
......@@ -524,7 +524,10 @@ enum Option_val
OV_DELETE_SERVICE_OS,
OV_RESET
OV_RESET,
/*--exec="name:'c0' argv='argv0 argv1'"*/
OV_EXEC
};
......@@ -546,6 +549,7 @@ struct option long_options[] = {
{"detach_from_container", required_argument, NULL, OV_DETACH_FROM_CONTAINER},
{"migrate_to_container", required_argument, NULL, OV_MIGRATE_TO_CONTAINER},
{"reset", no_argument, NULL, OV_RESET},
{"exec", required_argument, NULL, OV_EXEC},
{0, 0, 0, 0}
};
......@@ -683,6 +687,9 @@ bool parse_for_node_config(int argc, char** argv, Container_manager& cm)
case OV_RESET:
cm.reset();
break;
case OV_EXEC:
cm.exec(optarg);
break;
case '?':
case ':':
cmd_error = true;
......@@ -757,10 +764,19 @@ int main(int argc, char** argv)
argo_exit(EXIT_FAILURE, e.what());
}
char** exec_argv = cm->get_exec_argv();
delete cm;
rlock.unlock();
release();
/* We perform the execve(2) after all the cleanup is done. */
if (exec_argv)
{
execvp(exec_argv[0], exec_argv);
argo_exit(EXIT_FAILURE, "Command execution failed", errno);
}
argo_exit(EXIT_SUCCESS);
return 0;
}
......@@ -275,7 +275,7 @@ void Container_manager::create_root_cgroups()
void Container_manager::migrate_service_os()
{
system("for t in `cat /sys/fs/cgroup/cpuset/tasks`; do /bin/echo $t > /sys/fs/cgroup/cpuset/argo/service_os/tasks; done 2>/dev/null");
int n = system("for t in `cat /sys/fs/cgroup/cpuset/tasks`; do /bin/echo $t > /sys/fs/cgroup/cpuset/argo/service_os/tasks; done 2>/dev/null");
return;
vector<int> sos_tasks;
retrieve_from_file<int>( _cgroup_root + "cpuset/tasks",
......@@ -375,6 +375,9 @@ void Container_manager::load_existing_containers_as_root()
Container_manager::~Container_manager()
#if __cplusplus >= 201103L
noexcept(false)
#endif
{
std::ofstream ownership_map_file;
ownership_map_file.open(OWNERSHIP_MAP);
......@@ -681,8 +684,8 @@ void Container_manager::alter_service_os(string command)
#endif
String_parser sp(command);
sp.parse();
vector<string> allowed_keys(
{"cpus", "+cpus", "-cpus", "mems", "+mems", "-mems", "mem_migrate"});
const char* initkeys[] = {"cpus", "+cpus", "-cpus", "mems", "+mems", "-mems", "mem_migrate"};
vector<string> allowed_keys(initkeys, initkeys + sizeof(initkeys) / sizeof(initkeys[0]));
THROW_ON_BAD_INPUT_IF(sp.has_forbidden_keys(allowed_keys),
"Invalid service_os alteration command");
......@@ -766,7 +769,8 @@ void Container_manager::create_service_os(string command)
"The node already has a service_os");
String_parser sp(command);
sp.parse();
vector<string> allowed_keys({"cpus", "mems"});
const char* initkeys[] = {"cpus", "mems"};
vector<string> allowed_keys(initkeys, initkeys + sizeof(initkeys) / sizeof(initkeys[0]));
THROW_ON_BAD_INPUT_IF(sp.has_forbidden_keys(allowed_keys),
"Invalid service_os creation command");
......@@ -853,7 +857,7 @@ void Container_manager::reset()
clean_config("");
/*Temporary ugly brutal hack [JZ] (\_/)*/
system("rmdir /sys/fs/cgroup/cpuset/argo/argo_containers/ && rmdir /sys/fs/cgroup/cpuset/argo/");
int n = system("rmdir /sys/fs/cgroup/cpuset/argo/argo_containers/ && rmdir /sys/fs/cgroup/cpuset/argo/");
}
void Container_manager::attach_to_container(string command)
......@@ -866,7 +870,7 @@ void Container_manager::attach_to_container(string command)
string name;
sp.get_string("name", name);
Argo_container *cc = find_by_name(name);
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + "does not exists");
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists");
vector<int> tasks;
sp.get_int_list("pids", tasks);
......@@ -921,7 +925,7 @@ void Container_manager::detach_from_container(string command)
string name;
sp.get_string("name", name);
Argo_container *cc = find_by_name(name);
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + "does not exists");
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists");
vector<int> tasks;
sp.get_int_list("pids", tasks);
......@@ -946,7 +950,7 @@ void Container_manager::migrate_to_container(string command)
string name;
sp.get_string("name", name);
Argo_container *cc = find_by_name(name);
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + "does not exists");
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists");
vector<int> tasks;
sp.get_int_list("pids", tasks);
......@@ -961,12 +965,13 @@ void Container_manager::migrate_to_container(string command)
" because it belongs to another user! Alternatively, the action can be performed as root");
std::ostringstream oss;
for(auto task : tasks)
for(vector<int>::iterator task = tasks.begin(); task != tasks.end(); task++)
{
bool is_task_contained = false;
for(auto cont : _containers)
for(vector<Argo_container*>::iterator cont = _containers.begin();
cont != _containers.end(); cont++)
{
if(cont->has_task(task))
if((*cont)->has_task(*task))
{
is_task_contained = true;
break;
......@@ -974,7 +979,7 @@ void Container_manager::migrate_to_container(string command)
}
if(!is_task_contained)
{
oss<<"Task "<<task<<" is not in any Argo container; it cannot be migrated";
oss<<"Task "<<*task<<" is not in any Argo container; it cannot be migrated";
THROW_ON_ERRONEOUS_ACTION(oss.str());
}
}
......@@ -1065,3 +1070,57 @@ void Container_manager::clean_config(string command)
_containers.clear();
_logger->log(LOG_TYPE_INFO, "Config has been cleaned.");
}
void Container_manager::exec(string command)
{
String_parser sp(command);
sp.parse();
THROW_ON_BAD_INPUT_IF(!sp.has_key("name") || !sp.has_key("argv"),
"Bad exec command");
string name;
sp.get_string("name", name);
Argo_container *cc = find_by_name(name);
THROW_ON_ERRONEOUS_ACTION_IF(!cc, "Container " + name + " does not exists");
THROW_ON_FORBIDDEN_ACTION_IF(ruid != 0 && (ruid != cc->get_owner()),
"Can't execute in container " + cc->get_name() +
" because it belongs to another user! Alternatively, the action can be performed as root");
string argv;
sp.get_string("argv", argv);
if (argv[0] == '\'') /* Strip ' from both ends. */
argv = argv.substr(1, argv.size() - 2);
vector<string> argvs;
split(argv, ' ', argvs);
/* Remove a single layer of backslashes. */
for (vector<string>::iterator i = argvs.begin(); i != argvs.end(); ++i)
for (string::iterator j = i->begin(); j != i->end(); ++j)
if (*j == '\\')
i->erase(j);
vector<int> tasks(1, getpid());
cc->add_tasks(tasks);
cc->commit_last_changes();
std::ostringstream ss;
ss << "About to execute";
/* We use global allocators so that _exec_argv survives after
the container manager is destroyed. */
_exec_argv = new char*[argvs.size() + 1];
for (int i = 0; i < argvs.size(); i++)
{
_exec_argv[i] = new char[argvs[i].size() + 1];
strcpy(_exec_argv[i], argvs[i].c_str());
ss << " '" << argvs[i] << "'";
}
_exec_argv[argvs.size()] = NULL;
_logger->log(LOG_TYPE_INFO, ss.str());
}
......@@ -33,6 +33,8 @@ class Container_manager
string _argo_service_os_cgroup;
string _argo_argo_containers_root;
char ** _exec_argv;
Container_manager(Container_manager& orig) = delete;
Container_manager& operator = (const Container_manager& orig) = delete;
......@@ -223,11 +225,16 @@ class Container_manager
Container_manager(ILogger* logger,
Error_behavior error_behavior,
string cgroup_root = DEFAULT_CGROUP_ROOT);
~Container_manager();
~Container_manager()
#if __cplusplus >= 201103L
noexcept(false)
#endif
;
inline const string* const get_argo_argo_container_root() const {return &_cgroup_root;}
inline Error_behavior get_error_behaviour()const {return _error_behavior;}
inline ILogger* get_logger() const {return _logger;}
inline char** get_exec_argv() const {return _exec_argv;}
void show_available_resources(string command);
void create_container(string command);
......@@ -243,6 +250,7 @@ class Container_manager
void alter_service_os(string command);
void delete_service_os();
void reset();
void exec(string command);
};
#endif // __CONTAINER_MANAGER_HPP__
......
......@@ -31,7 +31,7 @@ Resource_locker::Resource_locker(const string& filename, const string& path):
TRACE_LOC_ON_MASK(RESOURCE_LOCKER_MASK, "euid = %d; ruid = %d\n",
geteuid(), getuid());
_fd = open(fname.c_str(), O_WRONLY|O_CREAT);
_fd = open(fname.c_str(), O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
if(_fd == -1)
{
argo_exit(EXIT_FAILURE, "Failure to open " + filename);
......
......@@ -39,5 +39,5 @@ void Syslogger::log(Log_type type, const string& message, int errnum)
{
string msg_out;
if(prepare_log(type, message, msg_out, errnum))
syslog(log_type_to_priority(type), msg_out.c_str());
syslog(log_type_to_priority(type), "%s", msg_out.c_str());
}
......@@ -23,6 +23,7 @@
vector<string> &split(const string &str_in, char delim, vector<string> &tokens)
{
#if 0
std::stringstream ss(str_in);
string token;
tokens.clear();
......@@ -32,6 +33,9 @@ vector<string> &split(const string &str_in, char delim, vector<string> &tokens)
tokens.push_back(token);
}
return tokens;
#endif
string delims(1, delim);
return split(str_in, delims, tokens);
}
vector<string> &split(const string &str_in, const string &delims,
......@@ -49,6 +53,30 @@ vector<string> &split(const string &str_in, const string &delims,
for(int i=0; i<(int)delims.size(); i++)
{
for(int j=start; j<length; j++)
{
if(str_in[j] == '\\')
{
j++;
continue;
}
if(str_in[j] == '\'')
{
for (j++; j<length; j++)
{
if(str_in[j] == '\\')
{
j++;
continue;
}
if (str_in[j] == '\'')
break;
}
if (j == length) /* Parse error */
{
tokens.clear();
return tokens;
}
}
if(str_in[j] == delims[i])
{
next_delim_pos = MIN(j,next_delim_pos);
......@@ -56,6 +84,7 @@ vector<string> &split(const string &str_in, const string &delims,
break;
}
}
}
if(found)
{
string token = str_in.substr(start, next_delim_pos-start);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment