#!/usr/bin/python
#
# Copyright 2011, Pall Sigurdsson <palli@opensource.is>
#
# This script is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


# No real need to change anything below here
version="1.0"

import sys
import okconfig
import os
import getpass

# Parse some Arguments
from optparse import OptionParser,OptionGroup

usage = """usage: %prog <command> [arguments]

Common okconfig commands:
  addhost       add a new host
  addtemplate   add a new template to existing host
  addgroup      add a new host/contact/service group
  addcontact    add a new contact
  listtemplates List all available templates
  listhosts     List all hosts
  init          Initilize nagios to use okconfig
  install       Install an agent on a remote server
  upgrade       runs migration routines in case of okconfig upgrades
  verify        verifies current okconfig installation

For help on specific command type:
 %prog <command> --help

Examples:
 %prog addgroup linuxservers --alias "Example Linux Servers"
 %prog addhost <host_name> --template linux --address 127.0.0.1 --group linuxservers
 %prog addtemplate <host_name> --template oracle
"""
parser = OptionParser(usage=usage)
parser.add_option("--debug", dest="debug", action="store_true",
    default=False,help="Print extra debugging information")
def parse_arguments():
    ''' Parse command line arguments and run command specified commands '''
    if len(sys.argv) < 2:
        parser.error("No command specified")
    elif sys.argv[1] == 'verify':
        verify()
    elif sys.argv[1] == 'addhost':
        addhost()
    elif sys.argv[1] == 'addgroup':
        addgroup()
    elif sys.argv[1] == 'addtemplate':
        addtemplate()
    elif sys.argv[1] == 'addcontact':
        addcontact()
    elif sys.argv[1] == "upgrade":
        upgrade()
    elif sys.argv[1] == "addservice":
        addservice()
    elif sys.argv[1] == "removehost":
        removehost()
    elif sys.argv[1] == "listtemplates":
        listtemplates()
    elif sys.argv[1] == "listhosts":
        listhosts()
    elif sys.argv[1] == "init":
        init()
    elif sys.argv[1] == "install":
        remote_install()
    elif sys.argv[1] == "help":
        parser.print_help()
    elif sys.argv[1] == "--help":
        parser.print_help()
    else:
        parser.error("Unknown command '%s'" % sys.argv[1])


def remote_install():
    ''' Install an ok agent on a remote server '''
    parser.usage = ''' %prog install <remote_server> [options]

Examples:
  # %prog install mylinuxserver --ssh --user root --password lol" 
  # %prog install mywinserver --winexe --user administrator --password lol --domain lol" 

Run %prog install --help for full list of command line arguments.
'''
    parser.add_option("--user", dest="user",
                      help="Username with admin privileges on remote box")
    parser.add_option("--password", dest="password",
                      help="Password to use to connect",default=None)
    parser.add_option("--domain", dest="domain",
                      help="Use this windows domain (works with --winexe)",default=None)
    parser.add_option("--ssh", dest="ssh", action="store_true",
                      default=False,help="Use ssh to connect")
    parser.add_option("--verbose", dest="verbose", action="store_true",
                      default=False,help="Show output of install script")
    parser.add_option("--winexe", dest="winexe", action="store_true",
                      default=False,help="use winexe to connect")
    parser.add_option("--host", dest="host", help="remote host to connect to")
    (opts,args) = parser.parse_args(sys.argv[2:])
    if opts.host: args.append(opts.host)

    if len(args) == 0: parser.error("Please specify at least one host on the command line.")    

    if opts.ssh:
        method = "ssh"
    elif opts.winexe:
        method = "winexe"
    else:
        method = None

    if not opts.password is None and opts.password.lower() == 'ask':
        opts.password = getpass.getpass("Password: ")

    if method == "winexe":
        if not opts.password or not opts.user:
            parser.error("winexe installation requires both username and password.")
        if not opts.domain:
            # local password database
            opts.domain = '.'

    for host in args:
        try:
            exit_status,stdout,stderr = okconfig.install_okagent(remote_host=host, domain=opts.domain, username=opts.user, password=opts.password, install_method=method)
        except okconfig.OKConfigError, e:
            exit_status=128
            stdout = "Exception occured while running install_okagent"
            stderr = str(e)
        if exit_status == 0:
            print "Install script on %s successful" % ( host )
        else:
            print "Install script on %s failed with exit_status %s" % (host, exit_status)
            print "Output:"
            print stdout
            print "Errors:"
            print stderr
        if opts.verbose:
            print "Script output:"
            print stdout



