Morrolan
2/27/2015 - 11:24 AM

Zabbix Deployment Script

Zabbix Deployment Script

__author__ = 'ihavelock'

# system modules
import logging
import json
import argparse
import os
import shutil
import fileinput

# custom modules
import afcsupport3

# third-party modules

# particular imports

################### CONSTANTS ####################

SETTINGS = r"config/config.json"

################### VARIABLES ####################

#

################### FUNCTIONS ####################


def begin():
    """
    As always, lets start at the beginning!

    """

    # load our settings into a dict
    settings = get_settings()

    logging.basicConfig(filename=settings['log_file'], level=logging.DEBUG,
                        format='%(asctime)s %(levelname)s:  %(message)s')

    logging.info("\n\n\n")
    logging.info("#########################################################################")
    logging.info("#")
    logging.info("# Zabbix Agent Config & Script Deployment Manager v0.1")
    logging.info("# Written by Ian Havelock")
    logging.info("#")
    logging.info("#########################################################################")

    # read commandline arguments
    logging.info("Parsing commandline arguments.")
    args = parse_arguments()

    # stitch together the filename from the commandline parameter and the directory, and add file extension.
    filename = args + ".json"
    logging.info("User has specified '{0}' environment file as a parameter.")
    file_path = os.path.join(settings['environment_dir'], filename)

    # pass the filename to the JSON parser so that we (hopefully!) have a list containing a dict per server.
    logging.info("Attempting to read server list.")
    servers_list = parse_json(file_path)

    logging.info("Checking that server list is correctly formed.")
    check_integrity(servers_list)

    logging.info("Attempting to process servers in list.")
    process_server_list(servers_list)

    # TODO: Check to see if RDP available, if so mount network share, if not stick file on holding area (TBD)


def get_settings():
    """
    Import settings from the JSON settings file!

    :return: dict
    """
    imported_settings = json.load(open(os.path.normpath(SETTINGS)))
    #print(imported_settings)
    settings_dict = imported_settings['config'][0]
    return settings_dict


def parse_arguments():
    """
    Here we will parse the commandline arguments and switches

    :return: list
    """
    parser = argparse.ArgumentParser()

    # tell our parser what to look for and a description of what it does.
    parser.add_argument("--environment", "-e",
                        help="Please enter the environment that you wish to update, i.e. 'ST4'.")

    # parse them to see if any were specified
    argo = parser.parse_args()

    # set our argdata variable to point to the environment parameter (perfectly fine if nothing is specified)

    # By doing it this way, and adding another layer before the return, it allows us to easily expand the args later
    # if required.
    argdata = argo.environment

    logging.info("Arguments passed:  {0}".format(argdata))

    return argdata


def parse_json(env):
    """
    Here we will first check to see if the file exists, and if so open it as a JSON object.

    :param env: string representing the filepath of the settings file to open.
    :return: list
    """

    servers_list = None
    # little bit of error handling in case the concatenated filename doesn't actually exist.
    logging.info("Checking to see if specified JSON file exists.")
    try:
        imported_servers = json.load(open(os.path.normpath(env)))
        servers_list = imported_servers['servers']
    except IOError:

        e = "The environment file you have specified at '{0}' does not exist.  Please try again.".format(env)
        logging.error(e)

        print(e)
        exit(1)

    return servers_list


def check_integrity(servers_list):
    """
    What we'll do here is to check as we go that we get the expected object type, i.e. a dict where we expect a dict.

    :param servers_list:
    """
    try:
        logging.info("Asserting that server list is actually a 'list' object.")
        assert(isinstance(servers_list, list))
    except AssertionError:
        e = "Type assertion failed - expected a list."
        logging.error(e)
        print(e)
        exit(1)

    logging.info("Asserting that all list entries are 'dict' object types.")
    for server in servers_list:
        try:
            assert(isinstance(server, dict))
        except AssertionError:
            e = "Type assertion failed - expected a dict."
            logging.error(e)
            print(e)
            exit(1)


def process_server_list(servers_list):
    """
    What we'll do here is to iterate through our list of servers, and do our processing as we go!

    :param servers_list:
    """

    settings = get_settings()
    master_dir = settings['master_dir']
    temp_dir = settings['temp_dir']
    zabbix_conf = os.path.join(temp_dir, settings['zabbix_conf'])

    for server in servers_list:

        if os.path.exists(temp_dir):
            logging.info("temp dir exists - deleting...")
            shutil.rmtree(temp_dir)

        if os.path.exists(master_dir):
            logging.info("Copying master directory to temp directory.")
            shutil.copytree(master_dir, temp_dir)

        else:
            e = "The directory '{0}' does not exist.".format(master_dir)
            logging.error(e)
            print(e)

        # now that we have our temp_dir, lets go replace the hostname?

        for line in fileinput.input(zabbix_conf, inplace=True):
            print(line.replace('#HOSTNAME#', server['hostname']), end='')

        copy_to_destination(server)


def copy_to_destination(server):
    """

    :param server:
    """
    settings = get_settings()
    temp_dir = settings['temp_dir']

    if server['rdp'] == "True":
        share = "\\\\" + server['ip'] + "\\" + server['path']
        logging.info("Share directory:  {0}".format(str(os.path.normpath(share))))
    else:
        share = settings['holding_area'] + "\\" + server['ip']
        logging.info("Share directory:  {0}".format(str(os.path.normpath(share))))

        if not os.path.isdir(share):
            os.makedirs(share)

    username = server['domain'] + "\\" + server['username']
    password = server['password']

    logging.info("Attempting to mount share...")
    afcsupport3.mount_share(share, username, password)
    logging.info("Share mounted successfully.")

    logging.info("Copying files to destination...")
    recursive_overwrite(temp_dir, share)


def recursive_overwrite(src, dest, ignore=None):
    if os.path.isdir(src):
        if not os.path.isdir(dest):
            os.makedirs(dest)
        files = os.listdir(src)
        if ignore is not None:
            ignored = ignore(src, files)
        else:
            ignored = set()
        for f in files:
            if f not in ignored:
                if not f.endswith('.exe'):  # hack because I can't get the ignore shit to work!
                    logging.info("Copying '{0}' to '{1}'".format(str(f), dest))
                    recursive_overwrite(os.path.join(src, f),
                                        os.path.join(dest, f),
                                        ignore)
    else:
        shutil.copyfile(src, dest)


def main():
    begin()


###############################################

if __name__ == "__main__":
    main()