// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- // Copyright (c) 2001-2007 International Computer Science Institute // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software") // to deal in the Software without restriction, subject to the conditions // listed in the XORP LICENSE file. These conditions include: you must // preserve this copyright notice, and you cannot mention the copyright // holders in advertising related to the Software without their permission. // The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This // notice is a summary of the XORP LICENSE file; the license in that file is // legally binding. #ident "$XORP: xorp/rtrmgr/module_command.cc,v 1.37 2007/02/16 22:47:23 pavlin Exp $" #include "rtrmgr_module.h" #include "libxorp/xorp.h" #include "libxorp/xlog.h" #include "libxorp/debug.h" #include "libxipc/xrl_router.hh" #include "module_command.hh" #include "rtrmgr_error.hh" #include "task.hh" #include "template_tree.hh" #include "template_tree_node.hh" #include "master_conf_tree_node.hh" #include "util.hh" #include "xrldb.hh" static string strip_quotes(const string& command, const string& value) throw (ParseError) { string error_msg; size_t old_size = value.size(); string tmp_value = unquote(value); if (tmp_value.size() != old_size && tmp_value.size() != old_size - 2) { error_msg = c_format("subcommand %s has invalid argument: %s", command.c_str(), value.c_str()); xorp_throw(ParseError, error_msg); } if (unquote(tmp_value).empty()) { error_msg = c_format("subcommand %s has empty argument", command.c_str()); xorp_throw(ParseError, error_msg); } return tmp_value; } ModuleCommand::ModuleCommand(TemplateTree& template_tree, TemplateTreeNode& template_tree_node, const string& cmd_name) : Command(template_tree_node, cmd_name), _tt(template_tree), _start_commit(NULL), _end_commit(NULL), _status_method(NULL), _startup_method(NULL), _shutdown_method(NULL), _execute_done(false), _verbose(template_tree.verbose()) { XLOG_ASSERT(cmd_name == "%modinfo"); } ModuleCommand::~ModuleCommand() { if (_start_commit != NULL) delete _start_commit; if (_end_commit != NULL) delete _end_commit; if (_status_method != NULL) delete _status_method; if (_startup_method != NULL) delete _startup_method; if (_shutdown_method != NULL) delete _shutdown_method; } void ModuleCommand::add_action(const list& action, const XRLdb& xrldb) throw (ParseError) { size_t expected_action_size = 2; // // Check the subcommand size // if (action.size() < expected_action_size) { xorp_throw(ParseError, "too few parameters to %modinfo"); } string subcommand = action.front(); if ((subcommand == "start_commit") || (subcommand == "end_commit") || (subcommand == "status_method") || (subcommand == "startup_method") || (subcommand == "shutdown_method")) { expected_action_size = 3; } if (action.size() > expected_action_size) { xorp_throw(ParseError, "too many parameters to %modinfo"); } if (action.size() < expected_action_size) { xorp_throw(ParseError, "too few parameters to %modinfo"); } typedef list::const_iterator CI; CI ptr = action.begin(); string cmd = *ptr; ++ptr; string value = *ptr; if (cmd == "provides") { _module_name = strip_quotes(cmd, value); _tt.register_module(_module_name, this); template_tree_node().set_subtree_module_name(_module_name); } else if (cmd == "depends") { if (_module_name.empty()) { xorp_throw(ParseError, "\"depends\" must be preceded by \"provides\""); } _depends.push_back(strip_quotes(cmd, value)); } else if (cmd == "path") { if (_module_name == "") { xorp_throw(ParseError, "\"path\" must be preceded by \"provides\""); } if (_module_exec_path != "") { xorp_throw(ParseError, "duplicate \"path\" subcommand"); } _module_exec_path = strip_quotes(cmd, value); } else if (cmd == "default_targetname") { if (_module_name == "") { xorp_throw(ParseError, "\"default_targetname\" must be preceded by \"provides\""); } _default_target_name = strip_quotes(cmd, value); template_tree_node().set_subtree_default_target_name(_default_target_name); } else if (cmd == "start_commit") { debug_msg("start_commit:\n"); list::const_iterator iter; for (iter = action.begin(); iter != action.end(); ++iter) debug_msg(">%s< ", (*iter).c_str()); debug_msg("\n"); list newaction = action; newaction.pop_front(); do { if (newaction.front() == "xrl") { _start_commit = new XrlAction(template_tree_node(), newaction, xrldb); break; } if (newaction.front() == "program") { _start_commit = new ProgramAction(template_tree_node(), newaction); break; } _start_commit = new Action(template_tree_node(), newaction); break; } while (false); } else if (cmd == "end_commit") { list newaction = action; newaction.pop_front(); do { if (newaction.front() == "xrl") { _end_commit = new XrlAction(template_tree_node(), newaction, xrldb); break; } if (newaction.front() == "program") { _end_commit = new ProgramAction(template_tree_node(), newaction); break; } _end_commit = new Action(template_tree_node(), newaction); break; } while (false); } else if (cmd == "status_method") { list newaction = action; newaction.pop_front(); do { if (newaction.front() == "xrl") { _status_method = new XrlAction(template_tree_node(), newaction, xrldb); break; } if (newaction.front() == "program") { _status_method = new ProgramAction(template_tree_node(), newaction); break; } _status_method = new Action(template_tree_node(), newaction); break; } while (false); } else if (cmd == "startup_method") { list newaction = action; newaction.pop_front(); do { if (newaction.front() == "xrl") { _startup_method = new XrlAction(template_tree_node(), newaction, xrldb); break; } if (newaction.front() == "program") { _startup_method = new ProgramAction(template_tree_node(), newaction); break; } _startup_method = new Action(template_tree_node(), newaction); break; } while (false); } else if (cmd == "shutdown_method") { list newaction = action; newaction.pop_front(); do { if (newaction.front() == "xrl") { _shutdown_method = new XrlAction(template_tree_node(), newaction, xrldb); break; } if (newaction.front() == "program") { _shutdown_method = new ProgramAction(template_tree_node(), newaction); break; } _shutdown_method = new Action(template_tree_node(), newaction); break; } while (false); } else { string err = "invalid subcommand \"" + cmd + "\" to %modinfo"; xorp_throw(ParseError, err); } } bool ModuleCommand::expand_actions(string& error_msg) { // // Expand all module-specific methods // if (_start_commit != NULL) { if (_start_commit->expand_action(error_msg) != true) return (false); } if (_end_commit != NULL) { if (_end_commit->expand_action(error_msg) != true) return (false); } if (_status_method != NULL) { if (_status_method->expand_action(error_msg) != true) return (false); } if (_startup_method != NULL) { if (_startup_method->expand_action(error_msg) != true) return (false); } if (_shutdown_method != NULL) { if (_shutdown_method->expand_action(error_msg) != true) return (false); } return (true); } bool ModuleCommand::check_referred_variables(string& error_msg) const { // // Check all module-specific methods // if (_start_commit != NULL) { if (_start_commit->check_referred_variables(error_msg) != true) return (false); } if (_end_commit != NULL) { if (_end_commit->check_referred_variables(error_msg) != true) return (false); } if (_status_method != NULL) { if (_status_method->check_referred_variables(error_msg) != true) return (false); } if (_startup_method != NULL) { if (_startup_method->check_referred_variables(error_msg) != true) return (false); } if (_shutdown_method != NULL) { if (_shutdown_method->check_referred_variables(error_msg) != true) return (false); } return (true); } Validation* ModuleCommand::startup_validation(TaskManager& taskmgr) const { if ((_status_method != NULL) && (_startup_method != NULL)) { XrlAction* xa = dynamic_cast(_status_method); if (xa != NULL) { return new XrlStatusStartupValidation(_module_name, *xa, taskmgr); } ProgramAction* pa = dynamic_cast(_status_method); if (pa != NULL) { return new ProgramStatusStartupValidation(_module_name, *pa, taskmgr); } return NULL; } else { return new DelayValidation(_module_name, taskmgr.eventloop(), 2000, _verbose); } } Validation* ModuleCommand::config_validation(TaskManager& taskmgr) const { if (_status_method != NULL) { XrlAction* xa = dynamic_cast(_status_method); if (xa != NULL) { return new XrlStatusConfigMeValidation(_module_name, *xa, taskmgr); } ProgramAction* pa = dynamic_cast(_status_method); if (pa != NULL) { return new ProgramStatusConfigMeValidation(_module_name, *pa, taskmgr); } return NULL; } else { return new DelayValidation(_module_name, taskmgr.eventloop(), 2000, _verbose); } } Validation* ModuleCommand::ready_validation(TaskManager& taskmgr) const { if (_status_method != NULL) { XrlAction* xa = dynamic_cast(_status_method); if (xa != NULL) { return new XrlStatusReadyValidation(_module_name, *xa, taskmgr); } ProgramAction* pa = dynamic_cast(_status_method); if (pa != NULL) { return new ProgramStatusReadyValidation(_module_name, *pa, taskmgr); } return NULL; } else { return new DelayValidation(_module_name, taskmgr.eventloop(), 2000, _verbose); } } Validation* ModuleCommand::shutdown_validation(TaskManager& taskmgr) const { if (_status_method != NULL) { XrlAction* xa = dynamic_cast(_status_method); if (xa != NULL) { return new XrlStatusShutdownValidation(_module_name, *xa, taskmgr); } ProgramAction* pa = dynamic_cast(_status_method); if (pa != NULL) { return new ProgramStatusShutdownValidation(_module_name, *pa, taskmgr); } return NULL; } else { return new DelayValidation(_module_name, taskmgr.eventloop(), 2000, _verbose); } } Startup* ModuleCommand::startup_method(TaskManager& taskmgr) const { if (_startup_method != NULL) { XrlAction* xa = dynamic_cast(_startup_method); if (xa != NULL) { return new XrlStartup(_module_name, *xa, taskmgr); } ProgramAction* pa = dynamic_cast(_startup_method); if (pa != NULL) { return new ProgramStartup(_module_name, *pa, taskmgr); } return NULL; } else { // The startup method is optional return NULL; } } Shutdown* ModuleCommand::shutdown_method(TaskManager& taskmgr) const { if (_shutdown_method != NULL) { XrlAction* xa = dynamic_cast(_shutdown_method); if (xa != NULL) { return new XrlShutdown(_module_name, *xa, taskmgr); } ProgramAction* pa = dynamic_cast(_shutdown_method); if (pa != NULL) { return new ProgramShutdown(_module_name, *pa, taskmgr); } return NULL; } else { // We can always kill it from the module manager. return NULL; } } int ModuleCommand::start_transaction(MasterConfigTreeNode& ctn, TaskManager& task_manager) const { if (_start_commit == NULL) return XORP_OK; XrlAction *xa = dynamic_cast(_start_commit); if (xa != NULL) { XrlRouter::XrlCallback cb = callback( this, &ModuleCommand::xrl_action_complete, &ctn, _start_commit, string("start transaction")); return xa->execute(ctn, task_manager, cb); } ProgramAction *pa = dynamic_cast(_start_commit); if (pa != NULL) { TaskProgramItem::ProgramCallback cb = callback( this, &ModuleCommand::program_action_complete, &ctn, _start_commit, string("start transaction")); return pa->execute(ctn, task_manager, cb); } XLOG_UNREACHABLE(); } int ModuleCommand::end_transaction(MasterConfigTreeNode& ctn, TaskManager& task_manager) const { if (_end_commit == NULL) return XORP_OK; XrlAction *xa = dynamic_cast(_end_commit); if (xa != NULL) { XrlRouter::XrlCallback cb = callback( this, &ModuleCommand::xrl_action_complete, &ctn, _end_commit, string("end transaction")); return xa->execute(ctn, task_manager, cb); } ProgramAction *pa = dynamic_cast(_end_commit); if (pa != NULL) { TaskProgramItem::ProgramCallback cb = callback( this, &ModuleCommand::program_action_complete, &ctn, _end_commit, string("end transaction")); return pa->execute(ctn, task_manager, cb); } XLOG_UNREACHABLE(); } string ModuleCommand::str() const { string tmp; tmp = "ModuleCommand: provides: " + _module_name + "\n"; tmp += " path: " + _module_exec_path + "\n"; typedef list::const_iterator CI; CI ptr = _depends.begin(); while (ptr != _depends.end()) { tmp += " depends: " + *ptr + "\n"; ++ptr; } return tmp; } void ModuleCommand::xrl_action_complete(const XrlError& err, XrlArgs* xrl_args, MasterConfigTreeNode *ctn, Action* action, string cmd) const { debug_msg("ModuleCommand::xrl_action_complete\n"); UNUSED(cmd); if (err != XrlError::OKAY()) { // // There was an error. There's nothing we can so here - errors // are handled in the TaskManager. // return; } process_xrl_action_return_arguments(xrl_args, ctn, action); } void ModuleCommand::program_action_complete(bool success, const string& stdout_output, const string& stderr_output, bool do_exec, MasterConfigTreeNode *ctn, Action *action, string cmd) const { debug_msg("ModuleCommand::program_action_complete\n"); if (! success) { // // There was an error. There's nothing we can so here - errors // are handled in the TaskManager. // return; } if (do_exec) { // Obtain the names of the variables to set ProgramAction* pa = dynamic_cast(action); XLOG_ASSERT(pa != NULL); string stdout_variable_name = pa->stdout_variable_name(); string stderr_variable_name = pa->stderr_variable_name(); // Set the values if (! stdout_variable_name.empty()) ctn->set_variable(stdout_variable_name, stdout_output); if (! stderr_variable_name.empty()) ctn->set_variable(stderr_variable_name, stderr_output); } UNUSED(cmd); }