def test_option_configdir(self): '''Test usage of the configdir option''' mop = McOptionParser() mop.configure_mop() (options, args) = \ mop.parse_args(['-c', '/usr/bin']) self.assertEqual(options.config_dir, '/usr/bin') mop = McOptionParser() mop.configure_mop() self.assertRaises(InvalidOptionError, mop.parse_args, ['-c', '/duke/'])
def test_option_invalid_nodeset(self): '''Test if nodeset/group source is invalid''' mop = McOptionParser() mop.configure_mop() self.assertRaises(InvalidOptionError, mop.parse_args, ['status', '-n', '@bad:group']) mop = McOptionParser() mop.configure_mop() self.assertRaises(InvalidOptionError, mop.parse_args, ['status', '-n', 'bad_node[set'])
def test_option_excluded_nodes(self): '''Test usage of the excluded_nodes option''' mop = McOptionParser() mop.configure_mop() (options, args) = \ mop.parse_args(['service', 'start', '-n', 'foo[8-15]', '-x', 'foo[8-12]']) self.assertTrue('foo[13-15]' in options.only_nodes) self.assertFalse('foo[8-9]' in options.only_nodes) self.assertTrue('foo[8-12]' in options.excluded_nodes) mop.parse_args(['service', 'start', '-x', 'foo[8-12]', '-n', 'foo[8-15]']) self.assertTrue('foo[13-15]' in options.only_nodes) self.assertFalse('foo[8-9]' in options.only_nodes) self.assertTrue('foo[8-12]' in options.excluded_nodes)
def test_option_version(self): '''Test usage of option --version''' mop = McOptionParser() mop.configure_mop() self.assertRaises(SystemExit, mop.parse_args, ['--version'])
def test_debug_config(self): '''Test configuration of the debug mode''' mop = McOptionParser() mop.configure_mop() (options, args) = mop.parse_args(['-d']) self.assertEqual(options.verbosity, 5) self.assertTrue(options.debug) mop = McOptionParser() mop.configure_mop() (options, args) = mop.parse_args(['-d']) self.assertEqual(options.verbosity, 5) self.assertTrue(options.debug) mop = McOptionParser() mop.configure_mop() (options, args) = mop.parse_args(['-vvv']) self.assertEqual(options.verbosity, 4) self.assertFalse(options.debug)
def test_option_onlynodes(self): '''Test usage of the only-nodes option''' mop = McOptionParser() mop.configure_mop() (options, args) = mop.parse_args(['-n', 'foo8']) self.assertTrue('foo8' in options.only_nodes) mop = McOptionParser() mop.configure_mop() (options, args) = \ mop.parse_args(['service', 'start', '-n', 'foo1,foo2']) self.assertTrue(isinstance(options.only_nodes, NodeSet)) self.assertTrue('foo1' in options.only_nodes) self.assertTrue('foo2' in options.only_nodes) self.assertTrue('service' in args and 'start' in args) mop = McOptionParser() mop.configure_mop() self.assertRaises(InvalidOptionError, mop.parse_args, ['service', 'start','-n', '[foo5]'])
def setUp(self): self.mop = McOptionParser() self.mop.configure_mop()
def test_instanciation(self): '''Test creation of an McOptionParser''' self.assertTrue(McOptionParser())
class McOptionParserTest(unittest.TestCase): def setUp(self): self.mop = McOptionParser() self.mop.configure_mop() def test_debug_config(self): """Test configuration of the debug mode""" options, _ = self.mop.parse_args(['-d']) self.assertEqual(options.verbosity, 5) def test_verbose(self): """Test configuration of the verbose mode""" options, _ = self.mop.parse_args(['-vvv']) self.assertEqual(options.verbosity, 4) def test_option_onlynodes_simple(self): """Test simple usage of the only-nodes option""" options, _ = self.mop.parse_args(['-n', 'foo8']) self.assertEqual('foo8', str(options.only_nodes)) def test_option_onlynodes_ns(self): """Test nodeset usage of the only-nodes option""" options, args = self.mop.parse_args(['service', 'start', '-n', 'foo1,foo2']) self.assertTrue(isinstance(options.only_nodes, NodeSet)) self.assertTrue('foo1' in options.only_nodes) self.assertTrue('foo2' in options.only_nodes) self.assertTrue('service' in args and 'start' in args) def test_option_configdir(self): """Test usage of the configdir option""" tmpdir = tempfile.mkdtemp() try: options, _ = self.mop.parse_args(['-c', tmpdir]) finally: os.rmdir(tmpdir) self.assertEqual(options.config_dir, tmpdir) def test_configdir_missing_dir(self): """-c with a non-existent directory raises an error""" self.assertFalse(os.path.exists('/foobar')) self.assertRaises(InvalidOptionError, self.mop.parse_args, ['-c', '/foobar']) def test_option_excluded_nodes(self): """Test usage of the excluded_nodes option""" options, _ = self.mop.parse_args(['service', 'start', '-n', 'foo[8-15]', '-x', 'foo[8-12]']) self.assertTrue('foo[13-15]' in options.only_nodes) self.assertFalse('foo[8-9]' in options.only_nodes) self.assertTrue('foo[8-12]' in options.excluded_nodes) options, _ = self.mop.parse_args(['service', 'start', '-x', 'foo[8-12]', '-n', 'foo[8-15]']) self.assertTrue('foo[13-15]' in options.only_nodes) self.assertFalse('foo[8-9]' in options.only_nodes) self.assertTrue('foo[8-12]' in options.excluded_nodes) def test_option_version(self): """Test usage of option --version""" self.assertRaises(SystemExit, self.mop.parse_args, ['--version']) def test_option_invalid_nodeset(self): """Test if nodeset/group source is invalid""" self.assertRaises(InvalidOptionError, self.mop.parse_args, ['status', '-n', '@bad:group']) def test_option_bad_nodeset_syntax(self): """Test if nodeset syntax is valid""" self.assertRaises(InvalidOptionError, self.mop.parse_args, ['status', '-n', 'bad_node[set']) def test_option_tags(self): """Test --tags option""" options, _ = self.mop.parse_args(['-t', 'tag1']) self.assertEqual(options.tags, set(['tag1'])) options, _ = self.mop.parse_args(['-t', 'tag1,tag2', '-t', 'tag3']) self.assertEqual(options.tags, set(['tag1', 'tag2', 'tag3'])) def test_option_assume_yes(self): """Test --assumeyes option""" options, _ = self.mop.parse_args(['-y']) self.assertEqual(options.assumeyes, True) def test_option_report_full(self): """Check report configuration option""" options, _ = self.mop.parse_args(['--report=full']) self.assertEqual(options.report, 'full') def test_option_report_invalid(self): """invalid report type raises an error""" self.assertRaises(InvalidOptionError, self.mop.parse_args, ['--report=xxxx']) def test_option_summary_translation(self): """Check summary translation""" options, _ = self.mop.parse_args(['-s']) self.assertEqual(options.report, 'default')
class McOptionParserTest(unittest.TestCase): def setUp(self): self.mop = McOptionParser() self.mop.configure_mop() def test_debug_config(self): """Test configuration of the debug mode""" options, _ = self.mop.parse_args(['-d']) self.assertEqual(options.verbosity, 5) def test_verbose(self): """Test configuration of the verbose mode""" options, _ = self.mop.parse_args(['-vvv']) self.assertEqual(options.verbosity, 4) def test_option_onlynodes_simple(self): """Test simple usage of the only-nodes option""" options, _ = self.mop.parse_args(['-n', 'foo8']) self.assertEqual('foo8', str(options.only_nodes)) def test_option_onlynodes_ns(self): """Test nodeset usage of the only-nodes option""" options, args = self.mop.parse_args( ['service', 'start', '-n', 'foo1,foo2']) self.assertTrue(isinstance(options.only_nodes, NodeSet)) self.assertTrue('foo1' in options.only_nodes) self.assertTrue('foo2' in options.only_nodes) self.assertTrue('service' in args and 'start' in args) def test_option_configdir(self): """Test usage of the configdir option""" tmpdir = tempfile.mkdtemp() try: options, _ = self.mop.parse_args(['-c', tmpdir]) finally: os.rmdir(tmpdir) self.assertEqual(options.config_dir, tmpdir) def test_configdir_missing_dir(self): """-c with a non-existent directory raises an error""" self.assertFalse(os.path.exists('/foobar')) self.assertRaises(InvalidOptionError, self.mop.parse_args, ['-c', '/foobar']) def test_option_excluded_nodes(self): """Test usage of the excluded_nodes option""" options, _ = self.mop.parse_args( ['service', 'start', '-n', 'foo[8-15]', '-x', 'foo[8-12]']) self.assertTrue('foo[13-15]' in options.only_nodes) self.assertFalse('foo[8-9]' in options.only_nodes) self.assertTrue('foo[8-12]' in options.excluded_nodes) options, _ = self.mop.parse_args( ['service', 'start', '-x', 'foo[8-12]', '-n', 'foo[8-15]']) self.assertTrue('foo[13-15]' in options.only_nodes) self.assertFalse('foo[8-9]' in options.only_nodes) self.assertTrue('foo[8-12]' in options.excluded_nodes) def test_option_version(self): """Test usage of option --version""" self.assertRaises(SystemExit, self.mop.parse_args, ['--version']) def test_option_invalid_nodeset(self): """Test if nodeset/group source is invalid""" self.assertRaises(InvalidOptionError, self.mop.parse_args, ['status', '-n', '@bad:group']) def test_option_bad_nodeset_syntax(self): """Test if nodeset syntax is valid""" self.assertRaises(InvalidOptionError, self.mop.parse_args, ['status', '-n', 'bad_node[set']) def test_option_tags(self): """Test --tags option""" options, _ = self.mop.parse_args(['-t', 'tag1']) self.assertEqual(options.tags, set(['tag1'])) options, _ = self.mop.parse_args(['-t', 'tag1,tag2', '-t', 'tag3']) self.assertEqual(options.tags, set(['tag1', 'tag2', 'tag3'])) def test_option_assume_yes(self): """Test --assumeyes option""" options, _ = self.mop.parse_args(['-y']) self.assertEqual(options.assumeyes, True) def test_option_report_full(self): """Check report configuration option""" options, _ = self.mop.parse_args(['--report=full']) self.assertEqual(options.report, 'full') def test_option_report_invalid(self): """invalid report type raises an error""" self.assertRaises(InvalidOptionError, self.mop.parse_args, ['--report=xxxx']) def test_option_summary_translation(self): """Check summary translation""" options, _ = self.mop.parse_args(['-s']) self.assertEqual(options.report, 'default')
def execute(self, command_line): ''' Ask for the manager to execute orders given by the command line. ''' self._mop = McOptionParser() self._mop.configure_mop() retcode = RC_OK try: (self._options, self._args) = self._mop.parse_args(command_line) self._conf = ConfigParser(self._options) # Configure ActionManager action_manager_self().default_fanout = self._conf['fanout'] action_manager_self().dryrun = self._conf['dryrun'] manager = service_manager_self() # Case 0: build the graph if self._conf.get('graph', False): manager.load_config(self._conf['config_dir']) # Deps graph generation self._console.output(manager.output_graph(self._args, self._conf.get('excluded_svc', []))) # Case 1 : call services referenced in the manager with # the required action elif self._args: # Compute all services with the required action services = self._args[:-1] action = self._args[-1] # Create a thread in interactive mode to manage # current running status if self.interactive: self.inter_thread.start() # Run tasks manager.call_services(services, action, conf=self._conf) retcode = self.retcode() if self._conf.get('summary', False): self._console.print_summary(self.actions) # Case 2 : Check configuration elif self._conf.get('config_dir', False): self._console.output("No actions specified, " "checking configuration...") manager.load_config(self._conf['config_dir']) self._console.output("%s seems good" % self._conf['config_dir']) # Case 3: Nothing to do so just print MilkCheck help else: self._mop.print_help() except (ServiceNotFoundError, ActionNotFoundError, InvalidVariableError, UndefinedVariableError, VariableAlreadyExistError, DependencyAlreadyReferenced, UnknownDependencyError, IllegalDependencyTypeError, ConfigParserError, ConfigurationError, ScannerError), exc: self._logger.error(str(exc)) retcode = RC_EXCEPTION
class CommandLine(CoreEvent): ''' This class models the Command Line which is a CoreEvent. From this class you can get back events generated by the engine and send order to the ServiceManager. ''' def __init__(self): CoreEvent.__init__(self) # Parser which reads the command line self._mop = None # Store the options parsed self._options = None # Store the configuration parsed self._conf = None # Store the arguments parsed self._args = None # Store executed actions self.actions = [] # Displayer self._console = ConsoleDisplay() # Store interactive mode self.interactive = Terminal.isinteractive() self._logger = ConfigParser.install_logger() call_back_self().attach(self) self.inter_thread = InteractiveThread(self._console) def execute(self, command_line): ''' Ask for the manager to execute orders given by the command line. ''' self._mop = McOptionParser() self._mop.configure_mop() retcode = RC_OK try: (self._options, self._args) = self._mop.parse_args(command_line) self._conf = ConfigParser(self._options) # Configure ActionManager action_manager_self().default_fanout = self._conf['fanout'] action_manager_self().dryrun = self._conf['dryrun'] manager = service_manager_self() # Case 0: build the graph if self._conf.get('graph', False): manager.load_config(self._conf['config_dir']) # Deps graph generation self._console.output(manager.output_graph(self._args, self._conf.get('excluded_svc', []))) # Case 1 : call services referenced in the manager with # the required action elif self._args: # Compute all services with the required action services = self._args[:-1] action = self._args[-1] # Create a thread in interactive mode to manage # current running status if self.interactive: self.inter_thread.start() # Run tasks manager.call_services(services, action, conf=self._conf) retcode = self.retcode() if self._conf.get('summary', False): self._console.print_summary(self.actions) # Case 2 : Check configuration elif self._conf.get('config_dir', False): self._console.output("No actions specified, " "checking configuration...") manager.load_config(self._conf['config_dir']) self._console.output("%s seems good" % self._conf['config_dir']) # Case 3: Nothing to do so just print MilkCheck help else: self._mop.print_help() except (ServiceNotFoundError, ActionNotFoundError, InvalidVariableError, UndefinedVariableError, VariableAlreadyExistError, DependencyAlreadyReferenced, UnknownDependencyError, IllegalDependencyTypeError, ConfigParserError, ConfigurationError, ScannerError), exc: self._logger.error(str(exc)) retcode = RC_EXCEPTION except InvalidOptionError, exc: self._logger.critical('Invalid options: %s\n' % exc) self._mop.print_help() retcode = RC_EXCEPTION
def execute(self, command_line): ''' Ask for the manager to execute orders given by the command line. ''' self._mop = McOptionParser() self._mop.configure_mop() retcode = RC_OK try: (self._options, self._args) = self._mop.parse_args(command_line) self._conf = ConfigParser(self._options) # Configure ActionManager action_manager_self().default_fanout = self._conf['fanout'] action_manager_self().dryrun = self._conf['dryrun'] self.manager = self.manager or ServiceManager() # Case 0: build the graph if self._conf.get('graph', False): self.manager.load_config(self._conf['config_dir']) # Deps graph generation self._console.output( self.manager.output_graph( self._args, self._conf.get('excluded_svc', []))) # Case 1 : call services referenced in the manager with # the required action elif self._args: # Compute all services with the required action services = self._args[:-1] action = self._args[-1] # Ask for confirmation if the configuration requests it. if action in self._conf['confirm_actions'] and \ not self._conf['assumeyes'] and \ not Terminal.confirm("Are you sure to run %s action?" % action): raise UserError('Execution aborted by user') # Create a thread in interactive mode to manage # current running status if self.interactive: self.inter_thread.start() # Run tasks self.manager.call_services(services, action, conf=self._conf) retcode = self.retcode() if self._conf.get('report', 'no').lower() != 'no': r_type = self._conf.get('report', 'default') self._console.print_summary(self.actions, report=r_type) # Case 2 : Check configuration elif self._conf.get('config_dir', False): self._console.output("No actions specified, " "checking configuration...") self.manager.load_config(self._conf['config_dir']) self._console.output("%s seems good" % self._conf['config_dir']) # Case 3: Nothing to do so just print MilkCheck help else: self._mop.print_help() except (ServiceNotFoundError, ActionNotFoundError, InvalidVariableError, UndefinedVariableError, VariableAlreadyExistError, DependencyAlreadyReferenced, UnknownDependencyError, IllegalDependencyTypeError, ConfigError, ScannerError, UserError) as exc: self._logger.error(str(exc)) retcode = RC_EXCEPTION except InvalidOptionError as exc: self._logger.critical('Invalid options: %s\n' % exc) self._mop.print_help() retcode = RC_EXCEPTION except KeyboardInterrupt as exc: self._logger.error('Keyboard Interrupt') retcode = (128 + SIGINT) except ScannerError as exc: self._logger.error('Bad syntax in config file :\n%s' % exc) retcode = RC_EXCEPTION except ImportError as exc: self._logger.error('Missing python dependency: %s' % exc) for line in traceback.format_exc().splitlines()[-3:-1]: self._logger.error(line) retcode = RC_EXCEPTION except Exception as exc: # In high verbosity mode, propagate the error if (not self._conf or self._conf.get('verbosity') >= 5): traceback.print_exc(file=sys.stdout) else: self._logger.error('Unexpected Exception : %s' % exc) retcode = RC_UNKNOWN_EXCEPTION # Quit the interactive thread self.inter_thread.quit() self.inter_thread.join() return retcode
class CommandLine(CoreEvent): ''' This class models the Command Line which is a CoreEvent. From this class you can get back events generated by the engine and send order to the ServiceManager. ''' def __init__(self): CoreEvent.__init__(self) # Parser which reads the command line self._mop = None # Store the options parsed self._options = None # Store the configuration parsed self._conf = None # Store the arguments parsed self._args = None # Store executed actions self.actions = [] # Displayer self._console = ConsoleDisplay() # Store interactive mode self.interactive = Terminal.isinteractive() # Useful for tests self.manager = None self._logger = ConfigParser.install_logger() call_back_self().attach(self) self.inter_thread = InteractiveThread(self._console) def execute(self, command_line): ''' Ask for the manager to execute orders given by the command line. ''' self._mop = McOptionParser() self._mop.configure_mop() retcode = RC_OK try: (self._options, self._args) = self._mop.parse_args(command_line) self._conf = ConfigParser(self._options) # Configure ActionManager action_manager_self().default_fanout = self._conf['fanout'] action_manager_self().dryrun = self._conf['dryrun'] self.manager = self.manager or ServiceManager() # Case 0: build the graph if self._conf.get('graph', False): self.manager.load_config(self._conf['config_dir']) # Deps graph generation self._console.output( self.manager.output_graph( self._args, self._conf.get('excluded_svc', []))) # Case 1 : call services referenced in the manager with # the required action elif self._args: # Compute all services with the required action services = self._args[:-1] action = self._args[-1] # Ask for confirmation if the configuration requests it. if action in self._conf['confirm_actions'] and \ not self._conf['assumeyes'] and \ not Terminal.confirm("Are you sure to run %s action?" % action): raise UserError('Execution aborted by user') # Create a thread in interactive mode to manage # current running status if self.interactive: self.inter_thread.start() # Run tasks self.manager.call_services(services, action, conf=self._conf) retcode = self.retcode() if self._conf.get('report', 'no').lower() != 'no': r_type = self._conf.get('report', 'default') self._console.print_summary(self.actions, report=r_type) # Case 2 : Check configuration elif self._conf.get('config_dir', False): self._console.output("No actions specified, " "checking configuration...") self.manager.load_config(self._conf['config_dir']) self._console.output("%s seems good" % self._conf['config_dir']) # Case 3: Nothing to do so just print MilkCheck help else: self._mop.print_help() except (ServiceNotFoundError, ActionNotFoundError, InvalidVariableError, UndefinedVariableError, VariableAlreadyExistError, DependencyAlreadyReferenced, UnknownDependencyError, IllegalDependencyTypeError, ConfigError, ScannerError, UserError) as exc: self._logger.error(str(exc)) retcode = RC_EXCEPTION except InvalidOptionError as exc: self._logger.critical('Invalid options: %s\n' % exc) self._mop.print_help() retcode = RC_EXCEPTION except KeyboardInterrupt as exc: self._logger.error('Keyboard Interrupt') retcode = (128 + SIGINT) except ScannerError as exc: self._logger.error('Bad syntax in config file :\n%s' % exc) retcode = RC_EXCEPTION except ImportError as exc: self._logger.error('Missing python dependency: %s' % exc) for line in traceback.format_exc().splitlines()[-3:-1]: self._logger.error(line) retcode = RC_EXCEPTION except Exception as exc: # In high verbosity mode, propagate the error if (not self._conf or self._conf.get('verbosity') >= 5): traceback.print_exc(file=sys.stdout) else: self._logger.error('Unexpected Exception : %s' % exc) retcode = RC_UNKNOWN_EXCEPTION # Quit the interactive thread self.inter_thread.quit() self.inter_thread.join() return retcode def retcode(self): ''' Determine a retcode from a the last point of the graph RC_OK = 0: Everything went as we expected RC_WARNING = 3: At least one service status is WARNING and all others status is OK RC_ERROR = 6: At least one service status is ERROR Handled by self.execute : RC_EXCEPTION = 9: User error (options or configuration) RC_UNKNOWN_EXCEPTION = 12: Internal error (this is probably a bug) ''' if self.manager.status in (DEP_ERROR, ERROR): return RC_ERROR elif self.manager.has_warnings(): return RC_WARNING else: return RC_OK def ev_started(self, obj): ''' Something has started on the object given as parameter. This migh be the beginning of a command one a node, an action or a service. ''' if isinstance(obj, Action) and self._conf['verbosity'] >= 2: self._console.print_action_command(obj) self._console.print_running_tasks() elif isinstance(obj, Service) and self._conf['verbosity'] >= 1: self._console.print_running_tasks() def ev_complete(self, obj): ''' Something is complete on the object given as parameter. This migh be the end of a command on a node, an action or a service. ''' if isinstance(obj, Action): self.actions.append(obj) if self._conf['verbosity'] >= 3 and obj.status != SKIPPED: self._console.print_action_results(obj) self._console.print_running_tasks() elif obj.status in (TIMEOUT, ERROR, DEP_ERROR) and \ self._conf['verbosity'] >= 1: self._console.print_action_results( obj, self._conf['verbosity'] == 1) self._console.print_running_tasks() elif isinstance(obj, Service) and self._conf['verbosity'] >= 1: self._console.print_running_tasks() def ev_status_changed(self, obj): ''' Status of the object given as parameter. Actions or Service's status might have changed. ''' if isinstance(obj, Service) and not (obj.status == SKIPPED and \ self._conf['verbosity'] < 3) and \ obj.status in (TIMEOUT, ERROR, DEP_ERROR, DONE, WARNING, SKIPPED) and not obj.simulate: self._console.print_status(obj) self._console.print_running_tasks() def ev_delayed(self, obj): ''' Object given as parameter has been delayed. This event is only raised when an action was delayed ''' if isinstance(obj, Action) and self._conf['verbosity'] >= 3: self._console.print_delayed_action(obj) self._console.print_running_tasks() def ev_trigger_dep(self, obj_source, obj_triggered): ''' obj_source/obj_triggered might be an action or a service. This event is raised when the obj_source triggered another object. Sample : Action A triggers Action B Service A triggers Service B ''' pass def ev_finished(self, obj): ''' Finalize milcheck call ''' pass