#!/usr/bin/env python
# -*- coding: utf-8 -*-

# check_opsi is part of the desktop management solution opsi
# (open pc server integration) http://www.opsi.org

# Copyright (C) 2010-2016 uib GmbH

# http://www.uib.de/

# All rights reserved.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.

# This program 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, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
"""
check_opsi is a nagios plugin to check an opsi-server.

@copyright:  uib GmbH <info@uib.de>
@author: Erol Ueluekmen <e.ueluekmen@uib.de>
@license: GNU General Public License version 2
"""

import base64
import getopt
import json
import ssl as ssl_module
import sys
import types
from httplib import HTTPSConnection

__version__ = "4.0.7.1"

if hasattr(ssl_module, '_create_unverified_context'):
	# We are running a new version of Python that implements PEP 476:
	# https://www.python.org/dev/peps/pep-0476/
	# To not break our expected behaviour we patch the default context
	# until we have a correct certificate check implementation.
	# TODO: remove this workaround when support for TLS1.1+ is implemented
	ssl_module._create_default_https_context = ssl_module._create_unverified_context


def forceList(var):
	if not isinstance(var, (set, list, tuple, types.GeneratorType)):
		return [var]

	return list(var)


def generateParams(task, config={}):
	result = {
		"task": task,
		"param": {},
	}

	for key, value in config.items():
		result["param"][key] = value

	return json.dumps(result)


def analyseResonse(response):
	result = json.loads(response)
	print result.get("message", "")
	sys.exit(int(result.get("state", 3)))


def usage(possibleTasks):
	print "\n\nUsage: %s [OPTIONS]" % sys.argv[0]
	print ""
	print "Global Options:"
	print "================"
	print "-h, --help		show this help"
	print "-V, --version		show Version of plugin"
	print "-H, --host		opsiHost"
	print "-P, --port		opsi Webservice port"
	print "-u, --username		opsi Monitoring Username"
	print "-p, --password		opsi Monitoring Password"
	print ""
	print "Task to Check:"
	print "==============="
	print "-t, --task		check-method"
	print ""
	print "Possible Tasks: %s" % " | ".join(possibleTasks)
	print ""
	print "Check Options:"
	print "==============="
	print "-c, --clientId		opsi-client-Id"
	print "-e, --productIds	productIds (comma seperated)"
	print "-g, --groupIds		groupIds (comma seperated)"
	print "-G, --hostGroupIds	HostGroupIds (comma seperated)"
	print "-d, --depotIds		depotIds (comma seperated) or 'all'"
	print "-v, --verbose		generates verbose output"
	print "-T, --timeout           Timeout in sec for activechecks default 30sec"
	print "-s, --state             actual Service state ID (0, 1, 2 or 3)"
	print "-o, --output            actual Service output"
	print "-r, --resource		opsi-Resource to check"
	print "--plugin                plugin to check directly on the client"
	print "--strictmode            strictmode (checkOpsiDepotSyncStatus)"
	print ""
	print "Examples:"
	print "=========="
	print "checkClientStatus:"
	print "%s -H localhost -p 4447 -t checkClientStatus -c testclient.domain.local" % sys.argv[0]
	print ""


def executeCheck(config, data):
	try:
		conn = HTTPSConnection(config["opsiHost"], config["port"])
		headers = {}
		if config.get("user", None) and config.get("password", None):
			headers["Authorization"] = "Basic %s" % base64.b64encode('%s:%s' % (config["user"], config["password"]))
		conn.request("POST", "/monitoring", data, headers=headers)
		response = conn.getresponse()
		data = response.read()
		return data
	finally:
		conn.close()


def main():
	possibleTasks = [
		"checkClientStatus",
		"checkProductStatus",
		"checkDepotSyncStatus",
		"checkPluginOnClient",
		"checkOpsiWebservice",
		"checkOpsiDiskUsage",
	]

	try:
		opts, _ = getopt.getopt(
			sys.argv[1:],
			"hVvc:H:P:u:p:x:t:c:e:d:g:G:T:s:o:r:",
			[
				"help", "version", "opsiHost=", "port=", "username=",
				"password=", "excl=", "task=", "clientId=", "productIds=",
				"depotIds=", "groupIds=", "hostGroupIds=", "verbose",
				"timeout", "state", "plugin=", "output=", "resource=",
				"strictmode"
			]
		)
	except getopt.GetoptError as err:
		print str(err)
		usage(possibleTasks)
		sys.exit(3)

	config = {}
	for opt, arg in opts:
		if opt in ("-V", "--version"):
			print __version__
			sys.exit(0)
		elif opt in ("-h", "--help"):
			usage(possibleTasks)
			sys.exit(0)
		elif opt in ("-H", "--host"):
			config["opsiHost"] = str(arg)
		elif opt in ("-P", "--port"):
			config["port"] = str(arg)
		elif opt in ("-u", "--user"):
			config["user"] = str(arg)
		elif opt in ("-p", "--password"):
			config["password"] = str(arg)
		elif opt in ("-t", "--task"):
			config["task"] = str(arg)
		elif opt in ("-c", "--clientId"):
			config["clientId"] = str(arg)
		elif opt in ("-d", "--depotIds"):
			if "," in arg:
				arg = arg.split(",")
			config["depotIds"] = forceList(arg)
		elif opt in ("-g", "--groupIds"):
			if "," in arg:
				arg = arg.split(",")
			config["groupIds"] = forceList(arg)
		elif opt in ("-G", "--hostGroupIds"):
			if "," in arg:
				arg = arg.split(",")
			config["hostGroupIds"] = arg
		elif opt in ("-e", "--productId"):
			if "," in arg:
				arg = arg.split(",")
			config["productIds"] = forceList(arg)
		elif opt in ("-x", "--excl"):
			if "," in arg:
				arg = arg.split(",")
			config["exclude"] = forceList(arg)
		elif opt in ("-v", "--verbose"):
			config["verbose"] = True
		elif opt in ("-T", "--timeout"):
			config["timeout"] = arg
		elif opt in ("-s", "--state"):
			config["state"] = arg
		elif opt == "--plugin":
			config["plugin"] = arg
		elif opt in ("-o", "--output"):
			config["output"] = str(arg)
		elif opt in ("-r", "--resource"):
			config["resource"] = str(arg)
		elif opt == "--strictmode":
			config["strict"] = True
		else:
			raise Exception(u"UNKNOWN: Unhandled Options are given")

	if "opsiHost" not in config:
		raise Exception(u"opsiHost not definded, please supply via -H!")
	elif "port" not in config:
		raise Exception(u"port not definded, please supply via -p!")

	if "task" not in config:
		raise Exception(u"no task was set, nothing to do")
	else:
		if config["task"] in possibleTasks:
			data = generateParams(config["task"], config)
		else:
			raise Exception(u"UNKNOWN: unknown check: '%s'" % config["task"])

	if data:
		response = executeCheck(config, data)
		analyseResonse(response)


if __name__ == '__main__':
	try:
		main()
	except Exception as e:
		print u"UNKNOWN: Failure '%s'" % str(e)
		sys.exit(3)
