Migrates Apex to Python
[apex.git] / apex / common / utils.py
diff --git a/apex/common/utils.py b/apex/common/utils.py
new file mode 100644 (file)
index 0000000..848f264
--- /dev/null
@@ -0,0 +1,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, '-vvv']
+    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.debug(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