def matchyaml(self, file: Lintable) -> List[MatchError]: matches: List[MatchError] = [] if not self.matchplay or str(file.base_kind) != 'text/yaml': return matches yaml = ansiblelint.utils.parse_yaml_linenumbers(file) # yaml returned can be an AnsibleUnicode (a string) when the yaml # file contains a single string. YAML spec allows this but we consider # this an fatal error. if isinstance(yaml, str): if yaml.startswith('$ANSIBLE_VAULT'): return [] return [MatchError(filename=str(file.path), rule=LoadingFailureRule())] if not yaml: return matches if isinstance(yaml, dict): yaml = [yaml] yaml = ansiblelint.skip_utils.append_skipped_rules(yaml, file) for play in yaml: # Bug #849 if play is None: continue if self.id in play.get('skipped_rules', ()): continue matches.extend(self.matchplay(file, play)) return matches
def run( self, file: Lintable, tags: Set[str] = set(), skip_list: List[str] = [] ) -> List[MatchError]: matches: List[MatchError] = list() if not file.path.is_dir(): try: if file.content is not None: # loads the file content pass except IOError as e: return [ MatchError( message=str(e), filename=file, rule=LoadingFailureRule(), tag=e.__class__.__name__.lower(), ) ] for rule in self.rules: if ( not tags or rule.has_dynamic_tags or not set(rule.tags).union([rule.id]).isdisjoint(tags) ): rule_definition = set(rule.tags) rule_definition.add(rule.id) if set(rule_definition).isdisjoint(skip_list): matches.extend(rule.getmatches(file)) # some rules can produce matches with tags that are inside our # skip_list, so we need to cleanse the matches matches = [m for m in matches if m.tag not in skip_list] return matches
def _emit_matches(self, files: List[Lintable]) -> Generator[MatchError, None, None]: visited: Set[Lintable] = set() while visited != self.lintables: for lintable in self.lintables - visited: try: for child in ansiblelint.utils.find_children(lintable): if self.is_excluded(str(child.path)): continue self.lintables.add(child) files.append(child) except MatchError as e: e.rule = LoadingFailureRule() yield e except AttributeError: yield MatchError( filename=str(lintable.path), rule=LoadingFailureRule() ) visited.add(lintable)
def _emit_matches(self, files: List[Lintable]) -> Generator[MatchError, None, None]: visited: Set = set() while visited != self.playbooks: for arg in self.playbooks - visited: try: for child in ansiblelint.utils.find_children(arg, self.playbook_dir): if self.is_excluded(str(child.path)): continue self.playbooks.add(child) files.append(child) except MatchError as e: e.rule = LoadingFailureRule() yield e visited.add(arg)
def matchyaml(self, file: Lintable) -> List[MatchError]: matches: List[MatchError] = [] if not self.matchplay: return matches yaml = ansiblelint.utils.parse_yaml_linenumbers( file.content, file.path) # yaml returned can be an AnsibleUnicode (a string) when the yaml # file contains a single string. YAML spec allows this but we consider # this an fatal error. if isinstance(yaml, str): return [MatchError(filename=file.path, rule=LoadingFailureRule())] if not yaml: return matches if isinstance(yaml, dict): yaml = [yaml] yaml = ansiblelint.skip_utils.append_skipped_rules( yaml, file.content, file.kind) for play in yaml: # Bug #849 if play is None: continue if self.id in play.get('skipped_rules', ()): continue result = self.matchplay(file, play) if not result: continue if isinstance(result, tuple): result = [result] if not isinstance(result, list): raise TypeError("{} is not a list".format(result)) for section, message, *optional_linenumber in result: linenumber = self._matchplay_linenumber( play, optional_linenumber) matches.append( self.create_matcherror(message=message, linenumber=linenumber, details=str(section), filename=file.path)) return matches
def __init__(self, rulesdirs: Optional[List[str]] = None) -> None: """Initialize a RulesCollection instance.""" if rulesdirs is None: rulesdirs = [] self.rulesdirs = ansiblelint.file_utils.expand_paths_vars(rulesdirs) self.rules: List[BaseRule] = [] # internal rules included in order to expose them for docs as they are # not directly loaded by our rule loader. self.rules.extend( [RuntimeErrorRule(), AnsibleParserErrorRule(), LoadingFailureRule()] ) for rulesdir in self.rulesdirs: _logger.debug("Loading rules from %s", rulesdir) self.extend(load_plugins(rulesdir)) self.rules = sorted(self.rules)
def find_children(lintable: Lintable) -> List[Lintable]: # noqa: C901 if not lintable.path.exists(): return [] playbook_dir = str(lintable.path.parent) _set_collections_basedir(playbook_dir or os.path.abspath('.')) add_all_plugin_dirs(playbook_dir or '.') if lintable.kind == 'role': playbook_ds = AnsibleMapping({'roles': [{'role': str(lintable.path)}]}) elif lintable.kind not in ("playbook", "tasks"): return [] else: try: playbook_ds = parse_yaml_from_file(str(lintable.path)) except AnsibleError as e: raise SystemExit(str(e)) results = [] basedir = os.path.dirname(str(lintable.path)) # playbook_ds can be an AnsibleUnicode string, which we consider invalid if isinstance(playbook_ds, str): raise MatchError(filename=str(lintable.path), rule=LoadingFailureRule()) for item in _playbook_items(playbook_ds): # if lintable.kind not in ["playbook"]: # continue for child in play_children(basedir, item, lintable.kind, playbook_dir): # We avoid processing parametrized children path_str = str(child.path) if "$" in path_str or "{{" in path_str: continue # Repair incorrect paths obtained when old syntax was used, like: # - include: simpletask.yml tags=nginx valid_tokens = list() for token in split_args(path_str): if '=' in token: break valid_tokens.append(token) path = ' '.join(valid_tokens) if path != path_str: child.path = Path(path) child.name = child.path.name results.append(child) return results
def run(self, playbookfile, tags=set(), skip_list=frozenset()) -> List: text = "" matches: List = list() error: Optional[IOError] = None for i in range(3): try: with open(playbookfile['path'], mode='r', encoding='utf-8') as f: text = f.read() break except IOError as e: _logger.warning("Couldn't open %s - %s [try:%s]", playbookfile['path'], e.strerror, i) error = e sleep(1) continue else: return [ MatchError(message=str(error), filename=playbookfile['path'], rule=LoadingFailureRule()) ] for rule in self.rules: if not tags or not set(rule.tags).union([rule.id ]).isdisjoint(tags): rule_definition = set(rule.tags) rule_definition.add(rule.id) if set(rule_definition).isdisjoint(skip_list): matches.extend(rule.matchlines(playbookfile, text)) matches.extend(rule.matchtasks(playbookfile, text)) matches.extend( rule.matchyaml( Lintable(playbookfile['path'], content=text, kind=playbookfile['type']))) # some rules can produce matches with tags that are inside our # skip_list, so we need to cleanse the matches matches = [m for m in matches if m.tag not in skip_list] return matches
def run( self, file: Lintable, tags=set(), skip_list=frozenset()) -> List[MatchError]: matches: List[MatchError] = list() error: Optional[IOError] = None for i in range(3): try: if file.content is not None: # loads the file content break except IOError as e: _logger.warning("Couldn't open %s - %s [try:%s]", file.path, e.strerror, i) error = e sleep(1) continue else: return [ MatchError(message=str(error), filename=str(file.path), rule=LoadingFailureRule()) ] for rule in self.rules: if not tags or not set(rule.tags).union([rule.id ]).isdisjoint(tags): rule_definition = set(rule.tags) rule_definition.add(rule.id) if set(rule_definition).isdisjoint(skip_list): matches.extend(rule.matchlines(file)) matches.extend(rule.matchtasks(file)) matches.extend(rule.matchyaml(file)) # some rules can produce matches with tags that are inside our # skip_list, so we need to cleanse the matches matches = [m for m in matches if m.tag not in skip_list] return matches