summaryrefslogtreecommitdiffstats
path: root/agents/ovh/fence_ovh.py
blob: 2b7eb864fd90356b0f001e15e5bd593eb1407ac8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!@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()