def _get_result(self, autoskip_selector="", interactive=False, interactive_default=True): if self.covered_by_autoskip_selector(autoskip_selector): io.debug(_( "autoskip matches {item} on {node}" ).format(item=self.id, node=self.node.name)) return (self.STATUS_SKIPPED, [_("cmdline")]) if interactive is False and self.attributes['interactive'] is True: return (self.STATUS_SKIPPED, [_("interactive only")]) if self.triggered and not self.has_been_triggered: io.debug(_("skipping {} because it wasn't triggered").format(self.id)) return (self.STATUS_SKIPPED, [_("no trigger")]) if self.unless: with io.job(_(" {node} {bundle} {item} checking 'unless' condition...").format( bundle=self.bundle.name, item=self.id, node=self.node.name, )): unless_result = self.bundle.node.run( self.unless, may_fail=True, ) if unless_result.return_code == 0: io.debug(_("{node}:{bundle}:action:{name}: failed 'unless', not running").format( bundle=self.bundle.name, name=self.name, node=self.bundle.node.name, )) return (self.STATUS_SKIPPED, ["unless"]) if ( interactive and self.attributes['interactive'] is not False and not io.ask( wrap_question( self.id, self.attributes['command'], _("Run action {}?").format( bold(self.name), ), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ), interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), ) ): return (self.STATUS_SKIPPED, [_("interactive")]) try: self.run() return (self.STATUS_ACTION_SUCCEEDED, None) except ActionFailure: return (self.STATUS_FAILED, None)
def update_all(self, interactive=False): """Update all versions, prompting the user for each possible update""" io.activate() for name, table in self.toml.items(): latest = self._latest_version(name) current = self._cached_version(name) now = datetime.datetime.now() if latest == current: io.stdout("{x} {name} is up to date ({current})".format( x=green("✓"), name=name, current=current, )) continue if interactive: question = wrap_question( name, "{} → {}".format(red(current), green(latest)), "Update {}".format(bold(name)), prefix="{} versions".format(blue("?"))) if not io.ask(question, True): continue else: io.stdout("{x} updated {name}: {current} → {new}".format( x=green("✓"), name=bold(name), current=red(current), new=green(latest), )) table['version'] = latest table['version_date'] = now self.toml[name] = table self._save()
def apply_start(repo, target, nodes, interactive=False, **kwargs): ''' Interactively update all versions if running in interactive mode. ''' _ = target _ = nodes _ = kwargs if interactive: question = wrap_question( bold("Version management"), "Do you want to check configured software versions for updates", "Check for updates ?", prefix="{} versions".format(blue("?")), ) if not io.ask(question, True): return repo.libs.versions.VersionManager().update_all(interactive=True)
def _get_result(self, interactive=False, interactive_default=True): if interactive is False and self.attributes['interactive'] is True: return (self.STATUS_SKIPPED, None) if self.triggered and not self.has_been_triggered: io.debug(_("skipping {} because it wasn't triggered").format(self.id)) return (self.STATUS_SKIPPED, None) if self.unless: unless_result = self.bundle.node.run( self.unless, may_fail=True, ) if unless_result.return_code == 0: io.debug(_("{node}:{bundle}:action:{name}: failed 'unless', not running").format( bundle=self.bundle.name, name=self.name, node=self.bundle.node.name, )) return (self.STATUS_SKIPPED, None) if ( interactive and self.attributes['interactive'] is not False and not io.ask( wrap_question( self.id, self.attributes['command'], _("Run action {}?").format( bold(self.name), ), ), interactive_default, ) ): return (self.STATUS_SKIPPED, None) try: self.run(interactive=interactive) return (self.STATUS_ACTION_SUCCEEDED, None) except ActionFailure: return (self.STATUS_FAILED, None)
def apply( self, autoskip_selector="", autoonly_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): self.node.repo.hooks.item_apply_start( self.node.repo, self.node, self, ) status_code = None status_before = None status_after = None start_time = datetime.now() if not self.covered_by_autoonly_selector(autoonly_selector): io.debug( _("autoonly does not match {item} on {node}").format( item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_CMDLINE if self.covered_by_autoskip_selector(autoskip_selector): io.debug( _("autoskip matches {item} on {node}").format( item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_CMDLINE if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_SOFTLOCK for item in self._precedes_items: if item._triggers_preceding_items(interactive=interactive): io.debug( _("preceding item {item} on {node} has been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) self.has_been_triggered = True break else: io.debug( _("preceding item {item} on {node} has NOT been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) if self.triggered and not self.has_been_triggered and status_code is None: io.debug( _("skipping {item} on {node} because it wasn't triggered"). format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_NO_TRIGGER if status_code is None and self.cached_unless_result and status_code is None: io.debug( _("'unless' for {item} on {node} succeeded, not fixing"). format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_UNLESS if self._faults_missing_for_attributes and status_code is None: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _("skipping {item} on {node} because it is missing faults " "for these attributes: {attrs} " "(most of the time this means you're missing " "a required key in your .secrets.cfg)").format( attrs=", ".join( sorted(self._faults_missing_for_attributes)), item=self.id, node=self.node.name, )) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_FAULT_UNAVAILABLE if status_code is None: try: status_before = self.cached_status except FaultUnavailable: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _("skipping {item} on {node} because it is missing Faults " "(most of the time this means you're missing " "a required key in your .secrets.cfg)").format( item=self.id, node=self.node.name, )) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_FAULT_UNAVAILABLE else: if status_before.correct: status_code = self.STATUS_OK if status_code is None: if not interactive: with io.job( _("{node} {bundle} {item}").format( bundle=bold(self.bundle.name), item=self.id, node=bold(self.node.name), )): self.fix(status_before) else: if status_before.must_be_created: question_text = _("Doesn't exist. Will be created.") elif status_before.must_be_deleted: question_text = _("Found on node. Will be removed.") else: question_text = self.ask( status_before.display_cdict, status_before.display_sdict, status_before.display_keys_to_fix, ) if self.comment: question_text += format_comment(self.comment) question = wrap_question( self.id, question_text, _("Fix {}?").format(bold(self.id)), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ) answer = io.ask( question, interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), ) if answer: with io.job( _("{node} {bundle} {item}").format( bundle=bold(self.bundle.name), item=self.id, node=bold(self.node.name), )): self.fix(status_before) else: status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_INTERACTIVE if status_code is None: status_after = self.get_status(cached=False) status_code = self.STATUS_FIXED if status_after.correct else self.STATUS_FAILED if status_code == self.STATUS_OK: details = None elif status_code == self.STATUS_SKIPPED: details = skip_reason elif status_before.must_be_created: details = True elif status_before.must_be_deleted: details = False elif status_code == self.STATUS_FAILED: details = status_after.display_keys_to_fix else: details = status_before.display_keys_to_fix self.node.repo.hooks.item_apply_end( self.node.repo, self.node, self, duration=datetime.now() - start_time, status_code=status_code, status_before=status_before, status_after=status_after, ) return (status_code, details)
def apply( self, autoskip_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): self.node.repo.hooks.item_apply_start( self.node.repo, self.node, self, ) status_code = None status_before = None status_after = None start_time = datetime.now() if self.covered_by_autoskip_selector(autoskip_selector): io.debug(_( "autoskip matches {item} on {node}" ).format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_CMDLINE if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_SOFTLOCK for item in self._precedes_items: if item._triggers_preceding_items(interactive=interactive): io.debug(_( "preceding item {item} on {node} has been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) self.has_been_triggered = True break else: io.debug(_( "preceding item {item} on {node} has NOT been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) if self.triggered and not self.has_been_triggered and status_code is None: io.debug(_( "skipping {item} on {node} because it wasn't triggered" ).format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_NO_TRIGGER if status_code is None and self.cached_unless_result and status_code is None: io.debug(_( "'unless' for {item} on {node} succeeded, not fixing" ).format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_UNLESS if self._faults_missing_for_attributes and status_code is None: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug(_( "skipping {item} on {node} because it is missing faults " "for these attributes: {attrs} " "(most of the time this means you're missing " "a required key in your .secrets.cfg)" ).format( attrs=", ".join(sorted(self._faults_missing_for_attributes)), item=self.id, node=self.node.name, )) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_FAULT_UNAVAILABLE if status_code is None: try: status_before = self.cached_status except FaultUnavailable: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug(_( "skipping {item} on {node} because it is missing Faults " "(most of the time this means you're missing " "a required key in your .secrets.cfg)" ).format( item=self.id, node=self.node.name, )) status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_FAULT_UNAVAILABLE else: if status_before.correct: status_code = self.STATUS_OK if status_code is None: if not interactive: with io.job(_("{node} {bundle} {item}").format( bundle=bold(self.bundle.name), item=self.id, node=bold(self.node.name), )): self.fix(status_before) else: if status_before.must_be_created: question_text = _("Doesn't exist. Will be created.") elif status_before.must_be_deleted: question_text = _("Found on node. Will be removed.") else: question_text = self.ask( status_before.display_cdict, status_before.display_sdict, status_before.display_keys_to_fix, ) if self.comment: question_text += format_comment(self.comment) question = wrap_question( self.id, question_text, _("Fix {}?").format(bold(self.id)), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ) answer = io.ask( question, interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), ) if answer: with io.job(_("{node} {bundle} {item}").format( bundle=bold(self.bundle.name), item=self.id, node=bold(self.node.name), )): self.fix(status_before) else: status_code = self.STATUS_SKIPPED skip_reason = self.SKIP_REASON_INTERACTIVE if status_code is None: status_after = self.get_status(cached=False) status_code = self.STATUS_FIXED if status_after.correct else self.STATUS_FAILED if status_code == self.STATUS_OK: details = None elif status_code == self.STATUS_SKIPPED: details = skip_reason elif status_before.must_be_created: details = True elif status_before.must_be_deleted: details = False elif status_code == self.STATUS_FAILED: details = status_after.display_keys_to_fix else: details = status_before.display_keys_to_fix self.node.repo.hooks.item_apply_end( self.node.repo, self.node, self, duration=datetime.now() - start_time, status_code=status_code, status_before=status_before, status_after=status_after, ) return (status_code, details)
def _get_result( self, autoskip_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): if self.covered_by_autoskip_selector(autoskip_selector): io.debug( _("autoskip matches {item} on {node}").format( item=self.id, node=self.node.name)) return (self.STATUS_SKIPPED, [_("cmdline")]) if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): return (self.STATUS_SKIPPED, [_("soft locked")]) if interactive is False and self.attributes['interactive'] is True: return (self.STATUS_SKIPPED, [_("interactive only")]) if self.triggered and not self.has_been_triggered: io.debug( _("skipping {} because it wasn't triggered").format(self.id)) return (self.STATUS_SKIPPED, [_("no trigger")]) if self.unless: with io.job( _(" {node} {bundle} {item} checking 'unless' condition..." ).format( bundle=self.bundle.name, item=self.id, node=self.node.name, )): unless_result = self.bundle.node.run( self.unless, may_fail=True, ) if unless_result.return_code == 0: io.debug( _("{node}:{bundle}:action:{name}: failed 'unless', not running" ).format( bundle=self.bundle.name, name=self.name, node=self.bundle.node.name, )) return (self.STATUS_SKIPPED, ["unless"]) question_body = "" if self.attributes['data_stdin'] is not None: question_body += "<" + _("data") + "> | " question_body += self.attributes['command'] if self.comment: question_body += format_comment(self.comment) if (interactive and self.attributes['interactive'] is not False and not io.ask( wrap_question( self.id, question_body, _("Run action {}?").format(bold(self.name), ), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ), interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), )): return (self.STATUS_SKIPPED, [_("interactive")]) try: self.run() return (self.STATUS_ACTION_SUCCEEDED, None) except ActionFailure as exc: return (self.STATUS_FAILED, [str(exc)])
def _get_result( self, autoskip_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): if self._faults_missing_for_attributes: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _("skipping {item} on {node} because it is missing faults " "for these attributes: {attrs} " "(most of the time this means you're missing " "a required key in your .secrets.cfg)").format( attrs=", ".join( sorted(self._faults_missing_for_attributes)), item=self.id, node=self.node.name, )) return (self.STATUS_SKIPPED, self.SKIP_REASON_FAULT_UNAVAILABLE) if self.covered_by_autoskip_selector(autoskip_selector): io.debug( _("autoskip matches {item} on {node}").format( item=self.id, node=self.node.name)) return (self.STATUS_SKIPPED, self.SKIP_REASON_CMDLINE) if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): return (self.STATUS_SKIPPED, self.SKIP_REASON_SOFTLOCK) if interactive is False and self.attributes['interactive'] is True: return (self.STATUS_SKIPPED, self.SKIP_REASON_INTERACTIVE_ONLY) for item in self._precedes_items: if item._triggers_preceding_items(interactive=interactive): io.debug( _("preceding item {item} on {node} has been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) self.has_been_triggered = True break else: io.debug( _("preceding item {item} on {node} has NOT been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) if self.triggered and not self.has_been_triggered: io.debug( _("skipping {} because it wasn't triggered").format(self.id)) return (self.STATUS_SKIPPED, self.SKIP_REASON_NO_TRIGGER) if self.unless: with io.job( _("{node} {bundle} {item} checking 'unless' condition"). format( bundle=bold(self.bundle.name), item=self.id, node=bold(self.node.name), )): unless_result = self.bundle.node.run( self.unless, may_fail=True, ) if unless_result.return_code == 0: io.debug( _("{node}:{bundle}:action:{name}: failed 'unless', not running" ).format( bundle=self.bundle.name, name=self.name, node=self.bundle.node.name, )) return (self.STATUS_SKIPPED, self.SKIP_REASON_UNLESS) question_body = "" if self.attributes['data_stdin'] is not None: question_body += "<" + _("data") + "> | " question_body += self.attributes['command'] if self.comment: question_body += format_comment(self.comment) if (interactive and self.attributes['interactive'] is not False and not io.ask( wrap_question( self.id, question_body, _("Run action {}?").format(bold(self.name), ), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ), interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), )): return (self.STATUS_SKIPPED, self.SKIP_REASON_INTERACTIVE) try: self.run() return (self.STATUS_ACTION_SUCCEEDED, None) except ActionFailure as exc: return (self.STATUS_FAILED, [str(exc)])
def apply( self, autoskip_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): self.node.repo.hooks.item_apply_start( self.node.repo, self.node, self, ) keys_to_fix = None status_code = None status_before = None status_after = None start_time = datetime.now() if self.covered_by_autoskip_selector(autoskip_selector): io.debug( _("autoskip matches {item} on {node}").format( item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED keys_to_fix = [_("cmdline")] if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): status_code = self.STATUS_SKIPPED keys_to_fix = [_("soft locked")] if self.triggered and not self.has_been_triggered and status_code is None: io.debug( _("skipping {item} on {node} because it wasn't triggered"). format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED keys_to_fix = [_("not triggered")] if status_code is None and self.cached_unless_result and status_code is None: io.debug( _("'unless' for {item} on {node} succeeded, not fixing"). format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED keys_to_fix = ["unless"] if self._faults_missing_for_attributes and status_code is None: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _("skipping {item} on {node} because it is missing faults " "for these attributes: {attrs} " "(most of the time this means you're missing " "a required key in your .secrets.cfg)").format( attrs=", ".join( sorted(self._faults_missing_for_attributes)), item=self.id, node=self.node.name, )) status_code = self.STATUS_SKIPPED keys_to_fix = [_("Fault unavailable")] if status_code is None: try: status_before = self.cached_status except FaultUnavailable: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _("skipping {item} on {node} because it is missing Faults " "(most of the time this means you're missing " "a required key in your .secrets.cfg)").format( item=self.id, node=self.node.name, )) status_code = self.STATUS_SKIPPED keys_to_fix = [_("Fault unavailable")] else: if status_before.correct: status_code = self.STATUS_OK if status_code is None: keys_to_fix = self.display_keys( copy(self.cached_cdict), copy(status_before.sdict), status_before.keys_to_fix[:], ) if not interactive: with io.job( _(" {node} {bundle} {item} fixing...").format( bundle=self.bundle.name, item=self.id, node=self.node.name, )): self.fix(status_before) else: if status_before.must_be_created: question_text = _("Doesn't exist. Will be created.") elif status_before.must_be_deleted: question_text = _("Found on node. Will be removed.") else: cdict, sdict = self.display_dicts( copy(self.cached_cdict), copy(status_before.sdict), keys_to_fix, ) question_text = self.ask(cdict, sdict, keys_to_fix) if self.comment: question_text += format_comment(self.comment) question = wrap_question( self.id, question_text, _("Fix {}?").format(bold(self.id)), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ) answer = io.ask( question, interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), ) if answer: with io.job( _(" {node} {bundle} {item} fixing...").format( bundle=self.bundle.name, item=self.id, node=self.node.name, )): self.fix(status_before) else: status_code = self.STATUS_SKIPPED keys_to_fix = [_("interactive")] if status_code is None: status_after = self.get_status(cached=False) status_code = self.STATUS_FIXED if status_after.correct else self.STATUS_FAILED if status_code == self.STATUS_SKIPPED: # can't use else for this because status_before is None changes = keys_to_fix elif status_before.must_be_created: changes = True elif status_before.must_be_deleted: changes = False elif status_code == self.STATUS_FAILED: changes = self.display_keys( self.cached_cdict.copy(), status_after.sdict.copy(), status_after.keys_to_fix[:], ) else: changes = keys_to_fix self.node.repo.hooks.item_apply_end( self.node.repo, self.node, self, duration=datetime.now() - start_time, status_code=status_code, status_before=status_before, status_after=status_after, ) return (status_code, changes)
def _get_result( self, autoskip_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): if self._faults_missing_for_attributes: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug(_( "skipping {item} on {node} because it is missing faults " "for these attributes: {attrs} " "(most of the time this means you're missing " "a required key in your .secrets.cfg)" ).format( attrs=", ".join(sorted(self._faults_missing_for_attributes)), item=self.id, node=self.node.name, )) return (self.STATUS_SKIPPED, self.SKIP_REASON_FAULT_UNAVAILABLE) if self.covered_by_autoskip_selector(autoskip_selector): io.debug(_( "autoskip matches {item} on {node}" ).format(item=self.id, node=self.node.name)) return (self.STATUS_SKIPPED, self.SKIP_REASON_CMDLINE) if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): return (self.STATUS_SKIPPED, self.SKIP_REASON_SOFTLOCK) if interactive is False and self.attributes['interactive'] is True: return (self.STATUS_SKIPPED, self.SKIP_REASON_INTERACTIVE_ONLY) for item in self._precedes_items: if item._triggers_preceding_items(interactive=interactive): io.debug(_( "preceding item {item} on {node} has been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) self.has_been_triggered = True break else: io.debug(_( "preceding item {item} on {node} has NOT been triggered by {other_item}" ).format(item=self.id, node=self.node.name, other_item=item.id)) if self.triggered and not self.has_been_triggered: io.debug(_("skipping {} because it wasn't triggered").format(self.id)) return (self.STATUS_SKIPPED, self.SKIP_REASON_NO_TRIGGER) if self.unless: with io.job(_("{node} {bundle} {item} checking 'unless' condition").format( bundle=bold(self.bundle.name), item=self.id, node=bold(self.node.name), )): unless_result = self.bundle.node.run( self.unless, may_fail=True, ) if unless_result.return_code == 0: io.debug(_("{node}:{bundle}:action:{name}: failed 'unless', not running").format( bundle=self.bundle.name, name=self.name, node=self.bundle.node.name, )) return (self.STATUS_SKIPPED, self.SKIP_REASON_UNLESS) question_body = "" if self.attributes['data_stdin'] is not None: question_body += "<" + _("data") + "> | " question_body += self.attributes['command'] if self.comment: question_body += format_comment(self.comment) if ( interactive and self.attributes['interactive'] is not False and not io.ask( wrap_question( self.id, question_body, _("Run action {}?").format( bold(self.name), ), prefix="{x} {node} ".format( node=bold(self.node.name), x=blue("?"), ), ), interactive_default, epilogue="{x} {node}".format( node=bold(self.node.name), x=blue("?"), ), ) ): return (self.STATUS_SKIPPED, self.SKIP_REASON_INTERACTIVE) try: self.run() return (self.STATUS_ACTION_SUCCEEDED, None) except ActionFailure as exc: return (self.STATUS_FAILED, [str(exc)])
def apply( self, autoskip_selector="", my_soft_locks=(), other_peoples_soft_locks=(), interactive=False, interactive_default=True, ): self.node.repo.hooks.item_apply_start(self.node.repo, self.node, self) keys_to_fix = None status_code = None status_before = None status_after = None start_time = datetime.now() if self.covered_by_autoskip_selector(autoskip_selector): io.debug(_("autoskip matches {item} on {node}").format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED keys_to_fix = [_("cmdline")] if self._skip_with_soft_locks(my_soft_locks, other_peoples_soft_locks): status_code = self.STATUS_SKIPPED keys_to_fix = [_("soft locked")] if self.triggered and not self.has_been_triggered and status_code is None: io.debug( _("skipping {item} on {node} because it wasn't triggered").format(item=self.id, node=self.node.name) ) status_code = self.STATUS_SKIPPED keys_to_fix = [_("not triggered")] if status_code is None and self.cached_unless_result and status_code is None: io.debug(_("'unless' for {item} on {node} succeeded, not fixing").format(item=self.id, node=self.node.name)) status_code = self.STATUS_SKIPPED keys_to_fix = ["unless"] if self._faults_missing_for_attributes and status_code is None: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _( "skipping {item} on {node} because it is missing faults " "for these attributes: {attrs} " "(most of the time this means you're missing " "a required key in your .secrets.cfg)" ).format( attrs=", ".join(sorted(self._faults_missing_for_attributes)), item=self.id, node=self.node.name ) ) status_code = self.STATUS_SKIPPED keys_to_fix = [_("Fault unavailable")] if status_code is None: try: status_before = self.cached_status except FaultUnavailable: if self.error_on_missing_fault: self._raise_for_faults() else: io.debug( _( "skipping {item} on {node} because it is missing Faults " "(most of the time this means you're missing " "a required key in your .secrets.cfg)" ).format(item=self.id, node=self.node.name) ) status_code = self.STATUS_SKIPPED keys_to_fix = [_("Fault unavailable")] else: if status_before.correct: status_code = self.STATUS_OK if status_code is None: keys_to_fix = self.display_keys( copy(self.cached_cdict), copy(status_before.sdict), status_before.keys_to_fix[:] ) if not interactive: with io.job( _(" {node} {bundle} {item} fixing...").format( bundle=self.bundle.name, item=self.id, node=self.node.name ) ): self.fix(status_before) else: if status_before.must_be_created: question_text = _("Doesn't exist. Will be created.") elif status_before.must_be_deleted: question_text = _("Found on node. Will be removed.") else: cdict, sdict = self.display_dicts(copy(self.cached_cdict), copy(status_before.sdict), keys_to_fix) question_text = self.ask(cdict, sdict, keys_to_fix) question = wrap_question( self.id, question_text, _("Fix {}?").format(bold(self.id)), prefix="{x} {node} ".format(node=bold(self.node.name), x=blue("?")), ) answer = io.ask( question, interactive_default, epilogue="{x} {node}".format(node=bold(self.node.name), x=blue("?")) ) if answer: with io.job( _(" {node} {bundle} {item} fixing...").format( bundle=self.bundle.name, item=self.id, node=self.node.name ) ): self.fix(status_before) else: status_code = self.STATUS_SKIPPED keys_to_fix = [_("interactive")] if status_code is None: status_after = self.get_status(cached=False) status_code = self.STATUS_FIXED if status_after.correct else self.STATUS_FAILED if status_code == self.STATUS_SKIPPED: # can't use else for this because status_before is None changes = keys_to_fix elif status_before.must_be_created: changes = True elif status_before.must_be_deleted: changes = False elif status_code == self.STATUS_FAILED: changes = self.display_keys( self.cached_cdict.copy(), status_after.sdict.copy(), status_after.keys_to_fix[:] ) else: changes = keys_to_fix self.node.repo.hooks.item_apply_end( self.node.repo, self.node, self, duration=datetime.now() - start_time, status_code=status_code, status_before=status_before, status_after=status_after, ) return (status_code, changes)