Changeset 29 for trunk/confloader.py

Show
Ignore:
Timestamp:
27/11/07 17:40:17 (4 years ago)
Author:
daedalus
Message:

* Manual bailout when in authoritarian mode now works correctly.
* Fixed up some of the log level and stats reporting.
* Added 'backout' mode, that will only run the backout portion of changes. More

useful for testing, but can also be used to undo provisioning by repurposing
the same set of templates used for provisioning.

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/confloader.py

    r28 r29  
    1414 
    1515from device import Device 
    16 from change import CHANGE_STATE 
     16from change import CHANGE_STATE, ChangeConditionFailure 
     17from provisioner import UserBailout 
    1718import util 
    1819 
     
    186187            self.add_namespace(nsnode) 
    187188        except IndexError: 
    188             log.warn("Cannot find global namespace") 
    189189            self.global_namespace = {} 
    190190 
     
    604604                    if prereq not in self.change_success: 
    605605 
     606                        # If we're in backout mode, a prereq in 'backout_ok' state 
     607                        # is treated as complete. 
     608                        if prereq.state in [ CHANGE_STATE['backout_ok'], ]: 
     609                            continue 
     610 
    606611                        # If a prereq has failed, doesn't need to retry, and is 
    607612                        # marked as 'onfail:continue', then we treat it as if 
    608613                        # this prereq has been met. 
    609                         if prereq.state not in [ CHANGE_STATE['pending'], 
     614                        elif prereq.state not in [ CHANGE_STATE['pending'], 
    610615                                                 CHANGE_STATE['retry'], 
    611616                                                 ] and prereq.on_fail_continue: 
     
    631636        Move a change from pending to complete. 
    632637        """ 
    633         log.debug("Change completed.") 
     638        log.info("Change %s completed.", change.name) 
    634639        if change.state == CHANGE_STATE['success']: 
    635640            self.change_success.append(change) 
     
    657662            # Change will be retried 
    658663            pass 
    659          
     664 
    660665        else: 
    661666            log.error("Unknown/unhandled change state '%s'", change.state) 
     
    703708 
    704709        # deal with errors in stats 
    705         #self.alldone.addErrback(self.stats_error) 
     710        #self.alldone.addErrback(self.print_stats) 
    706711                                 
    707712        return self.alldone 
    708713 
    709     def get_next_changes(self, ignored): 
     714    def get_next_changes(self, results): 
    710715        """ 
    711716        Fetch the next set of changes to run. 
     
    716721        have no interdependencies on one another. 
    717722        """ 
     723        log.debug("Results in get_next_changes are: %s", results) 
    718724        log.debug("Fetching outstanding changes...") 
    719725        self.current_changelist = self.cfgldr.get_available_changes() 
     
    747753            log.debug("adding change '%s' to implementation queue", change.name) 
    748754                 
    749             d = change.provisioner.perform_change(None, change, self.cfgldr.global_namespace) 
     755            d = change.provisioner.perform_change(None, change, self.cfgldr.global_namespace, backout=self.cfgldr.options.backout) 
    750756            d.addCallback(self.change_complete, change) 
    751757            d.addErrback(self.change_failure, change) 
     
    753759            pass 
    754760 
    755         dl = defer.DeferredList(dlist) 
     761        dl = defer.DeferredList(dlist, fireOnOneErrback=True, consumeErrors=True) 
    756762        # After the current crop of changes has been completed, find if there are more 
    757763        dl.addCallback( self.get_next_changes ) 
     764        dl.addErrback( self.bailout ) 
    758765        return dl 
    759766 
     767    def bailout(self, failure): 
     768        """ 
     769        Bailout detects the first error from the deferred list, 
     770        and bails out. 
     771        """ 
     772        log.debug("Running bailout...") 
     773        if failure.value.subFailure.type == UserBailout: 
     774            self.alldone.callback('Bailout') 
     775 
     776        else: 
     777            log.debug("Unhandled failure: %s", failure) 
     778            self.alldone.errback(failure) 
     779 
    760780    def change_complete(self, ignored, change): 
    761781        """ 
     
    765785 
    766786    def change_failure(self, failure, change): 
    767         log.error("Major change failure!") 
    768         tlog.err(failure) 
     787        if failure.type == UserBailout: 
     788            log.debug("Controller detected UserBailout.") 
     789            return failure 
     790 
     791        elif failure.type == ChangeConditionFailure: 
     792            pass 
     793 
     794        else: 
     795            log.error("Major change failure!") 
     796            tlog.err(failure) 
     797            pass 
     798         
    769799        self.change_complete(failure, change) 
    770800 
     
    780810 
    781811        log.info("--- Final results ---") 
    782          
    783         if not (success_count > 0 or failure_count > 0): 
    784             log.error("no changes succeeded or failed!") 
    785         else: 
    786             log.info("%d ok, %d failed (%d%% success rate)" % (success_count, failure_count, 100 * success_count / (success_count+failure_count) ) ) 
    787  
    788         if success_count > 0: 
    789             log.info( "Successful changes: %s" % ', '.join([ x.name for x in self.cfgldr.change_success])) 
    790  
    791         if failure_count > 0: 
    792             log.info( "Failed changes: %s" % ', '.join([ x.name for x in self.cfgldr.change_failure]) ) 
     812 
     813        # Don't print some stats when in backout mode 
     814        if not self.cfgldr.options.backout: 
     815         
     816            if not (success_count > 0 or failure_count > 0): 
     817                log.error("no changes succeeded or failed!") 
     818            else: 
     819                log.info("%d ok, %d failed (%d%% success rate)" % (success_count, failure_count, 100 * success_count / (success_count+failure_count) ) ) 
     820 
     821            if success_count > 0: 
     822                log.info( "Successful changes: %s" % ', '.join([ x.name for x in self.cfgldr.change_success])) 
     823 
     824            if failure_count > 0: 
     825                log.info( "Failed changes: %s" % ', '.join([ x.name for x in self.cfgldr.change_failure]) ) 
     826                pass 
     827            pass 
     828 
     829        # These stats are always printed 
    793830 
    794831        if backout_success_count > 0 or backout_failure_count > 0: 
    795             log.error( "%d backed out ok, %d failed (%d%% backout success rate)" % (backout_success_count, backout_failure_count, 100 * backout_success_count / (backout_success_count+backout_failure_count) )) 
     832            log.info( "%d backed out ok, %d failed (%d%% backout success rate)" % (backout_success_count, backout_failure_count, 100 * backout_success_count / (backout_success_count+backout_failure_count) )) 
    796833             
    797834        if backout_success_count > 0: