summaryrefslogtreecommitdiffstats
path: root/apex/common/utils.py
blob: e21ab8359783ab9edce4b89c29cfc6b33d06f8e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
##############################################################################
# Copyright (c) 2016 Tim Rozet (trozet@redhat.com) and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

import json
import logging
import os
import pprint
import subprocess
import yaml


def str2bool(var):
    if isinstance(var, bool):
        return var
    else:
        return var.lower() in ("true", "yes")


def parse_yaml(yaml_file):
    with open(yaml_file) as f:
        parsed_dict = yaml.safe_load(f)
        return parsed_dict


def dump_yaml(data, file):
    """
    Dumps data to a file as yaml
    :param data: yaml to be written to file
    :param file: filename to write to
    :return:
    """
    logging.debug("Writing file {} with "
                  "yaml data:\n{}".format(file, yaml.safe_dump(data)))
    with open(file, "w") as fh:
        yaml.safe_dump(data, fh, default_flow_style=False)


def dict_objects_to_str(dictionary):
        if isinstance(dictionary, list):
            tmp_list = []
            for element in dictionary:
                if isinstance(element, dict):
                    tmp_list.append(dict_objects_to_str(element))
                else:
                    tmp_list.append(str(element))
            return tmp_list
        elif not isinstance(dictionary, dict):
            if not isinstance(dictionary, bool):
                return str(dictionary)
            else:
                return dictionary
        return dict((k, dict_objects_to_str(v)) for
                    k, v in dictionary.items())


def run_ansible(ansible_vars, playbook, host='localhost', user='root',
                tmp_dir=None, dry_run=False):
    """
    Executes ansible playbook and checks for errors
    :param ansible_vars: dictionary of variables to inject into ansible run
    :param playbook: playbook to execute
    :param tmp_dir: temp directory to store ansible command
    :param dry_run: Do not actually apply changes
    :return: None
    """
    logging.info("Executing ansible playbook: {}".format(playbook))
    inv_host = "{},".format(host)
    if host == 'localhost':
        conn_type = 'local'
    else:
        conn_type = 'smart'
    ansible_command = ['ansible-playbook', '--become', '-i', inv_host,
                       '-u', user, '-c', conn_type, playbook, '-vv']
    if dry_run:
        ansible_command.append('--check')

    if isinstance(ansible_vars, dict) and ansible_vars:
        logging.debug("Ansible variables to be set:\n{}".format(
            pprint.pformat(ansible_vars)))
        ansible_command.append('--extra-vars')
        ansible_command.append(json.dumps(ansible_vars))
        if tmp_dir:
            ansible_tmp = os.path.join(tmp_dir,
                                       os.path.basename(playbook) + '.rerun')
            # FIXME(trozet): extra vars are printed without single quotes
            # so a dev has to add them manually to the command to rerun
            # the playbook.  Need to test if we can just add the single quotes
            # to the json dumps to the ansible command and see if that works
            with open(ansible_tmp, 'w') as fh:
                fh.write("ANSIBLE_HOST_KEY_CHECKING=FALSE {}".format(
                    ' '.join(ansible_command)))
    try:
        my_env = os.environ.copy()
        my_env['ANSIBLE_HOST_KEY_CHECKING'] = 'False'
        logging.info("Executing playbook...this may take some time")
        logging.info(subprocess.check_output(ansible_command, env=my_env,
                     stderr=subprocess.STDOUT).decode('utf-8'))
    except subprocess.CalledProcessError as e:
        logging.error("Error executing ansible: {}".format(
            pprint.pformat(e.output.decode('utf-8'))))
        raise