示例#1
0
def metamain(candidate, settings):
    try:
        fh = codecs.open(candidate.path, mode='rb', encoding='utf-8')
    except IOError, e:
        result = Result(candidate)
        result.errors = [Error(None, "Could not open %s: %s" %
                               (candidate.path, e))]
示例#2
0
def parse(candidate, options):
    result = Result(candidate.path)
    try:
        parse_inventory(candidate.path)
    except Exception as e:
        result.errors = [Error(None, "Inventory is broken: %s" % e.message)]
    return result
示例#3
0
def metamain(candidate, settings):
    try:
        fh = codecs.open(candidate.path, mode='rb', encoding='utf-8')
    except IOError, e:
        result = Result(candidate)
        result.errors = [
            Error(None, "Could not open %s: %s" % (candidate.path, e))
        ]
示例#4
0
def same_variable_defined_in_competing_groups(candidate, options):
    result = Result(candidate.path)
    # assume that group_vars file is under an inventory *directory*
    invfile = os.path.dirname(os.path.dirname(candidate.path))
    global _inv

    try:
        if ANSIBLE > 1:
            loader = ansible.parsing.dataloader.DataLoader()
            try:
                from ansible.inventory.manager import InventoryManager
                inv = _inv or InventoryManager(loader=loader, sources=invfile)
            except ImportError:
                var_manager = VariableManager()
                inv = _inv or ansible.inventory.Inventory(loader=loader,
                                                          variable_manager=var_manager,
                                                          host_list=invfile)
            _inv = inv
        else:
            inv = _inv or ansible.inventory.Inventory(invfile)
            _inv = inv
    except AnsibleError as e:
        result.errors = [Error(None, "Inventory is broken: %s" % e.message)]
        return result

    if hasattr(inv, 'groups'):
        group = inv.groups.get(os.path.basename(candidate.path))
    else:
        group = inv.get_group(os.path.basename(candidate.path))
    if not group:
        # group file exists in group_vars but no related group
        # in inventory directory
        return result
    remove_inherited_and_overridden_group_vars(group, inv)
    group_vars = set(_vars[group].keys())
    child_hosts = group.hosts
    child_groups = group.child_groups
    siblings = set()

    for child_host in child_hosts:
        siblings.update(child_host.groups)
    for child_group in child_groups:
        siblings.update(child_group.parent_groups)
    for sibling in siblings:
        if sibling != group:
            remove_inherited_and_overridden_group_vars(sibling, inv)
            sibling_vars = set(_vars[sibling].keys())
            common_vars = sibling_vars & group_vars
            common_hosts = [host.name for host in set(child_hosts) & set(sibling.hosts)]
            if common_vars and common_hosts:
                for var in common_vars:
                    error_msg_template = "Sibling groups {0} and {1} with common hosts {2} " + \
                                         "both define variable {3}"
                    error_msg = error_msg_template.format(group.name, sibling.name,
                                                          ", ".join(common_hosts), var)
                    result.errors.append(Error(None, error_msg))

    return result
示例#5
0
def same_variable_defined_in_competing_groups(candidate, options):
    result = Result(candidate.path)

    vaultpass = get_vault_password(options)
    # assume that group_vars file is under an inventory *directory*
    sdirs = candidate.path.split(os.sep)
    if sdirs.index('group_vars') == 0:
        invfile = os.getcwd()
    else:
        invfile = os.path.join(*sdirs[:sdirs.index('group_vars')])
    grpname = os.path.splitext(sdirs[sdirs.index('group_vars') + 1])[0]
    global _inv

    try:
        inv = _inv or parse_inventory(invfile)
    except AnsibleError as e:
        result.errors = [Error(None, "Inventory is broken: %s" % e.message)]
        return result

    if hasattr(inv, 'groups'):
        group = inv.groups.get(grpname)
    else:
        group = inv.get_group(grpname)
    if not group:
        # group file exists in group_vars but no related group
        # in inventory directory
        return result
    remove_inherited_and_overridden_group_vars(group, inv, invfile, vaultpass)
    group_vars = set(_vars[group].keys())
    child_hosts = group.hosts
    child_groups = group.child_groups
    siblings = set()

    for child_host in child_hosts:
        siblings.update(child_host.groups)
    for child_group in child_groups:
        siblings.update(child_group.parent_groups)
    for sibling in siblings:
        if sibling != group:
            remove_inherited_and_overridden_group_vars(sibling, inv, invfile,
                                                       vaultpass)
            sibling_vars = set(_vars[sibling].keys())
            common_vars = sibling_vars & group_vars
            common_hosts = [
                host.name for host in set(child_hosts) & set(sibling.hosts)
            ]
            if common_vars and common_hosts:
                for var in common_vars:
                    error_msg_template = "Sibling groups {0} and {1} with common hosts {2} " + \
                                         "both define variable {3}"
                    error_msg = error_msg_template.format(
                        group.name, sibling.name, ", ".join(common_hosts), var)
                    result.errors.append(Error(None, error_msg))

    return result