def verify():
    ''' Verify that current install of okconfig is functional. '''
    result = okconfig.verify()
    print "Okconfig verification"
    print "---------------------"
    for k,v in result.items():
        if v is True: v = "success"
        else: v = "fail"
        print "* %-70s...%s" % (k,v)

def init():
    ''' Initilize nagios configuration to use okconfig '''
    print "Initilizating nagios to use okconfig..."
    maincfg = okconfig.config.nagios_config
    template_dir = okconfig.config.template_directory
    dest_dir = okconfig.config.destination_directory
    print "Using configuration file %s" % (okconfig.config.config_file)
    if not os.path.exists(maincfg):
        raise okconfig.OKConfigError('Error: Nagios configuration file not found under %s' % (maincfg))
    print "Using Nagios configuration file %s" % (maincfg)

    import pynag.Parsers
    c = pynag.Parsers.config(cfg_file=maincfg)
    c._edit_static_file(attribute="cfg_dir", new_value=dest_dir, filename=maincfg)
    c._edit_static_file(attribute="cfg_dir", new_value=template_dir, filename=maincfg)
    if not os.path.exists(template_dir):
        print "Creating %s" % ( template_dir )
        os.makedirs(template_dir)
    if not os.path.exists(dest_dir):
        print "Creating %s" % ( dest_dir )
        os.makedirs(dest_dir)
    print 'All Done. Run "%s verify" to verify everything is working' % sys.argv[0]


def listhosts():
    """ List all available and active hosts in the system  """
    import pynag.Model
    hosts = pynag.Model.Host.objects.filter(register=1)
    header = "%-40s%s" % ('host name', 'groups')
    print header
    print "-"*len(header)
    for i in hosts:
        print "%-40s%s" % (i.host_name, i.hostgroups)
    footer = "--- %s hosts found" % (len(hosts))
    print footer,
    print "-"*(len(header)-len(footer))
def listtemplates():
    """ List all available oktemplates """
    for i in okconfig.get_templates():
        print i

def addgroup():
    ''' Add new group to current nagios configuration files '''
    parser.usage = ''' %prog addgroup <group_name> [options]

Examples:
  # %prog addgroup linuxservers --alias "My Linux Servers"

Run %prog addgroup --help for full list of command line arguments.
'''
    parser.add_option("--group", dest="group",
                      help="Name of group")
    parser.add_option("--force", dest="force", action="store_true",
                      default=False,help="Overwrite files if needed")
    parser.add_option("--alias", dest="alias", default=None,
                      help="Friendly name for this group")
    (opts,args) = parser.parse_args(sys.argv[2:])

    if opts.group: args.append(opts.group)

    if len(args) == 0: parser.error("Please specify at least one group on the command line.")    

    for group in args:
        f = okconfig.addgroup(group_name=group,alias=opts.alias,force=opts.force)
        for i in f: print "Saved", i

def addcontact():
    ''' Add new contact to current nagios configuration files '''
    parser.usage = ''' %prog addcontact <contact_name> [options]

Examples:
  # %prog addcontact "webmasters" --email "webmaster@example.com" 
  # %prog addcontact "admin" --email "admin@local" --alias "sysadmin group" 

Run %prog addcontact --help for full list of command line arguments.
'''
    parser.add_option("--contact", dest="contact", default=None,
                      help="contact_name")
    parser.add_option("--email", dest="email", default=None,
                      help="email for this contact")
    parser.add_option("--force", dest="force", action="store_true",
                      default=False,help="Overwrite files if needed")
    parser.add_option("--alias", dest="alias", default=None,
                      help="Friendly name for this contact")
    parser.add_option("--group", dest="group",
                      help="Put contact in the this contactgroup")

    (opts,args) = parser.parse_args(sys.argv[2:])

    if opts.contact: args.append(opts.contact)

    if len(args) == 0: parser.error("Please specify a contact on the command line. See --help.")
    for contact in args:
        f = okconfig.addcontact(contact_name=contact, alias=opts.alias, force=opts.force, group_name=opts.group, email=opts.email)
        for i in f: print "Saved", i


