#NEWLINE# @ argh_named ( 'control' ) #NEWLINE# @ arg_verbose #NEWLINE# @ arg_full_match #NEWLINE# @ arg_flag ( '-n' , '--no-deps' , help = 'do not run dependency tasks' ) #NEWLINE# @ arg_flag ( '-i' , '--ignore-missing' , help = 'do not fail in case no matching operations are found' ) #NEWLINE# @ arg_quiet #NEWLINE# @ arg_output_dir #NEWLINE# @ arg_flag ( '-t' , '--clock-tasks' , dest = 'show_times' , help = 'show timeline of execution for each tasks' ) #NEWLINE# @ argh . arg ( '-j' , '--jobs' , metavar = 'N' , type = int , help = 'max concurrent tasks (default: unlimited)' ) #NEWLINE# @ argh . arg ( 'pattern' , type = str , help = 'config search pattern' ) #NEWLINE# @ arg_host_access_method #NEWLINE# @ argh . arg ( 'operation' , type = str , help = 'operation to execute' ) #NEWLINE# @ expects_obj #NEWLINE# def handle_control( self , arg ) : #NEWLINE# #INDENT# 'config control operation' #NEWLINE# confman = self . get_confman ( arg . root_dir , reset_cache = False ) #NEWLINE# manager = self . get_manager ( confman ) #NEWLINE# self . collect_all ( manager ) #NEWLINE# all_configs = list ( confman . find_config ( '.' , all_configs = True ) ) #NEWLINE# all_ops = [ ] #NEWLINE# provider = { #NEWLINE# #INDENT# #NEWLINE# #UNINDENT# } #NEWLINE# for ( conf_node , conf ) in all_configs : #NEWLINE# #INDENT# plugin = conf . get_plugin ( ) #NEWLINE# if ( not plugin ) : #NEWLINE# #INDENT# self . log . debug ( 'skipping pluginless: %s:%s' , conf_node . name , conf . name ) #NEWLINE# continue #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if conf_node . get_tree_property ( 'template' , False ) : #NEWLINE# #INDENT# self . log . debug ( 'skipping template node: %s:%s' , conf_node . name , conf . name ) #NEWLINE# continue #NEWLINE# #UNINDENT# #UNINDENT# for op in plugin . iter_control_operations ( conf_node , conf ) : #NEWLINE# #INDENT# all_ops . append ( op ) #NEWLINE# for feature in op [ 'provides' ] : #NEWLINE# #INDENT# ops = provider . setdefault ( feature , [ ] ) #NEWLINE# ops . append ( op ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# handled = set ( ) #NEWLINE# def add_all_required_ops( op ) : #NEWLINE# #INDENT# key = ( op [ 'node' ] . name , op [ 'config' ] . name , op [ 'name' ] ) #NEWLINE# if ( key in handled ) : #NEWLINE# #INDENT# return #NEWLINE# #UNINDENT# handled . add ( key ) #NEWLINE# node = op [ 'node' ] #NEWLINE# conf = op [ 'config' ] #NEWLINE# tasks [ ( node . name , conf . name , op [ 'name' ] ) ] = op #NEWLINE# reqs = [ ( True , req ) for req in op [ 'requires' ] ] #NEWLINE# reqs . extend ( ( ( False , req ) for req in op [ 'optional_requires' ] ) ) #NEWLINE# for ( must_have , feature ) in reqs : #NEWLINE# #INDENT# try : #NEWLINE# #INDENT# provider_ops = provider [ feature ] #NEWLINE# #UNINDENT# except KeyError : #NEWLINE# #INDENT# if ( not must_have ) : #NEWLINE# #INDENT# continue #NEWLINE# #UNINDENT# raise errors . OperationError ( ( '%s/%s operation %r depends on feature %r, which is not provided by any config' % ( node . name , conf . name , arg . operation , feature ) ) ) #NEWLINE# #UNINDENT# depends = op . setdefault ( 'depends' , [ ] ) #NEWLINE# for dep_op in provider_ops : #NEWLINE# #INDENT# depends . append ( dep_op ) #NEWLINE# add_all_required_ops ( dep_op ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# tasks = { #NEWLINE# #INDENT# #NEWLINE# #UNINDENT# } #NEWLINE# comparison = core . ConfigMatch ( arg . pattern , full_match = arg . full_match ) #NEWLINE# for op in all_ops : #NEWLINE# #INDENT# node = op [ 'node' ] #NEWLINE# conf = op [ 'config' ] #NEWLINE# if ( ( arg . operation != op [ 'name' ] ) or ( not comparison . match_node ( node . name ) ) or ( not comparison . match_config ( conf . name ) ) ) : #NEWLINE# #INDENT# continue #NEWLINE# #UNINDENT# op [ 'run' ] = True #NEWLINE# add_all_required_ops ( op ) #NEWLINE# #UNINDENT# if ( not tasks ) : #NEWLINE# #INDENT# if arg . ignore_missing : #NEWLINE# #INDENT# self . log . info ( 'no matching operations found: --ignore-missing specified, ok!' ) #NEWLINE# return #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# raise errors . UserError ( 'no matching operations found' ) #NEWLINE# #UNINDENT# #UNINDENT# if arg . no_deps : #NEWLINE# #INDENT# for op in all_ops : #NEWLINE# #INDENT# depends = op . get ( 'depends' , [ ] ) #NEWLINE# for dep_op in depends [ : ] : #NEWLINE# #INDENT# if ( not dep_op . get ( 'run' ) ) : #NEWLINE# #INDENT# depends . remove ( dep_op ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# runner = work . Runner ( max_jobs = arg . jobs ) #NEWLINE# logger = ( self . log . info if arg . verbose else self . log . debug ) #NEWLINE# for ( op_id , op ) in tasks . items ( ) : #NEWLINE# #INDENT# run = ( op . get ( 'run' ) or ( not arg . no_deps ) ) #NEWLINE# op [ 'run' ] = run #NEWLINE# if ( not run ) : #NEWLINE# #INDENT# continue #NEWLINE# #UNINDENT# plugin = op [ 'plugin' ] #NEWLINE# logger ( 'scheduled to run: %s/%s [%s]' , op [ 'node' ] . name , op [ 'config' ] . name , op [ 'name' ] ) #NEWLINE# task = ControlTask ( op , arg . extras , verbose = arg . verbose , quiet = arg . quiet , output_dir = arg . output_dir , method = arg . method , color = arg . color ) #NEWLINE# runner . add_task ( task ) #NEWLINE# #UNINDENT# runner . run_all ( ) #NEWLINE# results = [ task . op . get ( 'result' ) for task in runner . stopped ] #NEWLINE# failed = [ r for r in results if r ] #NEWLINE# skipped_count = sum ( ( 1 for op in tasks . values ( ) if ( not op [ 'run' ] ) ) ) #NEWLINE# ran_count = ( len ( tasks ) - skipped_count ) #NEWLINE# assert ( len ( results ) == ran_count ) #NEWLINE# for ( i , task ) in enumerate ( runner . stopped ) : #NEWLINE# #INDENT# task_name = ( '%s/%s' % ( task . op [ 'node' ] . name , task . op [ 'config' ] . name ) ) #NEWLINE# self . task_times . add_task ( i , task_name , task . op [ 'start_time' ] , task . op [ 'stop_time' ] ) #NEWLINE# #UNINDENT# if arg . verbose : #NEWLINE# #INDENT# for task in runner . stopped : #NEWLINE# #INDENT# res = task . op [ 'result' ] #NEWLINE# if res : #NEWLINE# #INDENT# self . log . error ( 'FAILED: %s/%s [%s]: %r' , task . op [ 'node' ] . name , task . op [ 'config' ] . name , task . op [ 'name' ] , task . op [ 'result' ] ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# self . log . debug ( 'all tasks finished: %r' , results ) #NEWLINE# if failed : #NEWLINE# #INDENT# raise errors . ControlError ( ( '[%d/%d] control tasks failed (%d skipped)' % ( len ( failed ) , ran_count , skipped_count ) ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# self . log . info ( 'all [%d] control tasks finished successfully (%d skipped)' , ran_count , skipped_count )