示例#6
0
def parse(candidate, options):
    result = Result(candidate.path)
    try:
        if ANSIBLE > 1:
            loader = ansible.parsing.dataloader.DataLoader()
            var_manager = ansible.vars.VariableManager()
            ansible.inventory.Inventory(loader=loader, variable_manager=var_manager,
                                        host_list=candidate.path)
        else:
            ansible.inventory.Inventory(candidate.path)
    except Exception, e:
        result.errors = [Error(None, "Inventory is broken: %s" % e.message)]
示例#7
0
def parse(candidate, options):
    result = Result(candidate.path)
    try:
        if ANSIBLE > 1:
            loader = ansible.parsing.dataloader.DataLoader()
            var_manager = ansible.vars.VariableManager()
            ansible.inventory.Inventory(loader=loader,
                                        variable_manager=var_manager,
                                        host_list=candidate.path)
        else:
            ansible.inventory.Inventory(candidate.path)
    except Exception, e:
        result.errors = [Error(None, "Inventory is broken: %s" % e.message)]
示例#8
0
def rolesfile_contains_scm_in_src(candidate, settings):
    result = Result(candidate.path)
    if candidate.path.endswith(".yml") and os.path.exists(candidate.path):
        try:
            with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
                roles = parse_yaml_linenumbers(f.read(), candidate.path)
            for role in roles:
                if '+' in role.get('src'):
                    error = Error(role['__line__'], "Use scm key rather "
                                  "than src: scm+url")
                    result.errors.append(error)
        except Exception, e:
            result.errors = [Error(None, "Cannot parse YAML from %s: %s" %
                                   (candidate.path, str(e)))]
示例#9
0
def rolesfile_contains_scm_in_src(candidate, settings):
    result = Result(candidate.path)
    if candidate.path.endswith(".yml") and os.path.exists(candidate.path):
        try:
            with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
                roles = parse_yaml_linenumbers(f.read(), candidate.path)
            for role in roles:
                if '+' in role.get('src'):
                    error = Error(role['__line__'], "Use scm key rather "
                                  "than src: scm+url")
                    result.errors.append(error)
        except Exception as e:
            result.errors = [Error(None, "Cannot parse YAML from %s: %s" %
                                   (candidate.path, str(e)))]
    return result
示例#10
0
def yamlrolesfile(candidate, settings):
    rolesfile = os.path.join(os.path.dirname(candidate.path), "rolesfile")
    result = Result(candidate)
    if os.path.exists(rolesfile) and not os.path.exists(rolesfile + ".yml"):
        result.errors = [Error(None, "Rolesfile %s does not "
                                     "have a yaml extension" % rolesfile)]
        return result
    rolesfile = os.path.join(os.path.dirname(candidate.path), "rolesfile.yml")
    if os.path.exists(rolesfile):
        with codecs.open(rolesfile, mode='rb', encoding='utf-8') as f:
            try:
                yaml.safe_load(f)
            except Exception, e:
                result.errors = [Error(None, "Cannot parse YAML from %s: %s" %
                                       (rolesfile, str(e)))]
示例#11
0
def files_should_have_actual_content(candidate, settings):
    errors = []
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        content = yaml.safe_load(f.read())
    if not content:
        errors = [Error(None, "%s appears to have no useful content" % candidate)]
    return Result(candidate.path, errors)
示例#12
0
def yaml_form_rather_than_key_value(candidate, settings):
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        content = parse_yaml_linenumbers(f.read(), candidate.path)
    errors = []
    if content:
        fileinfo = dict(type=candidate.filetype, path=candidate.path)
        for task in get_action_tasks(content, fileinfo):
            normal_form = normalize_task(task, candidate.path)
            action = normal_form['action']['__ansible_module__']
            arguments = normal_form['action']['__ansible_arguments__']
            # Cope with `set_fact` where task['set_fact'] is None
            if not task.get(action):
                continue
            if isinstance(task[action], dict):
                continue
            # allow skipping based on tag e.g. if using splatting
            # https://docs.ansible.com/ansible/devel/reference_appendices\
            # /faq.html#argsplat-unsafe
            if 'skip_ansible_lint' in (task.get('tags') or []):
                continue
            # strip additional newlines off task[action]
            if task[action].strip().split() != arguments:
                errors.append(Error(task['__line__'], "Task arguments appear "
                                    "to be in key value rather "
                                    "than YAML format"))
    return Result(candidate.path, errors)
