def ask(self, status): if 'type' in status.info['needs_fixing']: if not status.info['path_info'].exists: return _("Doesn't exist.") else: return "{} {} → {}\n".format( bold(_("type")), status.info['path_info'].desc, _("file"), ) question = "" if 'owner' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("owner")), status.info['path_info'].owner, self.attributes['owner'], ) if 'group' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("group")), status.info['path_info'].group, self.attributes['group'], ) return question.rstrip("\n")
def ask(self, status): if not status.info['exists']: return _("'{}' not found in /etc/passwd").format(self.name) elif self.attributes['delete']: return _("'{}' found in /etc/passwd. Will be deleted.").format(self.name) output = "" for key, should_value in self.attributes.iteritems(): if key in ('delete', 'groups', 'hash_method', 'password', 'password_hash', 'salt', 'use_shadow'): continue is_value = status.info[key] if should_value != is_value: output += "{} {} → {}\n".format( bold(_ATTRIBUTE_NAMES[key]), is_value, should_value, ) if self.attributes['use_shadow']: filename = "/etc/shadow" found_hash = status.info['shadow_hash'] else: filename = "/etc/passwd" found_hash = status.info['passwd_hash'] if found_hash is None: output += bold(_ATTRIBUTE_NAMES['password_hash']) + " " + \ _("not found in {}").format(filename) + "\n" elif found_hash != self.attributes['password_hash']: output += bold(_ATTRIBUTE_NAMES['password_hash']) + " " + \ found_hash + "\n" output += " " * (len(_ATTRIBUTE_NAMES['password_hash']) - 1) + "→ " + \ self.attributes['password_hash'] + "\n" groups_should = set(self.attributes['groups']) groups_is = set(status.info['groups']) missing_groups = list(groups_should.difference(groups_is)) missing_groups.sort() extra_groups = list(groups_is.difference(groups_should)) extra_groups.sort() if missing_groups: output += bold(_("missing groups")) + " " + \ ", ".join(missing_groups) + "\n" if extra_groups: output += bold(_("extra groups")) + " " + \ ", ".join(extra_groups) + "\n" return output
def ask(self, status): before = _("installed") if status.info['installed'] \ else _("not installed") after = green(_("installed")) if self.attributes['installed'] \ else red(_("not installed")) return "{} {} → {}\n".format( bold(_("status")), before, after, )
def ask(self, status): if not status.info['exists']: return _("'{}' not found in /etc/group").format(self.name) elif self.attributes['delete']: return _("'{}' found in /etc/group. Will be deleted.").format(self.name) else: return "{} {} → {}\n".format( bold(_("GID")), status.info['gid'], self.attributes['gid'], )
def ask(self, status): if 'type' in status.info['needs_fixing']: if not status.info['path_info'].exists: return _("Doesn't exist. Do you want to create it?") else: return _( "Not a directory. " "The `file` utility says it's a '{}'.\n" "Do you want it removed and replaced?" ).format( status.info['path_info'].desc, ) question = "" if 'mode' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("mode")), status.info['path_info'].mode, self.attributes['mode'], ) if 'owner' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("owner")), status.info['path_info'].owner, self.attributes['owner'], ) if 'group' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("group")), status.info['path_info'].group, self.attributes['group'], ) return question.rstrip("\n")
def get_result(self, interactive=False, interactive_default=True): if interactive is False and self.attributes['interactive'] is True: return self.STATUS_ACTION_SKIPPED if self.triggered and not self.has_been_triggered: LOG.debug(_("skipping {} because it wasn't triggered").format(self.id)) return self.STATUS_ACTION_SKIPPED if self.unless: unless_result = self.bundle.node.run( self.unless, may_fail=True, ) if unless_result.return_code == 0: LOG.debug(_("{node}:action:{name}: failed 'unless', not running").format( name=self.name, node=self.bundle.node.name, )) return self.STATUS_ACTION_SKIPPED if ( interactive and self.attributes['interactive'] is not False and not ask_interactively( wrap_question( self.id, self.attributes['command'], _("Run action {}?").format( bold(self.name), ), ), interactive_default, ) ): return self.STATUS_ACTION_SKIPPED try: self.run(interactive=interactive) return self.STATUS_ACTION_OK except ActionFailure: return self.STATUS_ACTION_FAILED
def apply(self, 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.triggered and not self.has_been_triggered: LOG.debug(_("skipping {} because it wasn't triggered").format(self.id)) status_code = self.STATUS_SKIPPED if status_code is None: status_before = self.get_status() if self.unless and not status_before.correct: unless_result = self.node.run(self.unless, may_fail=True) if unless_result.return_code == 0: LOG.debug(_("'unless' for {} succeeded, not fixing").format(self.id)) status_code = self.STATUS_SKIPPED if status_code is None: if status_before.correct: status_code = self.STATUS_OK if status_code is None: if not interactive: self.fix(status_before) status_after = self.get_status() else: question = wrap_question( self.id, self.ask(status_before), _("Fix {}?").format(bold(self.id)), ) if ask_interactively(question, interactive_default): self.fix(status_before) status_after = self.get_status() else: status_code = self.STATUS_SKIPPED if status_code is None: if status_after.correct: status_code = self.STATUS_FIXED else: status_code = self.STATUS_FAILED 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
def ask(self, status): if 'type' in status.info['needs_fixing']: if not status.info['path_info'].exists: return _("Doesn't exist.") elif self.attributes['delete']: if status.info['path_info'].is_directory: return _("Directory and its contents will be deleted.") else: return _("File will be deleted.") else: return "{} {} → {}\n".format( bold(_("type")), status.info['path_info'].desc, _("file"), ) question = "" if 'content' in status.info['needs_fixing']: question += bold(_("content ")) if ( status.info['path_info'].is_text_file and not self.attributes['content_type'] == 'binary' ): if status.info['path_info'].size > DIFF_MAX_FILE_SIZE: question += _("(remote file larger than {} bytes, skipping diff)\n").format( DIFF_MAX_FILE_SIZE, ) elif len(self.content) > DIFF_MAX_FILE_SIZE: question += _("(new content larger than {} bytes, skipping diff)\n").format( DIFF_MAX_FILE_SIZE, ) else: content_is = get_remote_file_contents(self.node, self.name) content_should = self.content question += "\n" + diff( content_is, content_should, self.name, encoding_hint=self.attributes['encoding'], ) + "\n" else: question += "'{}' → {}\n".format( status.info['path_info'].desc, _("<blockwart content>"), ) if 'mode' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("mode")), status.info['path_info'].mode, self.attributes['mode'], ) if 'owner' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("owner")), status.info['path_info'].owner, self.attributes['owner'], ) if 'group' in status.info['needs_fixing']: question += "{} {} → {}\n".format( bold(_("group")), status.info['path_info'].group, self.attributes['group'], ) return question.rstrip("\n")