Esempio n. 1
0
    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)
Esempio n. 2
0
 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()
Esempio n. 3
0
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)
Esempio n. 4
0
    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)
Esempio n. 5
0
    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)
Esempio n. 6
0
    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)
Esempio n. 7
0
    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)])
Esempio n. 8
0
    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)])
Esempio n. 9
0
    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)
Esempio n. 10
0
    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)])
Esempio n. 11
0
    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)