示例#13
0
def yamlreview(candidate, settings):
    vaultpass = get_vault_password(settings)
    fname = get_decrypted_file(candidate.path, vaultpass)
    errors = indent_checker(fname)
    if candidate.path not in fname:
        os.unlink(fname)
    return Result(candidate.path, errors)
示例#14
0
def yamlrolesfile(candidate, settings):
    rolesfile = os.path.join(os.path.dirname(candidate.path), "rolesfile")
    result = Result(candidate)
    if os.path.exists(rolesfile) and not os.path.exists(rolesfile + ".yml"):
        result.errors = [Error(None, "Rolesfile %s does not "
                                     "have a .yml extension" % rolesfile)]
        return result
    rolesfile = os.path.join(os.path.dirname(candidate.path), "rolesfile.yml")
    if os.path.exists(rolesfile):
        with codecs.open(rolesfile, mode='rb', encoding='utf-8') as f:
            try:
                yaml.safe_load(f)
            except Exception as e:
                result.errors = [Error(None, "Cannot parse YAML from %s: %s" %
                                       (rolesfile, str(e)))]
    return result
示例#15
0
def code_passes_pycodestyle(candidate, options):
    result = utils.execute(["pycodestyle", candidate.path])
    errors = []
    if result.rc:
        for line in result.output.strip().split('\n'):
            lineno = int(line.split(':')[1])
            errors.append(Error(lineno, line))
    return Result(candidate.path, errors)
示例#16
0
def same_variable_defined_in_competing_groups(candidate, options):
    result = Result(candidate.path)
    # assume that group_vars file is under an inventory *directory*
    invfile = os.path.dirname(os.path.dirname(candidate.path))
    global _inv

    try:
        if ANSIBLE > 1:
            loader = ansible.parsing.dataloader.DataLoader()
            var_manager = ansible.vars.VariableManager()
            inv = _inv or ansible.inventory.Inventory(
                loader=loader, variable_manager=var_manager, host_list=invfile)
            _inv = inv
        else:
            inv = _inv or ansible.inventory.Inventory(invfile)
            _inv = inv
    except AnsibleError, e:
        result.errors = [Error(None, "Inventory is broken: %s" % e.message)]
        return result
示例#17
0
def no_vars_in_host_file(candidate, options):
    errors = []
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        try:
            yaml.safe_load(f)
        except Exception:
            for (lineno, line) in enumerate(f):
                if ':vars]' in line:
                    errors.append(
                        Error(lineno + 1, "contains a vars definition"))
    return Result(candidate.path, errors)
示例#18
0
def repeated_names(playbook, settings):
    with codecs.open(playbook['path'], mode='rb', encoding='utf-8') as f:
        yaml = parse_yaml_linenumbers(f, playbook['path'])
    namelines = defaultdict(list)
    errors = []
    if yaml:
        for task in get_action_tasks(yaml, playbook):
            if 'name' in task:
                namelines[task['name']].append(task['__line__'])
        for (name, lines) in namelines.items():
            if len(lines) > 1:
                errors.append(Error(lines[-1],
                                    "Task/handler name %s appears multiple times" % name))
    return Result(playbook, errors)
示例#19
0
def playbook_contains_logic(candidate, settings):
    errors = []
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        plays = parse_yaml_linenumbers(f.read(), candidate.path)
    for logic in ['tasks', 'pre_tasks', 'post_tasks', 'vars', 'handlers']:
        for play in plays:
            if logic in play:
                if isinstance(play[logic], list):
                    firstitemline = play[logic][0]['__line__'] - 1
                elif isinstance(play[logic], dict):
                    firstitemline = play[logic]['__line__']
                else:
                    continue
                # we can only access line number of first thing in the section
                # so we guess the section starts on the line above.
                errors.append(
                    Error(firstitemline,
                          "%s should not be required in a play" % logic))

    return Result(candidate.path, errors)
示例#20
0
def yaml_form_rather_than_key_value(candidate, settings):
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        content = parse_yaml_linenumbers(f.read(), candidate.path)
    errors = []
    if content:
        fileinfo = dict(type=candidate.filetype, path=candidate.path)
        for task in get_action_tasks(content, fileinfo):
            normal_form = normalize_task(task, candidate.path)
            action = normal_form['action']['__ansible_module__']
            arguments = normal_form['action']['__ansible_arguments__']
            # Cope with `set_fact` where task['set_fact'] is None
            if not task.get(action):
                continue
            if isinstance(task[action], dict):
                continue
            # strip additional newlines off task[action]
            if task[action].strip().split() != arguments:
                errors.append(
                    Error(
                        task['__line__'], "Task arguments appear "
                        "to be in key value rather "
                        "than YAML format"))
    return Result(candidate.path, errors)