def addtemplate():
    ''' Add new template to a current nagios host '''
    parser.usage = ''' %prog addtemplate <host_name> <template_name>

Examples:
  # %prog addtemplate myhost.example.com --template linux
  # %prog addtemplate myhost.example.com --template brocade
  # %prog addtemplate myhost.example.com --template ciscoswitch

Run %prog addtemplate --help for full list of command line arguments.
'''
    parser.add_option("--host", dest="host",
                      help="Name of host to add")
    parser.add_option("--template", dest="template",
                      help="Name of template to use")
    parser.add_option("--force", dest="force", action="store_true",
                      default=False,help="Overwrite files if needed")
    (opts,args) = parser.parse_args(sys.argv[2:])

    if not opts.host:
        if len(args) > 0: opts.host = args[0]
    if not opts.template:
        if len(args) > 1: opts.template = args[1]
    if not opts.template or not opts.host:
        parser.error("Please specify both host and template. See --help")
    templates = opts.template.split(',')
    for template_name in templates:
        f = okconfig.addtemplate(host_name=opts.host,template_name=template_name,force=opts.force)
        for i in f: print "Saved", i

def addhost():
    ''' Add new host to nagios configuration files '''
    parser.usage = ''' %prog addhost <host_name> [options]

Examples:
  # %prog addhost switch1.example.com --template ciscoswitch --alias "My main switch"
  # %prog addhost www.example.com --template linux --group webservers
  # %prog addhost localhost2 --address 127.0.0.2 --alias "my other localhost"

Run %prog addhost --help for full list of command line arguments.
'''

    parser.add_option("--host", dest="host",
                      help="Name of host to add")
    parser.add_option("--group", dest="group",default="default",
                      help="Group this host belongs to",)
    parser.add_option("--template", dest="template",
                      help="Add specified templates to this host")
    parser.add_option("--force", dest="force", action="store_true",
                      default=False,help="Overwrite files if needed")
    parser.add_option("--use", dest="use", default=None,
                      help="Inherit settings from specified template")
    parser.add_option("--address", dest="address", default=None,
                      help="IP Address of host")
    parser.add_option("--alias", dest="alias", default=None,
                      help="Alias to use")
    parser.add_option("--host_template", dest="ht", default="host",
                      help="Name of host template to use")

    (opts,args) = parser.parse_args(sys.argv[2:])

    if opts.host: args.append(opts.host)

    if len(args) == 0: parser.error("Please specify at least one host on the command line.")

    try: templates = opts.template.split(',')
    except AttributeError: templates = ()
    for host in args:
        f = okconfig.addhost(host_name=host,address=opts.address,group_name=opts.group,
            use=opts.use,force=opts.force,templates=templates,host_template=opts.ht,alias=opts.alias)
        for i in f: print "Saved", i	

def upgrade():
    ''' Upgrade current nagios configuration in case okconfig tools have been updated '''
    import okconfig.migration_tool
    result = okconfig.migration_tool.upgrade_okconfig()

def addservice():
    ''' Add a single service check to host '''
    parser.usage = ''' %prog addservice [attribute1=value1] [attribute2=value2] ...

Examples:
  # %prog addservice host_name=myhost use=okc-windows-updates service_description="My service check" 

Run %prog addservice --help for full list of command line arguments.
'''
    parser.add_option("--filename", dest="file", default=None,
                      help="Save the new service to specified filename")

    (opts,args) = parser.parse_args(sys.argv[2:])
    service_attributes = {}
    for arg in args:
        if not arg.find('=') > 0:
            parser.error('Attribute not in the form of key=value: \n %s \n See --help')
        key,value = arg.split('=',1)
        service_attributes[key] = value
    from pynag import Model
    new_service = Model.Service(filename=opts.file)
    for k,v in service_attributes.items():
        new_service[k] = v
    new_service.save()
    print "# Saved: \n%s \n# To %s" % (new_service, new_service.get_filename())

def removehost():
    ''' Delete a host from current nagios configuration files '''
    parser.usage = ''' %prog removehost <host_name> [options]

Examples:
  # %prog removehost "host.example.com" --remove-services

Run %prog removehost --help for full list of command line arguments.
'''
    parser.add_option("--host", dest="host", default=None,
                      help="Host to be removed")
    parser.add_option("--remove-services", dest="recursive", action="store_true",
                      default=False,help="Also remove all services that belong to this host")

    (opts,args) = parser.parse_args(sys.argv[2:])

    if opts.host: args.append(opts.host)

    if len(args) == 0: parser.error("Please specify a host_name on the command line. See --help.")       
    for i in args:
        okconfig.removehost(host_name=i, recursive=opts.recursive)
        print "Host %s removed." % (i)


if __name__ == '__main__':
    try:
        parse_arguments()
    except Exception, e:
            print "Error: ", e

