コード例 #1
0
ファイル: yaml_merge.py プロジェクト: bbenshab/yamlpath
def process_yaml_file(
    merger: Merger, log: ConsolePrinter, rhs_yaml: Any, rhs_file: str,
    merger_primed: bool
):
    """Merge RHS document(s) into the prime document."""
    # Except for - (STDIN), each YAML_FILE must actually be a file; because
    # merge data is expected, this is a fatal failure.
    if rhs_file != "-" and not isfile(rhs_file):
        log.error("Not a file:  {}".format(rhs_file))
        return 2

    log.info(
        "Processing {}...".format(
            "STDIN" if rhs_file.strip() == "-" else rhs_file))

    return merge_multidoc(rhs_file, rhs_yaml, log, merger, merger_primed)
コード例 #2
0
 def test_info_quiet(self, capsys):
     args = SimpleNamespace(verbose=False, quiet=True, debug=False)
     logger = ConsolePrinter(args)
     logger.info("Test")
     console = capsys.readouterr()
     assert not console.out
コード例 #3
0
def main():
    """Main code."""
    # Process any command-line arguments
    args = processcli()
    log = ConsolePrinter(args)
    validateargs(args, log)
    processor = EYAMLProcessor(log, None, binary=args.eyaml)

    # Prep the YAML parser
    yaml = Parsers.get_yaml_editor()

    # Process the input file(s)
    in_file_count = len(args.yaml_files)
    exit_state = 0
    for yaml_file in args.yaml_files:
        file_changed = False
        backup_file = yaml_file + ".bak"
        seen_anchors = []

        # Each YAML_FILE must actually be a file
        if not isfile(yaml_file):
            log.error("Not a file:  {}".format(yaml_file))
            exit_state = 2
            continue

        # Don't bother with the file change update when there's only one input
        # file.
        if in_file_count > 1:
            log.info("Processing {}...".format(yaml_file))

        # Try to open the file
        (yaml_data, doc_loaded) = Parsers.get_yaml_data(yaml, log, yaml_file)
        if not doc_loaded:
            # An error message has already been logged
            exit_state = 3
            continue

        # Process all EYAML values
        processor.data = yaml_data
        for yaml_path in processor.find_eyaml_paths():
            # Use ::get_nodes() instead of ::get_eyaml_values() here in order
            # to ignore values that have already been rotated via their
            # Anchors.
            for node_coordinate in processor.get_nodes(yaml_path,
                                                       mustexist=True):
                # Ignore values which are Aliases for those already decrypted
                node = node_coordinate.node
                anchor_name = Anchors.get_node_anchor(node)
                if anchor_name is not None:
                    if anchor_name in seen_anchors:
                        continue

                    seen_anchors.append(anchor_name)

                log.verbose("Decrypting value(s) at {}.".format(yaml_path))
                processor.publickey = args.oldpublickey
                processor.privatekey = args.oldprivatekey

                try:
                    txtval = processor.decrypt_eyaml(node)
                except EYAMLCommandException as ex:
                    log.error(ex)
                    exit_state = 3
                    continue

                # Prefer block (folded) values unless the original YAML value
                # was already a massivly long (string) line.
                output = EYAMLOutputFormats.BLOCK
                if not isinstance(node, FoldedScalarString):
                    output = EYAMLOutputFormats.STRING

                # Re-encrypt the value with new EYAML keys
                processor.publickey = args.newpublickey
                processor.privatekey = args.newprivatekey

                try:
                    processor.set_eyaml_value(yaml_path, txtval, output=output)
                except EYAMLCommandException as ex:
                    log.error(ex)
                    exit_state = 3
                    continue

                file_changed = True

        # Save the changes
        if file_changed:
            if args.backup:
                log.verbose("Saving a backup of {} to {}.".format(
                    yaml_file, backup_file))
                if exists(backup_file):
                    remove(backup_file)
                copy2(yaml_file, backup_file)

            log.verbose("Writing changed data to {}.".format(yaml_file))
            with open(yaml_file, 'w', encoding='utf-8') as yaml_dump:
                yaml.dump(yaml_data, yaml_dump)

    sys.exit(exit_state)
コード例 #4
0
def check_playbook_file_removed_and_added(playbook_path):
    playbook_ok = True

    yaml_parser = Parsers.get_yaml_editor()

    logging_args = SimpleNamespace(quiet=False, verbose=False, debug=False)
    log = ConsolePrinter(logging_args)

    # Find every path removed by a file Task (also matches tasks within blocks)
    files_absent_string = "tasks.**.file[state=absent][parent()].path"
    files_absent_yamlpath = YAMLPath(files_absent_string)
    path_editing_tasks_yamlpath = ""

    log.info("Info: Evaluating playbook '{}'".format(playbook_path))
    (yaml_data, doc_loaded) = Parsers.get_yaml_data(yaml_parser, log,
                                                    playbook_path)
    if not doc_loaded:
        # There was an issue loading the file; an error message has already been
        # printed via ConsolePrinter.
        return False

    processor = Processor(log, yaml_data)
    try:
        for node in processor.get_nodes(files_absent_yamlpath,
                                        mustexist=False):
            path = str(node)
            # 'node' is a NodeCoords.
            if path == 'None':
                continue
            elif "{{" in path:
                # Identified path is a Jinja expression, unfortunately there is no easy way to get
                # the actual path without making this test very complicated
                continue

            # Check if this paths is used in any of the following ansible modules
            ansible_modules = ["lineinfile", "blockinfile", "copy"]
            path_editing_tasks_string = "tasks.**.[.=~/{modules}/][*='{path}'][parent()].name"
            path_editing_tasks_yamlpath = YAMLPath(
                path_editing_tasks_string.format(
                    modules="|".join(ansible_modules), path=node))
            for task in processor.get_nodes(path_editing_tasks_yamlpath,
                                            mustexist=False):
                log.info(
                    "Error: Task '{}' manipulates a file that is removed by another task"
                    .format(task))
                playbook_ok = False
    except YAMLPathException as ex:
        no_file_msg = (
            "Cannot add PathSegmentTypes.TRAVERSE subreference to lists at 'None' "
            "in '{}'.")
        if str(ex) == no_file_msg.format(files_absent_string):
            log.info(
                "Info: Playbook {} has no 'file' tasks.".format(playbook_path))
        elif path_editing_tasks_yamlpath and str(ex) == no_file_msg.format(
                path_editing_tasks_yamlpath):
            log.info("Info: Playbook {} has no '{}' tasks.".format(
                playbook_path, " ".join(ansible_modules)))
        else:
            log.info("Error: {}.".format(ex))

    return playbook_ok