#!@PYTHON@ -tt # Copyright 2013 Adrian Gibanel Lopez (bTactic) # Adrian Gibanel improved this script at 2013 to add verification of success and to output metadata # Based on: # This is a fence agent for use at OVH # As there are no other fence devices available, we must use OVH's SOAP API #Quick-and-dirty # assemled by Dennis Busch, secofor GmbH, Germany # This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. import sys, time import shutil, tempfile import logging import atexit from datetime import datetime from suds.client import Client from suds.xsd.doctor import ImportDoctor, Import sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, fail_usage, EC_LOGIN_DENIED, run_delay OVH_RESCUE_PRO_NETBOOT_ID = '28' OVH_HARD_DISK_NETBOOT_ID = '1' STATUS_HARD_DISK_SLEEP = 240 # Wait 4 minutes to SO to boot STATUS_RESCUE_PRO_SLEEP = 150 # Wait 2 minutes 30 seconds to Rescue-Pro to run def define_new_opts(): all_opt["email"] = { "getopt" : "Z:", "longopt" : "email", "help" : "-Z, --email=[email] email for reboot message: admin@domain.com", "required" : "1", "shortdesc" : "Reboot email", "order" : 1} def netboot_reboot(conn, options, mode): # dedicatedNetbootModifyById changes the mode of the next reboot conn.service.dedicatedNetbootModifyById(options["session"], options["--plug"], mode, '', options["--email"]) # dedicatedHardRebootDo initiates a hard reboot on the given node conn.service.dedicatedHardRebootDo(options["session"], options["--plug"], 'Fencing initiated by cluster', '', 'en') conn.logout(options["session"]) def reboot_time(conn, options): result = conn.service.dedicatedHardRebootStatus(options["session"], options["--plug"]) tmpstart = datetime.strptime(result.start, '%Y-%m-%d %H:%M:%S') tmpend = datetime.strptime(result.end, '%Y-%m-%d %H:%M:%S') result.start = tmpstart result.end = tmpend return result def soap_login(options): imp = Import('http://schemas.xmlsoap.org/soap/encoding/') url = 'https://www.ovh.com/soapi/soapi-re-1.59.wsdl' imp.filter.add('http://soapi.ovh.com/manager') d = ImportDoctor(imp) tmp_dir = tempfile.mkdtemp() tempfile.tempdir = tmp_dir atexit.register(remove_tmp_dir, tmp_dir) try: soap = Client(url, doctor=d) session = soap.service.login(options["--username"], options["--password"], 'en', 0) except Exception as e: logging.error("Failed: {}".format(str(e))) fail(EC_LOGIN_DENIED) options["session"] = session return soap def remove_tmp_dir(tmp_dir): shutil.rmtree(tmp_dir) def main(): device_opt = ["login", "passwd", "port", "email", "no_status", "web"] atexit.register(atexit_handler) define_new_opts() options = check_input(device_opt, process_input(device_opt), other_conditions=True) docs = {} docs["shortdesc"] = "Fence agent for OVH" docs["longdesc"] = "fence_ovh is an Power Fencing agent \ which can be used within OVH datecentre. \ Poweroff is simulated with a reboot into rescue-pro mode." docs["vendorurl"] = "http://www.ovh.net" show_docs(options, docs) if options["--action"] == "list": fail_usage("Action 'list' is not supported in this fence agent") if options["--action"] == "list-status": fail_usage("Action 'list-status' is not supported in this fence agent") if "--email" not in options: fail_usage("You have to enter e-mail address which is notified by fence agent") if options["--action"] == "validate-all": sys.exit(0) if options["--action"] != "monitor" and not options["--plug"].endswith(".ovh.net"): options["--plug"] += ".ovh.net" run_delay(options) conn = soap_login(options) if options["--action"] == 'monitor': try: conn.service.logout(options["session"]) except Exception: pass sys.exit(0) # Save datetime just before changing netboot before_netboot_reboot = datetime.now() if options["--action"] == 'off': # Reboot in Rescue-pro netboot_reboot(conn, options, OVH_RESCUE_PRO_NETBOOT_ID) time.sleep(STATUS_RESCUE_PRO_SLEEP) elif options["--action"] in ['on', 'reboot']: # Reboot from HD netboot_reboot(conn, options, OVH_HARD_DISK_NETBOOT_ID) time.sleep(STATUS_HARD_DISK_SLEEP) # Save datetime just after reboot after_netboot_reboot = datetime.now() # Verify that action was completed sucesfully reboot_t = reboot_time(conn, options) logging.debug("reboot_start_end.start: %s\n", reboot_t.start.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("before_netboot_reboot: %s\n", before_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("reboot_start_end.end: %s\n", reboot_t.end.strftime('%Y-%m-%d %H:%M:%S')) logging.debug("after_netboot_reboot: %s\n", after_netboot_reboot.strftime('%Y-%m-%d %H:%M:%S')) if reboot_t.start < after_netboot_reboot < reboot_t.end: result = 0 logging.debug("Netboot reboot went OK.\n") else: result = 1 logging.debug("ERROR: Netboot reboot wasn't OK.\n") try: conn.service.logout(options["session"]) except Exception: pass sys.exit(result) if __name__ == "__main__": main()