#!/usr/bin/env python
#Adam Bowen - Apr 2016
#This script deletes a vdb
#requirements
#pip install docopt delphixpy

#The below doc follows the POSIX compliant standards and allows us to use 
#this doc to also define our arguments for the script. This thing is brilliant.
"""Delete a VDB

Usage:
  dx_delete_db.py (--group <name> [--name <name>] | --all_dbs )
                  [-d <identifier> | --engine <identifier> | --all]
                  [--usebackup] [--debug] [--parallel <n>] [--poll <n>]
                  [--config <path_to_file>] [--logdir <path_to_file>]
  dx_delete_db.py (--host <name> [--group <name>] [--object_type <type>] 
                  | --object_type <name> [--group <name>] [--host <type>] )
                  [-d <identifier> | --engine <identifier> | --all]
                  [--usebackup] [--debug] [--parallel <n>] [--poll <n>]
                  [--config <path_to_file>] [--logdir <path_to_file>]
  dx_delete_db.py -h | --help | -v | --version

Delete a VDB

Examples:
  dx_delete_db.py --group "Sources" --object_type dsource --usebackup
  dx_delete_db.py --name "Employee Oracle 11G DB"
  dx_delete_db.py --host LINUXSOURCE --parallel 2 --usebackup
  dx_delete_db.py --host LINUXSOURCE --parallel 4 --usebackup --debug -d landsharkengine



Options:
  -d <identifier>           Identifier of Delphix engine in dxtools.conf.
  --engine <type>           Alt Identifier of Delphix engine in dxtools.conf.
  --all                     Run against all engines.
  --all_dbs                 Run against all database objects
  --name <name>             Name of object in Delphix to execute against.
  --group <name>            Name of group in Delphix to execute against.
  --host <name>             Name of environment in Delphix to execute against.
  --object_type <obj_type>  dsource or vdb.
  --usebackup               Snapshot using "Most Recent backup".
                            Available for MSSQL and ASE only.
  --debug                   Enable debug logging
  --parallel <n>            Limit number of jobs to maxjob
  --poll <n>                The number of seconds to wait between job polls
                            [default: 10]
  --config <path_to_file>   The path to the dxtools.conf file
                            [default: ./dxtools.conf]
  --logdir <path_to_file>    The path to the logfile you want to use.
                            [default: ./dx_snapshot_db.log]
  -h --help                 Show this screen.
  -v --version              Show version.

"""

VERSION="v.0.0.001"


from docopt import docopt
import logging
from os.path import basename
import signal
import sys
import time
import traceback
import json

from multiprocessing import Process
from time import sleep, time

from delphixpy.v1_6_0.delphix_engine import DelphixEngine
from delphixpy.v1_6_0.exceptions import HttpError, JobError
from delphixpy.v1_6_0 import job_context
from delphixpy.v1_6_0.web import database, environment, group, job, source, user
from delphixpy.v1_6_0.web.vo import ASESpecificBackupSyncParameters, ASENewBackupSyncParameters, ASELatestBackupSyncParameters, MSSqlSyncParameters


def find_obj_by_name(engine, server, f_class, obj_name):
    """
    Function to find objects by name and object class, and return object's reference as a string
    You might use this function to find objects like groups.
    """
    print_debug(engine["hostname"] + ": Searching objects in the " + f_class.__name__ + " class\n   for one named \"" + obj_name +"\"")
    obj_ref = ''

    all_objs = f_class.get_all(server)
    for obj in all_objs:
        if obj.name == obj_name:
            print_debug(engine["hostname"] + ": Found a match " + str(obj.reference))
            return obj

def find_all_databases_by_group_name(engine, server, group_name, exclude_js_container=False):
    """
    Easy way to quickly find databases by group name
    """

    #First search groups for the name specified and return its reference
    group_obj = find_obj_by_name(engine, server, group, group_name)
    if group_obj:
        databases=database.get_all(server, group=group_obj.reference, no_js_container_data_source=exclude_js_container)
        return databases

def find_database_by_name_and_group_name(engine, server, group_name, database_name):

    databases = find_all_databases_by_group_name(engine, server, group_name)

    for each in databases:
        if each.name == database_name:
            print_debug(engine["hostname"] + ": Found a match " + str(each.reference))
            return each
    print_info("Unable to find \"" + database_name + "\" in " + group_name)

def find_source_by_database(engine, server, database_obj):
    #The source tells us if the database is enabled/disables, virtual, vdb/dSource, or is a staging database.
    source_obj = source.get_all(server, database=database_obj.reference)
    #We'll just do a little sanity check here to ensure we only have a 1:1 result.
    if len(source_obj) == 0:
        print_error(engine["hostname"] + ": Did not find a source for " + database_obj.name + ". Exiting")
        sys.exit(1)
    elif len(source_obj) > 1:
        print_error(engine["hostname"] + ": More than one source returned for " + database_obj.name + ". Exiting")
        print_error(source_obj)
        sys.exit(1)
    return source_obj

def get_config(config_file_path):
    """
    This function reads in the dxtools.conf file
    """
    #First test to see that the file is there and we can open it
    try:
        config_file = open(config_file_path).read()
    except:
        print_error("Was unable to open " + config_file_path + ". Please check the path and permissions, then try again.")
        sys.exit(1)
    #Now parse the file contents as json and turn them into a python dictionary, throw an error if it isn't proper json
    try:
        config = json.loads(config_file)
    except:
        print_error("Was unable to read " + config_file_path + " as json. Please check file in a json formatter and try again.")
        sys.exit(1)
    #Create a dictionary of engines (removing the data node from the dxtools.json, for easier parsing)
    delphix_engines = {}
    for each in config['data']:
        delphix_engines[each['hostname']] = each
    print_debug(delphix_engines)
    return delphix_engines

def logging_est(logfile_path):
    """
    Establish Logging
    """
    global debug
    logging.basicConfig(filename=logfile_path,format='%(levelname)s:%(asctime)s:%(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
    print_info("Welcome to " + basename(__file__) + ", version " + VERSION)
    global logger
    debug = arguments['--debug']
    logger = logging.getLogger()
    if debug == True:
        logger.setLevel(10)
        print_info("Debug Logging is enabled.")

def job_mode(server):
    """
    This function tells Delphix how to execute jobs, based on the single_thread variable at the beginning of the file
    """
    #Synchronously (one at a time)
    if single_thread == True:
        job_m = job_context.sync(server)
        print_debug("These jobs will be executed synchronously")
    #Or asynchronously
    else:
        job_m = job_context.async(server)
        print_debug("These jobs will be executed asynchronously")
    return job_m

def job_wait():
    """
    This job stops all work in the thread/process until jobs are completed.
    """
    #Grab all the jos on the server (the last 25, be default)
    all_jobs = job.get_all(server)
    #For each job in the list, check to see if it is running (not ended)
    for jobobj in all_jobs:
        if not (jobobj.job_state in ["CANCELED", "COMPLETED", "FAILED"]):
            print_debug("Waiting for " + jobobj.reference + " (currently: " + jobobj.job_state+ ") to finish running against the container")
            #If so, wait
            job_context.wait(server,jobobj.reference)