示例#21
0
def yaml_form_rather_than_key_value(candidate, settings):
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        content = parse_yaml_linenumbers(f.read(), candidate.path)
    errors = []
    if content:
        fileinfo = dict(type=candidate.filetype, path=candidate.path)
        for task in get_action_tasks(content, fileinfo):
            normal_form = normalize_task(task, candidate.path)
            action = normal_form['action']['__ansible_module__']
            arguments = normal_form['action']['__ansible_arguments__']
            # FIXME: This is a bug - perhaps when connection is local
            # or similar
            if action not in task:
                continue
            if isinstance(task[action], dict):
                continue
            if task[action] != ' '.join(arguments):
                errors.append(
                    Error(
                        task['__line__'], "Task arguments appear "
                        "to be in key value rather "
                        "than YAML format"))
    return Result(candidate.path, errors)
示例#22
0
def noop(candidate, settings):
    return Result(candidate.path)
示例#23
0
def host_vars_exist(candidate, settings):
    return Result(candidate.path,
                  [Error(None, "Host vars are generally "
                         "not required")])
示例#24
0
def repeated_vars(candidate, settings):
    with codecs.open(candidate.realpath, 'r') as f:
        errors = hunt_repeated_yaml_keys(f) or dict()
    return Result(candidate, [Error(err_line, "Variable %s occurs more than once" % err_key)
                              for err_key in errors for err_line in errors[err_key]])
示例#25
0
def host_vars_exist(candidate, settings):
    """Group variables are preferred over host variables."""
    return Result(candidate.path,
                  [Error(None, "Host vars are generally "
                         "not required")])
示例#26
0
def noop(candidate, settings):
    """No operation."""
    return Result(candidate.path)
示例#27
0
def yamlreview(candidate, settings):
    errors = indent_checker(candidate.path)
    return Result(candidate.path, errors)
示例#28
0
    with codecs.open(candidate.path, mode='rb', encoding='utf-8') as f:
        content = yaml.load(f.read())
    if not content:
        errors = [Error(None, "%s appears to have no useful content" % candidate)]
    return Result(candidate.path, errors)


def metamain(candidate, settings):
    try:
        fh = codecs.open(candidate.path, mode='rb', encoding='utf-8')
    except IOError, e:
        result = Result(candidate)
        result.errors = [Error(None, "Could not open %s: %s" %
                               (candidate.path, e))]
    try:
        result = Result(candidate)
        data = yaml.safe_load(fh)
        if 'dependencies' in data:
            if data["dependencies"] == []:
                return result
            else:
                result.errors = [Error(None, "Role dependencies are "
                                             "not empty")]
        else:
            result.errors = [Error(None, "Role meta/main.yml does "
                                         "not contain a dependencies section")]
    except Exception, e:
        result.errors = [Error(None, "Could not parse in %s: %s" %
                               (candidate.path, e))]
    finally:
        fh.close()
示例#29
0
def check_success(candidate, settings):
    return Result(candidate)
示例#30
0
def check_fail(candidate, settings):
    return Result(candidate, [Error(1, "test failed")])
示例#31
0
        errors = [
            Error(None, "%s appears to have no useful content" % candidate)
        ]
    return Result(candidate.path, errors)


def metamain(candidate, settings):
    try:
        fh = codecs.open(candidate.path, mode='rb', encoding='utf-8')
    except IOError, e:
        result = Result(candidate)
        result.errors = [
            Error(None, "Could not open %s: %s" % (candidate.path, e))
        ]
    try:
        result = Result(candidate)
        data = yaml.safe_load(fh)
        if 'dependencies' in data:
            if data["dependencies"] == []:
                return result
            else:
                result.errors = [
                    Error(None, "Role dependencies are "
                          "not empty")
                ]
        else:
            result.errors = [
                Error(
                    None, "Role meta/main.yml does "
                    "not contain a dependencies section")
            ]
示例#32
0
def repeated_vars(candidate, settings):
    with codecs.open(candidate.path, 'r') as text:
        errors = hunt_repeated_yaml_keys(text) or dict()
    return Result([Error(errors[err], "Variable %s occurs more than once" % err) for
                   err in errors])