import fence-agents-4.2.1-27.el8

This commit is contained in:
CentOS Sources 2019-08-06 15:18:43 -04:00 committed by Stepan Oksanichenko
commit 510d72e4ea
40 changed files with 4779 additions and 0 deletions

5
.fence-agents.metadata Normal file
View File

@ -0,0 +1,5 @@
0a56f6d9ed2014a363486d33b63eca094379be06 SOURCES/aliyun-python-sdk-core-2.13.1.tar.gz
c2a98b9a1562d223a76514f05028488ca000c395 SOURCES/aliyun-python-sdk-ecs-4.9.3.tar.gz
f14647a4d37a9a254c4e711b95a7654fc418e41e SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz
e2561df8e7ff9113dab118a651371dd88dab0142 SOURCES/fence-agents-4.2.1.tar.gz
326a73f58a62ebee00c11a12cfdd838b196e0e8e SOURCES/pycryptodome-3.6.4.tar.gz

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
SOURCES/aliyun-python-sdk-core-2.13.1.tar.gz
SOURCES/aliyun-python-sdk-ecs-4.9.3.tar.gz
SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz
SOURCES/fence-agents-4.2.1.tar.gz
SOURCES/pycryptodome-3.6.4.tar.gz

View File

@ -0,0 +1,12 @@
diff -uNr a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence_azure_arm.py
--- a/agents/azure_arm/fence_azure_arm.py 2018-06-28 14:24:54.000000000 +0200
+++ b/agents/azure_arm/fence_azure_arm.py 2019-01-15 10:24:16.030092206 +0100
@@ -7,6 +7,8 @@
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail_usage, run_command, run_delay
+
+sys.path.insert(0, '/usr/lib/fence-agents/bundled/azure')
import azure_fence
def get_nodes_list(clients, options):

View File

@ -0,0 +1,50 @@
From 342570c5a5af4c277be283507ef7898a078e2df9 Mon Sep 17 00:00:00 2001
From: mmartinv <32071463+mmartinv@users.noreply.github.com>
Date: Fri, 16 Nov 2018 12:55:58 +0100
Subject: [PATCH] Fix 'log_expect' in fence_hpblade.py
Update the 'log_expect' call to the new method definition.
---
agents/hpblade/fence_hpblade.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/agents/hpblade/fence_hpblade.py b/agents/hpblade/fence_hpblade.py
index b2cc94a3..fbc89f61 100644
--- a/agents/hpblade/fence_hpblade.py
+++ b/agents/hpblade/fence_hpblade.py
@@ -16,7 +16,7 @@
def get_enclosure_type(conn, options):
conn.send_eol("show enclosure info")
- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
type_re=re.compile(r"^\s*Enclosure Type: (\w+)(.*?)\s*$")
enclosure="unknown"
@@ -39,7 +39,7 @@ def get_power_status(conn, options):
powrestr = "^\\s*Power: (.*?)\\s*$"
conn.send_eol(cmd_send)
- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
power_re = re.compile(powrestr)
status = "unknown"
@@ -72,7 +72,7 @@ def set_power_status(conn, options):
conn.send_eol("poweron " + dev + options["--plug"])
elif options["--action"] == "off":
conn.send_eol("poweroff " + dev + options["--plug"] + " force")
- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
def get_instances_list(conn, options):
outlets = {}
@@ -84,7 +84,7 @@ def get_instances_list(conn, options):
listrestr = "^\\s*(\\d+)\\s+(.*?)\\s+(.*?)\\s+OK\\s+(.*?)\\s+(.*?)\\s*$"
conn.send_eol(cmd_send)
- conn.log_expect(options, options["--command-prompt"], int(options["--shell-timeout"]))
+ conn.log_expect(options["--command-prompt"], int(options["--shell-timeout"]))
list_re = re.compile(listrestr)
for line in conn.before.splitlines():

View File

@ -0,0 +1,24 @@
From f77297b654586bf539e78957f26cae1d22c6f081 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Fri, 2 Nov 2018 09:24:56 +0100
Subject: [PATCH] fence_scsi: fix incorrect SCSI key when node ID is 10 or
higher
The last four digits of the SCSI key will be zero padded digit between 0000-0009.
---
agents/scsi/fence_scsi.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py
index 2180d0c9..79ada4fa 100644
--- a/agents/scsi/fence_scsi.py
+++ b/agents/scsi/fence_scsi.py
@@ -191,7 +191,7 @@ def get_cluster_id(options):
def get_node_id(options):
cmd = options["--corosync-cmap-path"] + " nodelist"
- match = re.search(r".(\d).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"])
+ match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"])
return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist")

View File

@ -0,0 +1,41 @@
From 116fb7d1253ac31a8f174187dfe9f4a0c6546ade Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Fri, 7 Sep 2018 15:56:56 +0200
Subject: [PATCH] fence_vmware_soap: cleanup when receiving SIGTERM
---
agents/vmware_soap/fence_vmware_soap.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/agents/vmware_soap/fence_vmware_soap.py b/agents/vmware_soap/fence_vmware_soap.py
index b90edc9b..dd1a4ed6 100644
--- a/agents/vmware_soap/fence_vmware_soap.py
+++ b/agents/vmware_soap/fence_vmware_soap.py
@@ -3,7 +3,7 @@
import sys
import shutil, tempfile, suds
import logging, requests
-import atexit
+import atexit, signal
sys.path.append("@FENCEAGENTSLIBDIR@")
from suds.client import Client
@@ -211,6 +211,9 @@ def logout():
except Exception:
pass
+def signal_handler(signum, frame):
+ raise Exception("Signal \"%d\" received which has triggered an exit of the process." % signum)
+
def main():
global options_global
global conn_global
@@ -219,6 +222,8 @@ def main():
atexit.register(atexit_handler)
atexit.register(logout)
+ signal.signal(signal.SIGTERM, signal_handler)
+
options_global = check_input(device_opt, process_input(device_opt))
##

View File

@ -0,0 +1,146 @@
From 11a63822fbdc0a9ebe1b668b26a59f1cc9649f6c Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Wed, 24 Oct 2018 14:51:27 +0200
Subject: [PATCH] fence_scsi: watchdog retries support
---
agents/scsi/fence_scsi.py | 60 ++++++++++++++++++++----------
tests/data/metadata/fence_scsi.xml | 4 +-
2 files changed, 43 insertions(+), 21 deletions(-)
diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py
index 79ada4fa..8a1e4c77 100644
--- a/agents/scsi/fence_scsi.py
+++ b/agents/scsi/fence_scsi.py
@@ -158,13 +158,15 @@ def get_reservation_key(options, dev):
return match.group(1) if match else None
-def get_registration_keys(options, dev):
+def get_registration_keys(options, dev, fail=True):
reset_dev(options,dev)
keys = []
cmd = options["--sg_persist-path"] + " -n -i -k -d " + dev
out = run_cmd(options, cmd)
if out["err"]:
- fail_usage("Cannot get registration keys")
+ fail_usage("Cannot get registration keys", fail)
+ if not fail:
+ return []
for line in out["out"].split("\n"):
match = re.search(r"\s+0x(\S+)\s*", line)
if match:
@@ -218,9 +220,8 @@ def get_key(fail=True):
try:
f = open(file_path, "r")
except IOError:
- if fail:
- fail_usage("Failed: Cannot open file \""+ file_path + "\"")
- else:
+ fail_usage("Failed: Cannot open file \""+ file_path + "\"", fail)
+ if not fail:
return None
return f.readline().strip().lower()
@@ -244,9 +245,8 @@ def dev_read(fail=True):
try:
f = open(file_path, "r")
except IOError:
- if fail:
- fail_usage("Failed: Cannot open file \"" + file_path + "\"")
- else:
+ fail_usage("Failed: Cannot open file \"" + file_path + "\"", fail)
+ if not fail:
return None
# get not empty lines from file
devs = [line.strip() for line in f if line.strip()]
@@ -371,14 +371,20 @@ def define_new_opts():
}
-def scsi_check_get_verbose():
+def scsi_check_get_options(options):
try:
- f = open("/etc/sysconfig/watchdog", "r")
+ f = open("/etc/sysconfig/stonith", "r")
except IOError:
- return False
- match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE)
+ return options
+
+ match = re.findall(r"^\s*(\S*)\s*=\s*(\S*)\s*", "".join(f.readlines()), re.MULTILINE)
+
+ for m in match:
+ options[m[0].lower()] = m[1].lower()
+
f.close()
- return bool(match)
+
+ return options
def scsi_check(hardreboot=False):
@@ -388,7 +394,10 @@ def scsi_check(hardreboot=False):
options["--sg_turs-path"] = "@SG_TURS_PATH@"
options["--sg_persist-path"] = "@SG_PERSIST_PATH@"
options["--power-timeout"] = "5"
- if scsi_check_get_verbose():
+ options["retry"] = "0"
+ options["retry-sleep"] = "1"
+ options = scsi_check_get_options(options)
+ if "verbose" in options and options["verbose"] == "yes":
logging.getLogger().setLevel(logging.DEBUG)
devs = dev_read(fail=False)
if not devs:
@@ -399,11 +408,18 @@ def scsi_check(hardreboot=False):
logging.error("Key not found")
return 0
for dev in devs:
- if key in get_registration_keys(options, dev):
- logging.debug("key " + key + " registered with device " + dev)
- return 0
- else:
- logging.debug("key " + key + " not registered with device " + dev)
+ for n in range(int(options["retry"]) + 1):
+ if n > 0:
+ logging.debug("retry: " + str(n) + " of " + options["retry"])
+ if key in get_registration_keys(options, dev, fail=False):
+ logging.debug("key " + key + " registered with device " + dev)
+ return 0
+ else:
+ logging.debug("key " + key + " not registered with device " + dev)
+
+ if n < int(options["retry"]):
+ time.sleep(float(options["retry-sleep"]))
+
logging.debug("key " + key + " registered with any devices")
if hardreboot == True:
@@ -452,7 +468,11 @@ def main():
device(s). The result is that only registered nodes may write to the \
device(s). When a node failure occurs, the fence_scsi agent will remove the \
key belonging to the failed node from the device(s). The failed node will no \
-longer be able to write to the device(s). A manual reboot is required."
+longer be able to write to the device(s). A manual reboot is required.\
+\n.P\n\
+When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and \
+verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it \
+failing."
docs["vendorurl"] = ""
show_docs(options, docs)
diff --git a/tests/data/metadata/fence_scsi.xml b/tests/data/metadata/fence_scsi.xml
index 45a84168..b8cdabd1 100644
--- a/tests/data/metadata/fence_scsi.xml
+++ b/tests/data/metadata/fence_scsi.xml
@@ -1,7 +1,9 @@
<?xml version="1.0" ?>
<resource-agent name="fence_scsi" shortdesc="Fence agent for SCSI persistent reservation" >
<longdesc>fence_scsi is an I/O fencing agent that uses SCSI-3 persistent reservations to control access to shared storage devices. These devices must support SCSI-3 persistent reservations (SPC-3 or greater) as well as the "preempt-and-abort" subcommand.
-The fence_scsi agent works by having each node in the cluster register a unique key with the SCSI device(s). Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_scsi agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required.</longdesc>
+The fence_scsi agent works by having each node in the cluster register a unique key with the SCSI device(s). Once registered, a single node will become the reservation holder by creating a "write exclusive, registrants only" reservation on the device(s). The result is that only registered nodes may write to the device(s). When a node failure occurs, the fence_scsi agent will remove the key belonging to the failed node from the device(s). The failed node will no longer be able to write to the device(s). A manual reboot is required.
+
+When used as a watchdog device you can define e.g. retry=1, retry-sleep=2 and verbose=yes parameters in /etc/sysconfig/stonith if you have issues with it failing.</longdesc>
<vendor-url></vendor-url>
<parameters>
<parameter name="action" unique="0" required="1">

View File

@ -0,0 +1,23 @@
From 267afc5caa0580cc483220e671cda094413a4e16 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Wed, 28 Nov 2018 09:54:16 +0100
Subject: [PATCH] build: fix if-redirection to make check_used_options run for
the agents as intended
---
make/fencebuild.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/make/fencebuild.mk b/make/fencebuild.mk
index 9e8bd692..143082f0 100644
--- a/make/fencebuild.mk
+++ b/make/fencebuild.mk
@@ -33,7 +33,7 @@ define gen_agent_from_py
-e 's#@''PING4_CMD@#${PING4_CMD}#g' \
> $@
- if [ 0 -eq `echo "$(@)" | grep fence_ 2>&1 /dev/null; echo $$?` ]; then \
+ if [ 0 -eq `echo "$(@)" | grep fence_ > /dev/null 2>&1; echo $$?` ]; then \
PYTHONPATH=$(abs_top_srcdir)/lib:$(abs_top_builddir)/lib $(PYTHON) $(top_srcdir)/lib/check_used_options.py $@; \
else true ; fi

View File

@ -0,0 +1,812 @@
From 64e3f3ef4d0abefd2836fe015c87173310b1e130 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Mon, 3 Dec 2018 10:11:15 -0600
Subject: [PATCH 1/8] Add new fence agent for Redfish
- Agent works on all fence devices that implement the Redfish API specification
- Agent programatically finds the Systems Resouce URI if it's not provided
---
agents/redfish/fence_redfish.py | 151 +++++++++++++++++++++
tests/data/metadata/fence_redfish.xml | 181 ++++++++++++++++++++++++++
2 files changed, 332 insertions(+)
create mode 100644 agents/redfish/fence_redfish.py
create mode 100644 tests/data/metadata/fence_redfish.xml
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
new file mode 100644
index 00000000..df7cf8c2
--- /dev/null
+++ b/agents/redfish/fence_redfish.py
@@ -0,0 +1,151 @@
+#!@PYTHON@ -tt
+
+# Copyright (c) 2018 Dell Inc. or its subsidiaries. All Rights Reserved.
+
+# Fence agent for devices that support the Redfish API Specification.
+
+import sys
+import re
+import json
+import requests
+import atexit
+sys.path.append("@FENCEAGENTSLIBDIR@")
+
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
+from fencing import *
+from fencing import fail_usage
+
+def get_power_status(conn, options):
+ uri = options["--systems-uri"]
+ response = send_get_request(options, uri)
+ if response['ret'] is False:
+ fail_usage("Couldn't get power information")
+ data = response['data']
+ if data[u'PowerState'].strip() == "On":
+ return "on"
+ else:
+ return "off"
+
+def set_power_status(conn, options):
+ action = {
+ 'on' : "On",
+ 'off': "ForceOff",
+ 'reboot': "GracefulRestart"
+ }[options["--action"]]
+
+ payload = {'ResetType': action}
+ headers = {'content-type': 'application/json'}
+
+ # Search for 'Actions' key and extract URI from it
+ uri = options["--systems-uri"]
+ response = send_get_request(options, uri)
+ if response['ret'] is False:
+ return {'ret': False}
+ data = response['data']
+ uri = data["Actions"]["#ComputerSystem.Reset"]["target"]
+
+ response = send_post_request(options, uri, payload, headers)
+ if response['ret'] is False:
+ fail_usage("Error sending power command")
+ return
+
+def send_get_request(options, uri):
+ full_uri = "https://" + options["--ip"] + uri
+ try:
+ resp = requests.get(full_uri, verify=False,
+ auth=(options["--username"], options["--password"]))
+ data = resp.json()
+ except:
+ return {'ret': False}
+ return {'ret': True, 'data': data}
+
+def send_post_request(options, uri, payload, headers):
+ full_uri = "https://" + options["--ip"] + uri
+ try:
+ requests.post(full_uri, data=json.dumps(payload),
+ headers=headers, verify=False,
+ auth=(options["--username"], options["--password"]))
+ except:
+ return {'ret': False}
+ return {'ret': True}
+
+def find_systems_resource(options):
+ uri = options["--redfish-uri"]
+ response = send_get_request(options, uri)
+ if response['ret'] is False:
+ return {'ret': False}
+ data = response['data']
+
+ if 'Systems' not in data:
+ # Systems resource not found"
+ return {'ret': False}
+ else:
+ uri = data["Systems"]["@odata.id"]
+ response = send_get_request(options, uri)
+ if response['ret'] is False:
+ return {'ret': False}
+ data = response['data']
+
+ # need to be able to handle more than one entry
+ for member in data[u'Members']:
+ system_uri = member[u'@odata.id']
+ return {'ret': True, 'uri': system_uri}
+
+def define_new_opts():
+ all_opt["redfish-uri"] = {
+ "getopt" : ":",
+ "longopt" : "redfish-uri",
+ "help" : "--redfish-uri=[uri] Base or starting Redifsh URI",
+ "required" : "0",
+ "default" : "/redfish/v1",
+ "shortdesc" : "Base or starting Redfish URI",
+ "order": 1
+ }
+ all_opt["systems-uri"] = {
+ "getopt" : ":",
+ "longopt" : "systems-uri",
+ "help" : "--systems-uri=[uri] Redfish Systems resource URI",
+ "required" : "0",
+ "shortdesc" : "Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1",
+ "order": 1
+ }
+
+def main():
+ atexit.register(atexit_handler)
+ device_opt = ["ipaddr", "login", "passwd", "redfish-uri", "systems-uri", "ssl"]
+ define_new_opts()
+
+ opt = process_input(device_opt)
+
+ all_opt["ipport"]["default"] = "443"
+ options = check_input(device_opt, opt)
+
+ docs = {}
+ docs["shortdesc"] = "I/O Fencing agent for Redfish"
+ docs["longdesc"] = "fence_redfish is an I/O Fencing agent which can be used with \
+Out-of-Band controllers that support Redfish APIs. These controllers provide remote \
+access to control power on a server."
+ docs["vendorurl"] = "http://www.dmtf.org"
+ show_docs(options, docs)
+
+ ##
+ ## Operate the fencing device
+ ####
+
+ # Disable insecure-certificate-warning message
+ if "--ssl-insecure" in opt:
+ requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+
+ if "--systems-uri" not in opt:
+ # Systems URI not provided, find it
+ sysresult = find_systems_resource(options)
+ if sysresult['ret'] is False:
+ sys.exit(1)
+ else:
+ options["--systems-uri"] = sysresult["uri"]
+
+ result = fence_action(None, options, set_power_status, get_power_status, None)
+ sys.exit(result)
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml
new file mode 100644
index 00000000..43d447d0
--- /dev/null
+++ b/tests/data/metadata/fence_redfish.xml
@@ -0,0 +1,181 @@
+<?xml version="1.0" ?>
+<resource-agent name="fence_redfish" shortdesc="I/O Fencing agent for Redfish" >
+<longdesc>fence_redfish is an I/O Fencing agent which can be used with Out-of-Band controllers that support Redfish APIs. These controllers provide remote access to control power on a server.</longdesc>
+<vendor-url>http://www.dmtf.org</vendor-url>
+<parameters>
+ <parameter name="ipport" unique="0" required="0">
+ <getopt mixed="-u, --ipport=[port]" />
+ <content type="integer" default="443" />
+ <shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
+ </parameter>
+ <parameter name="ssl_secure" unique="0" required="0">
+ <getopt mixed="--ssl-secure" />
+ <content type="boolean" />
+ <shortdesc lang="en">SSL connection with verifying fence device's certificate</shortdesc>
+ </parameter>
+ <parameter name="systems-uri" unique="0" required="0" deprecated="1">
+ <getopt mixed="--systems-uri=[uri]" />
+ <content type="string" />
+ <shortdesc lang="en">Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1</shortdesc>
+ </parameter>
+ <parameter name="action" unique="0" required="1">
+ <getopt mixed="-o, --action=[action]" />
+ <content type="string" default="reboot" />
+ <shortdesc lang="en">Fencing Action</shortdesc>
+ </parameter>
+ <parameter name="inet6_only" unique="0" required="0">
+ <getopt mixed="-6, --inet6-only" />
+ <content type="boolean" />
+ <shortdesc lang="en">Forces agent to use IPv6 addresses only</shortdesc>
+ </parameter>
+ <parameter name="ipaddr" unique="0" required="0" deprecated="1">
+ <getopt mixed="-a, --ip=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP Address or Hostname</shortdesc>
+ </parameter>
+ <parameter name="port" unique="0" required="0" deprecated="1">
+ <getopt mixed="-n, --plug=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP address or hostname of fencing device (together with --port-as-ip)</shortdesc>
+ </parameter>
+ <parameter name="passwd_script" unique="0" required="0" deprecated="1">
+ <getopt mixed="-S, --password-script=[script]" />
+ <content type="string" />
+ <shortdesc lang="en">Script to retrieve password</shortdesc>
+ </parameter>
+ <parameter name="inet4_only" unique="0" required="0">
+ <getopt mixed="-4, --inet4-only" />
+ <content type="boolean" />
+ <shortdesc lang="en">Forces agent to use IPv4 addresses only</shortdesc>
+ </parameter>
+ <parameter name="passwd" unique="0" required="0" deprecated="1">
+ <getopt mixed="-p, --password=[password]" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
+ </parameter>
+ <parameter name="ssl" unique="0" required="0">
+ <getopt mixed="-z, --ssl" />
+ <content type="boolean" />
+ <shortdesc lang="en">SSL connection</shortdesc>
+ </parameter>
+ <parameter name="redfish-uri" unique="0" required="0" deprecated="1">
+ <getopt mixed="--redfish-uri=[uri]" />
+ <content type="string" default="/redfish/v1" />
+ <shortdesc lang="en">Base or starting Redfish URI</shortdesc>
+ </parameter>
+ <parameter name="ssl_insecure" unique="0" required="0">
+ <getopt mixed="--ssl-insecure" />
+ <content type="boolean" />
+ <shortdesc lang="en">SSL connection without verifying fence device's certificate</shortdesc>
+ </parameter>
+ <parameter name="login" unique="0" required="1" deprecated="1">
+ <getopt mixed="-l, --username=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Login Name</shortdesc>
+ </parameter>
+ <parameter name="plug" unique="0" required="0" obsoletes="port">
+ <getopt mixed="-n, --plug=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP address or hostname of fencing device (together with --port-as-ip)</shortdesc>
+ </parameter>
+ <parameter name="username" unique="0" required="1" obsoletes="login">
+ <getopt mixed="-l, --username=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Login Name</shortdesc>
+ </parameter>
+ <parameter name="redfish_uri" unique="0" required="0" obsoletes="redfish-uri">
+ <getopt mixed="--redfish-uri=[uri]" />
+ <content type="string" default="/redfish/v1" />
+ <shortdesc lang="en">Base or starting Redfish URI</shortdesc>
+ </parameter>
+ <parameter name="ip" unique="0" required="0" obsoletes="ipaddr">
+ <getopt mixed="-a, --ip=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP Address or Hostname</shortdesc>
+ </parameter>
+ <parameter name="systems_uri" unique="0" required="0" obsoletes="systems-uri">
+ <getopt mixed="--systems-uri=[uri]" />
+ <content type="string" />
+ <shortdesc lang="en">Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1</shortdesc>
+ </parameter>
+ <parameter name="password" unique="0" required="0" obsoletes="passwd">
+ <getopt mixed="-p, --password=[password]" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
+ </parameter>
+ <parameter name="password_script" unique="0" required="0" obsoletes="passwd_script">
+ <getopt mixed="-S, --password-script=[script]" />
+ <content type="string" />
+ <shortdesc lang="en">Script to retrieve password</shortdesc>
+ </parameter>
+ <parameter name="verbose" unique="0" required="0">
+ <getopt mixed="-v, --verbose" />
+ <content type="boolean" />
+ <shortdesc lang="en">Verbose mode</shortdesc>
+ </parameter>
+ <parameter name="debug" unique="0" required="0" deprecated="1">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <content type="string" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="debug_file" unique="0" required="0" obsoletes="debug">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <content type="string" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="version" unique="0" required="0">
+ <getopt mixed="-V, --version" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display version information and exit</shortdesc>
+ </parameter>
+ <parameter name="help" unique="0" required="0">
+ <getopt mixed="-h, --help" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display help and exit</shortdesc>
+ </parameter>
+ <parameter name="power_wait" unique="0" required="0">
+ <getopt mixed="--power-wait=[seconds]" />
+ <content type="second" default="0" />
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="login_timeout" unique="0" required="0">
+ <getopt mixed="--login-timeout=[seconds]" />
+ <content type="second" default="5" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
+ </parameter>
+ <parameter name="power_timeout" unique="0" required="0">
+ <getopt mixed="--power-timeout=[seconds]" />
+ <content type="second" default="20" />
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="delay" unique="0" required="0">
+ <getopt mixed="--delay=[seconds]" />
+ <content type="second" default="0" />
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
+ </parameter>
+ <parameter name="shell_timeout" unique="0" required="0">
+ <getopt mixed="--shell-timeout=[seconds]" />
+ <content type="second" default="3" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
+ </parameter>
+ <parameter name="port_as_ip" unique="0" required="0">
+ <getopt mixed="--port-as-ip" />
+ <content type="boolean" />
+ <shortdesc lang="en">Make "port/plug" to be an alias to IP address</shortdesc>
+ </parameter>
+ <parameter name="retry_on" unique="0" required="0">
+ <getopt mixed="--retry-on=[attempts]" />
+ <content type="integer" default="1" />
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
+ </parameter>
+</parameters>
+<actions>
+ <action name="on" automatic="0"/>
+ <action name="off" />
+ <action name="reboot" />
+ <action name="status" />
+ <action name="monitor" />
+ <action name="metadata" />
+ <action name="validate-all" />
+</actions>
+</resource-agent>
From 6921a34d64d098a7b1f32205e0be434438c36898 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Mon, 3 Dec 2018 10:46:52 -0600
Subject: [PATCH 2/8] Updated fence_redfish.xml with make xml-upload
---
tests/data/metadata/fence_redfish.xml | 148 ++++++++++++++------------
1 file changed, 79 insertions(+), 69 deletions(-)
diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml
index 43d447d0..a39541e6 100644
--- a/tests/data/metadata/fence_redfish.xml
+++ b/tests/data/metadata/fence_redfish.xml
@@ -3,110 +3,115 @@
<longdesc>fence_redfish is an I/O Fencing agent which can be used with Out-of-Band controllers that support Redfish APIs. These controllers provide remote access to control power on a server.</longdesc>
<vendor-url>http://www.dmtf.org</vendor-url>
<parameters>
- <parameter name="ipport" unique="0" required="0">
- <getopt mixed="-u, --ipport=[port]" />
- <content type="integer" default="443" />
- <shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
- </parameter>
- <parameter name="ssl_secure" unique="0" required="0">
- <getopt mixed="--ssl-secure" />
- <content type="boolean" />
- <shortdesc lang="en">SSL connection with verifying fence device's certificate</shortdesc>
- </parameter>
- <parameter name="systems-uri" unique="0" required="0" deprecated="1">
- <getopt mixed="--systems-uri=[uri]" />
- <content type="string" />
- <shortdesc lang="en">Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1</shortdesc>
- </parameter>
<parameter name="action" unique="0" required="1">
<getopt mixed="-o, --action=[action]" />
<content type="string" default="reboot" />
- <shortdesc lang="en">Fencing Action</shortdesc>
+ <shortdesc lang="en">Fencing action</shortdesc>
+ </parameter>
+ <parameter name="inet4_only" unique="0" required="0">
+ <getopt mixed="-4, --inet4-only" />
+ <content type="boolean" />
+ <shortdesc lang="en">Forces agent to use IPv4 addresses only</shortdesc>
</parameter>
<parameter name="inet6_only" unique="0" required="0">
<getopt mixed="-6, --inet6-only" />
<content type="boolean" />
<shortdesc lang="en">Forces agent to use IPv6 addresses only</shortdesc>
</parameter>
- <parameter name="ipaddr" unique="0" required="0" deprecated="1">
+ <parameter name="ip" unique="0" required="0" obsoletes="ipaddr">
<getopt mixed="-a, --ip=[ip]" />
<content type="string" />
- <shortdesc lang="en">IP Address or Hostname</shortdesc>
+ <shortdesc lang="en">IP address or hostname of fencing device</shortdesc>
</parameter>
- <parameter name="port" unique="0" required="0" deprecated="1">
- <getopt mixed="-n, --plug=[ip]" />
+ <parameter name="ipaddr" unique="0" required="0" deprecated="1">
+ <getopt mixed="-a, --ip=[ip]" />
<content type="string" />
- <shortdesc lang="en">IP address or hostname of fencing device (together with --port-as-ip)</shortdesc>
+ <shortdesc lang="en">IP address or hostname of fencing device</shortdesc>
</parameter>
- <parameter name="passwd_script" unique="0" required="0" deprecated="1">
- <getopt mixed="-S, --password-script=[script]" />
- <content type="string" />
- <shortdesc lang="en">Script to retrieve password</shortdesc>
+ <parameter name="ipport" unique="0" required="0">
+ <getopt mixed="-u, --ipport=[port]" />
+ <content type="integer" default="443" />
+ <shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
</parameter>
- <parameter name="inet4_only" unique="0" required="0">
- <getopt mixed="-4, --inet4-only" />
- <content type="boolean" />
- <shortdesc lang="en">Forces agent to use IPv4 addresses only</shortdesc>
+ <parameter name="login" unique="0" required="1" deprecated="1">
+ <getopt mixed="-l, --username=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Login name</shortdesc>
</parameter>
<parameter name="passwd" unique="0" required="0" deprecated="1">
<getopt mixed="-p, --password=[password]" />
<content type="string" />
<shortdesc lang="en">Login password or passphrase</shortdesc>
</parameter>
- <parameter name="ssl" unique="0" required="0">
- <getopt mixed="-z, --ssl" />
- <content type="boolean" />
- <shortdesc lang="en">SSL connection</shortdesc>
- </parameter>
- <parameter name="redfish-uri" unique="0" required="0" deprecated="1">
- <getopt mixed="--redfish-uri=[uri]" />
- <content type="string" default="/redfish/v1" />
- <shortdesc lang="en">Base or starting Redfish URI</shortdesc>
+ <parameter name="passwd_script" unique="0" required="0" deprecated="1">
+ <getopt mixed="-S, --password-script=[script]" />
+ <content type="string" />
+ <shortdesc lang="en">Script to run to retrieve password</shortdesc>
</parameter>
- <parameter name="ssl_insecure" unique="0" required="0">
- <getopt mixed="--ssl-insecure" />
- <content type="boolean" />
- <shortdesc lang="en">SSL connection without verifying fence device's certificate</shortdesc>
+ <parameter name="password" unique="0" required="0" obsoletes="passwd">
+ <getopt mixed="-p, --password=[password]" />
+ <content type="string" />
+ <shortdesc lang="en">Login password or passphrase</shortdesc>
</parameter>
- <parameter name="login" unique="0" required="1" deprecated="1">
- <getopt mixed="-l, --username=[name]" />
+ <parameter name="password_script" unique="0" required="0" obsoletes="passwd_script">
+ <getopt mixed="-S, --password-script=[script]" />
<content type="string" />
- <shortdesc lang="en">Login Name</shortdesc>
+ <shortdesc lang="en">Script to run to retrieve password</shortdesc>
</parameter>
<parameter name="plug" unique="0" required="0" obsoletes="port">
<getopt mixed="-n, --plug=[ip]" />
<content type="string" />
<shortdesc lang="en">IP address or hostname of fencing device (together with --port-as-ip)</shortdesc>
</parameter>
- <parameter name="username" unique="0" required="1" obsoletes="login">
- <getopt mixed="-l, --username=[name]" />
+ <parameter name="port" unique="0" required="0" deprecated="1">
+ <getopt mixed="-n, --plug=[ip]" />
<content type="string" />
- <shortdesc lang="en">Login Name</shortdesc>
+ <shortdesc lang="en">IP address or hostname of fencing device (together with --port-as-ip)</shortdesc>
+ </parameter>
+ <parameter name="redfish-uri" unique="0" required="0" deprecated="1">
+ <getopt mixed="--redfish-uri=[uri]" />
+ <content type="string" default="/redfish/v1" />
+ <shortdesc lang="en">Base or starting Redfish URI</shortdesc>
</parameter>
<parameter name="redfish_uri" unique="0" required="0" obsoletes="redfish-uri">
<getopt mixed="--redfish-uri=[uri]" />
<content type="string" default="/redfish/v1" />
<shortdesc lang="en">Base or starting Redfish URI</shortdesc>
</parameter>
- <parameter name="ip" unique="0" required="0" obsoletes="ipaddr">
- <getopt mixed="-a, --ip=[ip]" />
+ <parameter name="ssl" unique="0" required="0">
+ <getopt mixed="-z, --ssl" />
+ <content type="boolean" />
+ <shortdesc lang="en">Use SSL connection with verifying certificate</shortdesc>
+ </parameter>
+ <parameter name="ssl_insecure" unique="0" required="0">
+ <getopt mixed="--ssl-insecure" />
+ <content type="boolean" />
+ <shortdesc lang="en">Use SSL connection without verifying certificate</shortdesc>
+ </parameter>
+ <parameter name="ssl_secure" unique="0" required="0">
+ <getopt mixed="--ssl-secure" />
+ <content type="boolean" />
+ <shortdesc lang="en">Use SSL connection with verifying certificate</shortdesc>
+ </parameter>
+ <parameter name="systems-uri" unique="0" required="0" deprecated="1">
+ <getopt mixed="--systems-uri=[uri]" />
<content type="string" />
- <shortdesc lang="en">IP Address or Hostname</shortdesc>
+ <shortdesc lang="en">Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1</shortdesc>
</parameter>
<parameter name="systems_uri" unique="0" required="0" obsoletes="systems-uri">
<getopt mixed="--systems-uri=[uri]" />
<content type="string" />
<shortdesc lang="en">Redfish Systems resource URI, i.e. /redfish/v1/Systems/System.Embedded.1</shortdesc>
</parameter>
- <parameter name="password" unique="0" required="0" obsoletes="passwd">
- <getopt mixed="-p, --password=[password]" />
+ <parameter name="username" unique="0" required="1" obsoletes="login">
+ <getopt mixed="-l, --username=[name]" />
<content type="string" />
- <shortdesc lang="en">Login password or passphrase</shortdesc>
+ <shortdesc lang="en">Login name</shortdesc>
</parameter>
- <parameter name="password_script" unique="0" required="0" obsoletes="passwd_script">
- <getopt mixed="-S, --password-script=[script]" />
- <content type="string" />
- <shortdesc lang="en">Script to retrieve password</shortdesc>
+ <parameter name="quiet" unique="0" required="0">
+ <getopt mixed="-q, --quiet" />
+ <content type="boolean" />
+ <shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc>
</parameter>
<parameter name="verbose" unique="0" required="0">
<getopt mixed="-v, --verbose" />
@@ -133,41 +138,45 @@
<content type="boolean" />
<shortdesc lang="en">Display help and exit</shortdesc>
</parameter>
- <parameter name="power_wait" unique="0" required="0">
- <getopt mixed="--power-wait=[seconds]" />
+ <parameter name="delay" unique="0" required="0">
+ <getopt mixed="--delay=[seconds]" />
<content type="second" default="0" />
- <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
</parameter>
<parameter name="login_timeout" unique="0" required="0">
<getopt mixed="--login-timeout=[seconds]" />
<content type="second" default="5" />
<shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
</parameter>
+ <parameter name="port_as_ip" unique="0" required="0">
+ <getopt mixed="--port-as-ip" />
+ <content type="boolean" />
+ <shortdesc lang="en">Make "port/plug" to be an alias to IP address</shortdesc>
+ </parameter>
<parameter name="power_timeout" unique="0" required="0">
<getopt mixed="--power-timeout=[seconds]" />
<content type="second" default="20" />
<shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
</parameter>
- <parameter name="delay" unique="0" required="0">
- <getopt mixed="--delay=[seconds]" />
+ <parameter name="power_wait" unique="0" required="0">
+ <getopt mixed="--power-wait=[seconds]" />
<content type="second" default="0" />
- <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
</parameter>
<parameter name="shell_timeout" unique="0" required="0">
<getopt mixed="--shell-timeout=[seconds]" />
<content type="second" default="3" />
<shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
</parameter>
- <parameter name="port_as_ip" unique="0" required="0">
- <getopt mixed="--port-as-ip" />
- <content type="boolean" />
- <shortdesc lang="en">Make "port/plug" to be an alias to IP address</shortdesc>
- </parameter>
<parameter name="retry_on" unique="0" required="0">
<getopt mixed="--retry-on=[attempts]" />
<content type="integer" default="1" />
<shortdesc lang="en">Count of attempts to retry power on</shortdesc>
</parameter>
+ <parameter name="gnutlscli_path" unique="0" required="0">
+ <getopt mixed="--gnutlscli-path=[path]" />
+ <shortdesc lang="en">Path to gnutls-cli binary</shortdesc>
+ </parameter>
</parameters>
<actions>
<action name="on" automatic="0"/>
@@ -176,6 +185,7 @@
<action name="status" />
<action name="monitor" />
<action name="metadata" />
+ <action name="manpage" />
<action name="validate-all" />
</actions>
</resource-agent>
From 755627fadd711848ea256d72f5e75f36f83b4d31 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Mon, 3 Dec 2018 11:55:23 -0600
Subject: [PATCH 3/8] Added run_delay()
---
agents/redfish/fence_redfish.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index df7cf8c2..0e4a4f68 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -13,7 +13,7 @@
from requests.packages.urllib3.exceptions import InsecureRequestWarning
from fencing import *
-from fencing import fail_usage
+from fencing import fail_usage, run_delay
def get_power_status(conn, options):
uri = options["--systems-uri"]
@@ -127,6 +127,7 @@ def main():
access to control power on a server."
docs["vendorurl"] = "http://www.dmtf.org"
show_docs(options, docs)
+ run_delay(options)
##
## Operate the fencing device
From 15fef4c47f391a3f03c714d86c9670ea209dec99 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Tue, 4 Dec 2018 10:56:58 -0600
Subject: [PATCH 4/8] Modify power status check
- Only returns off if PowerState = Off
- Otherwise returns on
---
agents/redfish/fence_redfish.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 0e4a4f68..7998fb1c 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -21,10 +21,10 @@ def get_power_status(conn, options):
if response['ret'] is False:
fail_usage("Couldn't get power information")
data = response['data']
- if data[u'PowerState'].strip() == "On":
- return "on"
- else:
+ if data[u'PowerState'].strip() == "Off":
return "off"
+ else:
+ return "on"
def set_power_status(conn, options):
action = {
From acf70f4672be65562841227ab0b4cacb87965f44 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Wed, 5 Dec 2018 10:39:32 -0600
Subject: [PATCH 5/8] Changed reboot type to ForceRestart
---
agents/redfish/fence_redfish.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 7998fb1c..3fe2bfc0 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -30,7 +30,7 @@ def set_power_status(conn, options):
action = {
'on' : "On",
'off': "ForceOff",
- 'reboot': "GracefulRestart"
+ 'reboot': "ForceRestart"
}[options["--action"]]
payload = {'ResetType': action}
From 56e3358d45050ac669c099c56873feefa1ecda38 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Wed, 5 Dec 2018 10:54:44 -0600
Subject: [PATCH 6/8] Replaced default port 443 with default ssl enabled option
---
agents/redfish/fence_redfish.py | 2 +-
tests/data/metadata/fence_redfish.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 3fe2bfc0..6a2dbb76 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -117,7 +117,7 @@ def main():
opt = process_input(device_opt)
- all_opt["ipport"]["default"] = "443"
+ all_opt["ssl"]["default"] = "1"
options = check_input(device_opt, opt)
docs = {}
diff --git a/tests/data/metadata/fence_redfish.xml b/tests/data/metadata/fence_redfish.xml
index a39541e6..e1c18584 100644
--- a/tests/data/metadata/fence_redfish.xml
+++ b/tests/data/metadata/fence_redfish.xml
@@ -80,7 +80,7 @@
</parameter>
<parameter name="ssl" unique="0" required="0">
<getopt mixed="-z, --ssl" />
- <content type="boolean" />
+ <content type="boolean" default="1" />
<shortdesc lang="en">Use SSL connection with verifying certificate</shortdesc>
</parameter>
<parameter name="ssl_insecure" unique="0" required="0">
From 5c25a85b22a17d6bbc3dcb47c99b76e3a99a5857 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Wed, 5 Dec 2018 13:29:42 -0600
Subject: [PATCH 7/8] Renamed variable to avoid reusing variable name
---
agents/redfish/fence_redfish.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 6a2dbb76..1ea25cd8 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -42,9 +42,9 @@ def set_power_status(conn, options):
if response['ret'] is False:
return {'ret': False}
data = response['data']
- uri = data["Actions"]["#ComputerSystem.Reset"]["target"]
+ action_uri = data["Actions"]["#ComputerSystem.Reset"]["target"]
- response = send_post_request(options, uri, payload, headers)
+ response = send_post_request(options, action_uri, payload, headers)
if response['ret'] is False:
fail_usage("Error sending power command")
return
From 7dce8b1e22d57fec0d34e91a99fab9d8a06f1303 Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Thu, 6 Dec 2018 10:33:06 -0600
Subject: [PATCH 8/8] Removed unnecessary variable assignments to simplify code
---
agents/redfish/fence_redfish.py | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 1ea25cd8..67ef67ab 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -16,8 +16,7 @@
from fencing import fail_usage, run_delay
def get_power_status(conn, options):
- uri = options["--systems-uri"]
- response = send_get_request(options, uri)
+ response = send_get_request(options, options["--systems-uri"])
if response['ret'] is False:
fail_usage("Couldn't get power information")
data = response['data']
@@ -37,8 +36,7 @@ def set_power_status(conn, options):
headers = {'content-type': 'application/json'}
# Search for 'Actions' key and extract URI from it
- uri = options["--systems-uri"]
- response = send_get_request(options, uri)
+ response = send_get_request(options, options["--systems-uri"])
if response['ret'] is False:
return {'ret': False}
data = response['data']
@@ -70,8 +68,7 @@ def send_post_request(options, uri, payload, headers):
return {'ret': True}
def find_systems_resource(options):
- uri = options["--redfish-uri"]
- response = send_get_request(options, uri)
+ response = send_get_request(options, options["--redfish-uri"])
if response['ret'] is False:
return {'ret': False}
data = response['data']
@@ -80,8 +77,7 @@ def find_systems_resource(options):
# Systems resource not found"
return {'ret': False}
else:
- uri = data["Systems"]["@odata.id"]
- response = send_get_request(options, uri)
+ response = send_get_request(options, data["Systems"]["@odata.id"])
if response['ret'] is False:
return {'ret': False}
data = response['data']

View File

@ -0,0 +1,60 @@
From 7aa3c50d1d02dd26bdeac99c49ada72f842d88e8 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 17 Jan 2019 16:52:52 +0100
Subject: [PATCH] fence_redfish: fail when using invalid cert without
--ssl-insecure
---
agents/redfish/fence_redfish.py | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 67ef67ab..5b719d4b 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -6,6 +6,7 @@
import sys
import re
+import logging
import json
import requests
import atexit
@@ -20,6 +21,9 @@ def get_power_status(conn, options):
if response['ret'] is False:
fail_usage("Couldn't get power information")
data = response['data']
+
+ logging.debug("PowerState is: " + data[u'PowerState'])
+
if data[u'PowerState'].strip() == "Off":
return "off"
else:
@@ -50,21 +54,21 @@ def set_power_status(conn, options):
def send_get_request(options, uri):
full_uri = "https://" + options["--ip"] + uri
try:
- resp = requests.get(full_uri, verify=False,
+ resp = requests.get(full_uri, verify=not "--ssl-insecure" in options,
auth=(options["--username"], options["--password"]))
data = resp.json()
- except:
- return {'ret': False}
+ except Exception as e:
+ fail_usage("Failed: send_get_request: " + str(e))
return {'ret': True, 'data': data}
def send_post_request(options, uri, payload, headers):
full_uri = "https://" + options["--ip"] + uri
try:
requests.post(full_uri, data=json.dumps(payload),
- headers=headers, verify=False,
+ headers=headers, verify=not "--ssl-insecure" in options,
auth=(options["--username"], options["--password"]))
- except:
- return {'ret': False}
+ except Exception as e:
+ fail_usage("Failed: send_post_request: " + str(e))
return {'ret': True}
def find_systems_resource(options):

View File

@ -0,0 +1,43 @@
From 9ebd2e2e36ae0de5c9164f4ac3fd29bdac0cab61 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 14 Feb 2019 10:03:33 +0100
Subject: [PATCH] fence_redfish: use "ipport" parameter and improve logging
---
agents/redfish/fence_redfish.py | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 5b719d4b..28840058 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -22,7 +22,10 @@ def get_power_status(conn, options):
fail_usage("Couldn't get power information")
data = response['data']
- logging.debug("PowerState is: " + data[u'PowerState'])
+ try:
+ logging.debug("PowerState is: " + data[u'PowerState'])
+ except Exception:
+ fail_usage("Unable to get PowerState: " + "https://" + options["--ip"] + ":" + str(options["--ipport"]) + options["--systems-uri"])
if data[u'PowerState'].strip() == "Off":
return "off"
@@ -52,7 +55,7 @@ def set_power_status(conn, options):
return
def send_get_request(options, uri):
- full_uri = "https://" + options["--ip"] + uri
+ full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri
try:
resp = requests.get(full_uri, verify=not "--ssl-insecure" in options,
auth=(options["--username"], options["--password"]))
@@ -62,7 +65,7 @@ def send_get_request(options, uri):
return {'ret': True, 'data': data}
def send_post_request(options, uri, payload, headers):
- full_uri = "https://" + options["--ip"] + uri
+ full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri
try:
requests.post(full_uri, data=json.dumps(payload),
headers=headers, verify=not "--ssl-insecure" in options,

View File

@ -0,0 +1,24 @@
From 21898e45ca2624546de99086a27a14dd1ff86a2b Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 21 Feb 2019 09:08:03 +0100
Subject: [PATCH] fence_redfish: backwards compatibility for <ip>:<port>
---
agents/redfish/fence_redfish.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index 28840058..f1424232 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -140,6 +140,10 @@ def main():
if "--ssl-insecure" in opt:
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
+ # backwards compatibility for <ip>:<port>
+ if options["--ip"].count(":") == 1:
+ (options["--ip"], options["--ipport"]) = options["--ip"].split(":")
+
if "--systems-uri" not in opt:
# Systems URI not provided, find it
sysresult = find_systems_resource(options)

View File

@ -0,0 +1,22 @@
From 64ac6207152508392690b7c1dfcac3fe0a76adfd Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Fri, 5 Apr 2019 09:48:52 +0200
Subject: [PATCH] fence_gce: fix Python 3 encoding issue
---
agents/gce/fence_gce.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 93cd11801..b171710d9 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -146,7 +146,7 @@ def get_metadata(metadata_key, params=None, timeout=None):
url = '%s?%s' % (metadata_url, params)
request = urlrequest.Request(url, headers=METADATA_HEADERS)
request_opener = urlrequest.build_opener(urlrequest.ProxyHandler({}))
- return request_opener.open(request, timeout=timeout * 1.1).read()
+ return request_opener.open(request, timeout=timeout * 1.1).read().decode("utf-8")
def define_new_opts():

View File

@ -0,0 +1,48 @@
From 1b3e548fcc0bd427dade178fa260567047ff3a0e Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Mon, 6 May 2019 13:24:18 +0200
Subject: [PATCH] fence_azure_arm: use skip_shutdown feature when available
The "skip_shutdown" parameter is ignored in older Azure SDK, so there's
no need for a fallback option.
---
agents/azure_arm/fence_azure_arm.py | 6 +++---
tests/data/metadata/fence_azure_arm.xml | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/agents/azure_arm/fence_azure_arm.py b/agents/azure_arm/fence_azure_arm.py
index 58b9eeb13..be0d40345 100755
--- a/agents/azure_arm/fence_azure_arm.py
+++ b/agents/azure_arm/fence_azure_arm.py
@@ -114,8 +114,8 @@ def set_power_status(clients, options):
azure_fence.set_network_state(compute_client, network_client, rgName, vmName, "unblock")
if (options["--action"]=="off"):
- logging.info("Deallocating " + vmName + " in resource group " + rgName)
- compute_client.virtual_machines.deallocate(rgName, vmName)
+ logging.info("Poweroff " + vmName + " in resource group " + rgName)
+ compute_client.virtual_machines.power_off(rgName, vmName, skip_shutdown=True)
elif (options["--action"]=="on"):
logging.info("Starting " + vmName + " in resource group " + rgName)
compute_client.virtual_machines.start(rgName, vmName)
@@ -199,7 +199,7 @@ def main():
docs = {}
docs["shortdesc"] = "Fence agent for Azure Resource Manager"
- docs["longdesc"] = "Used to deallocate virtual machines and to report power state of virtual machines running in Azure. It uses Azure SDK for Python to connect to Azure.\
+ docs["longdesc"] = "fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure.\
\n.P\n\
For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal\
\n.P\n\
diff --git a/tests/data/metadata/fence_azure_arm.xml b/tests/data/metadata/fence_azure_arm.xml
index 1c0b6cc6b..97ecfdba4 100644
--- a/tests/data/metadata/fence_azure_arm.xml
+++ b/tests/data/metadata/fence_azure_arm.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" ?>
<resource-agent name="fence_azure_arm" shortdesc="Fence agent for Azure Resource Manager" >
-<longdesc>Used to deallocate virtual machines and to report power state of virtual machines running in Azure. It uses Azure SDK for Python to connect to Azure.
+<longdesc>fence_azure_arm is an I/O Fencing agent for Azure Resource Manager. It uses Azure SDK for Python to connect to Azure.
For instructions to setup credentials see: https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-create-service-principal-portal

View File

@ -0,0 +1,65 @@
From 75a74debba2205547d8eefae221221c2c71d99ce Mon Sep 17 00:00:00 2001
From: Jose Delarosa <jose.delarosa@dell.com>
Date: Mon, 15 Apr 2019 12:46:42 -0500
Subject: [PATCH] fence_redfish: add headers to HTTP methods
* Needed for full compliance with Redfish spec.
* May cause errors in some devices if not sent.
---
agents/redfish/fence_redfish.py | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/agents/redfish/fence_redfish.py b/agents/redfish/fence_redfish.py
index f1424232..390a4827 100644
--- a/agents/redfish/fence_redfish.py
+++ b/agents/redfish/fence_redfish.py
@@ -16,6 +16,11 @@
from fencing import *
from fencing import fail_usage, run_delay
+GET_HEADERS = {'accept': 'application/json', 'OData-Version': '4.0'}
+POST_HEADERS = {'content-type': 'application/json', 'accept': 'application/json',
+ 'OData-Version': '4.0'}
+
+
def get_power_status(conn, options):
response = send_get_request(options, options["--systems-uri"])
if response['ret'] is False:
@@ -40,7 +45,6 @@ def set_power_status(conn, options):
}[options["--action"]]
payload = {'ResetType': action}
- headers = {'content-type': 'application/json'}
# Search for 'Actions' key and extract URI from it
response = send_get_request(options, options["--systems-uri"])
@@ -49,7 +53,7 @@ def set_power_status(conn, options):
data = response['data']
action_uri = data["Actions"]["#ComputerSystem.Reset"]["target"]
- response = send_post_request(options, action_uri, payload, headers)
+ response = send_post_request(options, action_uri, payload)
if response['ret'] is False:
fail_usage("Error sending power command")
return
@@ -58,17 +62,18 @@ def send_get_request(options, uri):
full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri
try:
resp = requests.get(full_uri, verify=not "--ssl-insecure" in options,
+ headers=GET_HEADERS,
auth=(options["--username"], options["--password"]))
data = resp.json()
except Exception as e:
fail_usage("Failed: send_get_request: " + str(e))
return {'ret': True, 'data': data}
-def send_post_request(options, uri, payload, headers):
+def send_post_request(options, uri, payload):
full_uri = "https://" + options["--ip"] + ":" + str(options["--ipport"]) + uri
try:
requests.post(full_uri, data=json.dumps(payload),
- headers=headers, verify=not "--ssl-insecure" in options,
+ headers=POST_HEADERS, verify=not "--ssl-insecure" in options,
auth=(options["--username"], options["--password"]))
except Exception as e:
fail_usage("Failed: send_post_request: " + str(e))

View File

@ -0,0 +1,164 @@
From a4e8b77ac51a0e4a6de489823ee1be47cbc7eb18 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 9 May 2019 12:09:48 +0200
Subject: [PATCH] fence_rhevm: add RHEV v4 API support and auto-detection
---
agents/rhevm/fence_rhevm.py | 44 +++++++++++++++++++++++------
tests/data/metadata/fence_rhevm.xml | 7 ++++-
2 files changed, 41 insertions(+), 10 deletions(-)
diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py
index a1cdaf605..6012c4239 100644
--- a/agents/rhevm/fence_rhevm.py
+++ b/agents/rhevm/fence_rhevm.py
@@ -9,7 +9,8 @@
from fencing import fail, EC_FETCH_VM_UUID, run_delay
RE_GET_ID = re.compile("<vm( .*)? id=\"(.*?)\"", re.IGNORECASE)
-RE_STATUS = re.compile("<state>(.*?)</state>", re.IGNORECASE)
+RE_STATUS = re.compile("<status>(.*?)</status>", re.IGNORECASE)
+RE_STATE = re.compile("<state>(.*?)</state>", re.IGNORECASE)
RE_GET_NAME = re.compile("<name>(.*?)</name>", re.IGNORECASE)
def get_power_status(conn, options):
@@ -25,7 +26,10 @@ def get_power_status(conn, options):
options["id"] = result.group(2)
- result = RE_STATUS.search(res)
+ if tuple(map(int, options["--api-version"].split(".")))[0] > 3:
+ result = RE_STATUS.search(res)
+ else:
+ result = RE_STATE.search(res)
if result == None:
# We were able to parse ID so output is correct
# in some cases it is possible that RHEV-M output does not
@@ -59,7 +63,10 @@ def get_list(conn, options):
lines = res.split("<vm ")
for i in range(1, len(lines)):
name = RE_GET_NAME.search(lines[i]).group(1)
- status = RE_STATUS.search(lines[i]).group(1)
+ if tuple(map(int, options["--api-version"].split(".")))[0] > 3:
+ status = RE_STATUS.search(lines[i]).group(1)
+ else:
+ status = RE_STATE.search(lines[i]).group(1)
outlets[name] = ("", status)
except AttributeError:
return {}
@@ -69,6 +76,13 @@ def get_list(conn, options):
return outlets
def send_command(opt, command, method="GET"):
+ if opt["--api-version"] == "auto":
+ opt["--api-version"] = "4"
+ res = send_command(opt, "")
+ if re.search("<title>Error</title>", res):
+ opt["--api-version"] = "3"
+ logging.debug("auto-detected API version: " + opt["--api-version"])
+
## setup correct URL
if "--ssl" in opt or "--ssl-secure" in opt or "--ssl-insecure" in opt:
url = "https:"
@@ -90,7 +104,7 @@ def send_command(opt, command, method="GET"):
web_buffer = io.BytesIO()
conn.setopt(pycurl.URL, url.encode("UTF-8"))
conn.setopt(pycurl.HTTPHEADER, [
- "Version: 3",
+ "Version: {}".format(opt["--api-version"]),
"Content-type: application/xml",
"Accept: application/xml",
"Prefer: persistent-auth",
@@ -130,8 +144,9 @@ def send_command(opt, command, method="GET"):
result = web_buffer.getvalue().decode("UTF-8")
- logging.debug("%s\n", command)
- logging.debug("%s\n", result)
+ logging.debug("url: %s\n", url)
+ logging.debug("command: %s\n", command)
+ logging.debug("result: %s\n", result)
return result
@@ -151,6 +166,15 @@ def define_new_opts():
"required" : "0",
"shortdesc" : "Reuse cookies for authentication",
"order" : 1}
+ all_opt["api_version"] = {
+ "getopt" : ":",
+ "longopt" : "api-version",
+ "help" : "--api-version "
+ "Version of RHEV API (default: auto)",
+ "required" : "0",
+ "order" : 2,
+ "default" : "auto",
+ }
all_opt["api_path"] = {
"getopt" : ":",
"longopt" : "api-path",
@@ -158,20 +182,19 @@ def define_new_opts():
"default" : "/ovirt-engine/api",
"required" : "0",
"shortdesc" : "The path part of the API URL",
- "order" : 2}
+ "order" : 3}
all_opt["disable_http_filter"] = {
"getopt" : "",
"longopt" : "disable-http-filter",
"help" : "--disable-http-filter Set HTTP Filter header to false",
"required" : "0",
"shortdesc" : "Set HTTP Filter header to false",
- "order" : 3}
+ "order" : 4}
def main():
device_opt = [
"ipaddr",
- "api_path",
"login",
"passwd",
"ssl",
@@ -179,6 +202,8 @@ def main():
"web",
"port",
"use_cookies",
+ "api_version",
+ "api_path",
"disable_http_filter",
]
@@ -186,6 +211,7 @@ def main():
define_new_opts()
all_opt["power_wait"]["default"] = "1"
+ all_opt["shell_timeout"]["default"] = "5"
options = check_input(device_opt, process_input(device_opt))
diff --git a/tests/data/metadata/fence_rhevm.xml b/tests/data/metadata/fence_rhevm.xml
index 6344db79f..c56cf64b6 100644
--- a/tests/data/metadata/fence_rhevm.xml
+++ b/tests/data/metadata/fence_rhevm.xml
@@ -98,6 +98,11 @@
<content type="string" />
<shortdesc lang="en">Login name</shortdesc>
</parameter>
+ <parameter name="api_version" unique="0" required="0">
+ <getopt mixed="--api-version" />
+ <content type="string" default="auto" />
+ <shortdesc lang="en">Version of RHEV API (default: auto)</shortdesc>
+ </parameter>
<parameter name="api_path" unique="0" required="0">
<getopt mixed="--api-path=[path]" />
<shortdesc lang="en">The path part of the API URL</shortdesc>
@@ -164,7 +169,7 @@
</parameter>
<parameter name="shell_timeout" unique="0" required="0">
<getopt mixed="--shell-timeout=[seconds]" />
- <content type="second" default="3" />
+ <content type="second" default="5" />
<shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
</parameter>
<parameter name="retry_on" unique="0" required="0">

View File

@ -0,0 +1,21 @@
From e5c6c2e134fd397ffe3319adc7afb8b633a251b2 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 14 May 2019 16:44:59 +0200
Subject: [PATCH] fence_mpath: import ctypes to fix watchdog hardreboot
---
agents/mpath/fence_mpath.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py
index d9ac2ef54..e4f598361 100644
--- a/agents/mpath/fence_mpath.py
+++ b/agents/mpath/fence_mpath.py
@@ -6,6 +6,7 @@
import os
import logging
import atexit
+import ctypes
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import fail_usage, run_command, atexit_handler, check_input, process_input, show_docs
from fencing import fence_action, all_opt, run_delay

View File

@ -0,0 +1,32 @@
From a77165d7c8caadf514462d359c6d564048c2c33a Mon Sep 17 00:00:00 2001
From: Sandro <42254081+Numblesix@users.noreply.github.com>
Date: Tue, 29 Jan 2019 13:29:52 +0100
Subject: [PATCH] Changed Encoding to UTF-8
Starting from RHV/Ovirt 4.2 we saw issues with the agent(unable to fence) after switching to UTF-8 all worked again.
---
agents/rhevm/fence_rhevm.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py
index 2a5107cc6..a1cdaf605 100644
--- a/agents/rhevm/fence_rhevm.py
+++ b/agents/rhevm/fence_rhevm.py
@@ -88,7 +88,7 @@ def send_command(opt, command, method="GET"):
## send command through pycurl
conn = pycurl.Curl()
web_buffer = io.BytesIO()
- conn.setopt(pycurl.URL, url.encode("ascii"))
+ conn.setopt(pycurl.URL, url.encode("UTF-8"))
conn.setopt(pycurl.HTTPHEADER, [
"Version: 3",
"Content-type: application/xml",
@@ -128,7 +128,7 @@ def send_command(opt, command, method="GET"):
opt["cookie"] = cookie
- result = web_buffer.getvalue().decode()
+ result = web_buffer.getvalue().decode("UTF-8")
logging.debug("%s\n", command)
logging.debug("%s\n", result)

View File

@ -0,0 +1,31 @@
From 965924fe8bf7dcd0bc15fb0e9265ab49bb8a5dd8 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Mon, 20 May 2019 15:49:39 +0200
Subject: [PATCH] fence_rhevm: fix debug encoding issues
Tested with UTF-8 encoded comment in result, which caused this issue,
and added to command and url in case they are in UTF-8 decoded state.
---
agents/rhevm/fence_rhevm.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py
index 6012c423..9e4650cd 100644
--- a/agents/rhevm/fence_rhevm.py
+++ b/agents/rhevm/fence_rhevm.py
@@ -144,9 +144,9 @@ def send_command(opt, command, method="GET"):
result = web_buffer.getvalue().decode("UTF-8")
- logging.debug("url: %s\n", url)
- logging.debug("command: %s\n", command)
- logging.debug("result: %s\n", result)
+ logging.debug("url: %s\n", url.encode("UTF-8"))
+ logging.debug("command: %s\n", command.encode("UTF-8"))
+ logging.debug("result: %s\n", result.encode("UTF-8"))
return result
--
2.21.0

View File

@ -0,0 +1,30 @@
From 1c4a64ca803831b44c96c75022abe5bb8713cd1a Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Wed, 22 May 2019 10:13:34 +0200
Subject: [PATCH] fence_scsi: detect node ID using new format, and fallback to
old format before failing
---
agents/scsi/fence_scsi.py | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/agents/scsi/fence_scsi.py b/agents/scsi/fence_scsi.py
index 8a1e4c77..5580e08b 100644
--- a/agents/scsi/fence_scsi.py
+++ b/agents/scsi/fence_scsi.py
@@ -192,8 +192,14 @@ def get_cluster_id(options):
def get_node_id(options):
cmd = options["--corosync-cmap-path"] + " nodelist"
+ out = run_cmd(options, cmd)["out"]
+
+ match = re.search(r".(\d+).name \(str\) = " + options["--plug"] + "\n", out)
+
+ # try old format before failing
+ if not match:
+ match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", out)
- match = re.search(r".(\d+).ring._addr \(str\) = " + options["--plug"] + "\n", run_cmd(options, cmd)["out"])
return match.group(1) if match else fail_usage("Failed: unable to parse output of corosync-cmapctl or node does not exist")

View File

@ -0,0 +1,42 @@
From 418b3a36c8a7de0e984a0cd4707f2b90f279c4ce Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 13 Jun 2019 11:29:25 +0200
Subject: [PATCH] fence_scsi watchdog: dont exit when command fails using retry
parameter
---
lib/fencing.py.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/lib/fencing.py.py b/lib/fencing.py.py
index 8cd0a813..6f2526a9 100644
--- a/lib/fencing.py.py
+++ b/lib/fencing.py.py
@@ -530,7 +530,7 @@ def fail_usage(message="", stop=True):
logging.error("Please use '-h' for usage\n")
sys.exit(EC_GENERIC_ERROR)
-def fail(error_code):
+def fail(error_code, stop=True):
message = {
EC_LOGIN_DENIED : "Unable to connect/login to fencing device",
EC_CONNECTION_LOST : "Connection lost",
@@ -546,7 +546,8 @@ def fail(error_code):
}[error_code] + "\n"
logging.error("%s\n", message)
- sys.exit(EC_GENERIC_ERROR)
+ if stop:
+ sys.exit(EC_GENERIC_ERROR)
def usage(avail_opt):
print("Usage:")
@@ -1009,7 +1010,7 @@ def run_command(options, command, timeout=None, env=None, log_command=None):
thread.join(timeout)
if thread.is_alive():
process.kill()
- fail(EC_TIMED_OUT)
+ fail(EC_TIMED_OUT, stop=(int(options.get("retry", 0)) < 1))
status = process.wait()

View File

@ -0,0 +1,344 @@
From 418df5845d1781e18e300cf17b2de714e4ff09d1 Mon Sep 17 00:00:00 2001
From: "feng.changf1" <feng.changf1@alibaba-inc.com>
Date: Tue, 24 Jul 2018 15:56:50 +0800
Subject: [PATCH 1/3] Add Aliyun fence agent.
---
agents/aliyun/fence_aliyun.py | 146 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 146 insertions(+)
create mode 100644 agents/aliyun/fence_aliyun.py
diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
new file mode 100644
index 00000000..ec7d2316
--- /dev/null
+++ b/agents/aliyun/fence_aliyun.py
@@ -0,0 +1,146 @@
+#!/usr/bin/python -tt
+
+import sys, re
+import logging
+import atexit
+import json
+sys.path.append("@FENCEAGENTSLIBDIR@")
+from fencing import *
+from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
+
+from aliyunsdkcore import client
+
+from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
+from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest
+from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest
+from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest
+
+def _send_request(conn, request):
+ request.set_accept_format('json')
+ try:
+ response_str = conn.do_action_with_exception(request)
+ response_detail = json.loads(response_str)
+ return response_detail
+ except Exception as e:
+ fail_usage("Failed: _send_request failed")
+
+def start_instance(conn, instance_id):
+ request = StartInstanceRequest()
+ request.set_InstanceId(instance_id)
+ _send_request(conn, request)
+
+def stop_instance(conn, instance_id):
+ request = StopInstanceRequest()
+ request.set_InstanceId(instance_id)
+ request.set_ForceStop('true')
+ _send_request(conn, request)
+
+def reboot_instance(conn, instance_id):
+ request = RebootInstanceRequest()
+ request.set_InstanceId(instance_id)
+ request.set_ForceStop('true')
+ _send_request(conn, request)
+
+def get_status(conn, instance_id):
+ request = DescribeInstancesRequest()
+ request.set_InstanceIds(json.dumps([instance_id]))
+ response = _send_request(conn, request)
+ instance_status = None
+ if response is not None:
+ instance_list = response.get('Instances').get('Instance')
+ for item in instance_list:
+ instance_status = item.get('Status')
+ return instance_status
+
+def get_nodes_list(conn, options):
+ result = {}
+ request = DescribeInstancesRequest()
+ response = _send_request(conn, request)
+ instance_status = None
+ if response is not None:
+ instance_list = response.get('Instances').get('Instance')
+ for item in instance_list:
+ instance_id = item.get('InstanceId')
+ result[instance_id] = ("", None)
+ return result
+
+def get_power_status(conn, options):
+ state = get_status(conn, options["--plug"])
+ if state == "Running":
+ return "on"
+ elif state == "Stopped":
+ return "off"
+ else:
+ return "unknown"
+
+
+def set_power_status(conn, options):
+ if (options["--action"]=="off"):
+ stop_instance(conn, options["--plug"])
+ elif (options["--action"]=="on"):
+ start_instance(conn, options["--plug"])
+ elif (options["--action"]=="reboot"):
+ reboot_instance(conn, options["--plug"])
+
+
+def define_new_opts():
+ all_opt["region"] = {
+ "getopt" : "r:",
+ "longopt" : "region",
+ "help" : "-r, --region=[name] Region, e.g. cn-hangzhou",
+ "shortdesc" : "Region.",
+ "required" : "0",
+ "order" : 2
+ }
+ all_opt["access_key"] = {
+ "getopt" : "a:",
+ "longopt" : "access-key",
+ "help" : "-a, --access-key=[name] Access Key",
+ "shortdesc" : "Access Key.",
+ "required" : "0",
+ "order" : 3
+ }
+ all_opt["secret_key"] = {
+ "getopt" : "s:",
+ "longopt" : "secret-key",
+ "help" : "-s, --secret-key=[name] Secret Key",
+ "shortdesc" : "Secret Key.",
+ "required" : "0",
+ "order" : 4
+ }
+
+# Main agent method
+def main():
+ conn = None
+
+ device_opt = ["port", "no_password", "region", "access_key", "secret_key"]
+
+ atexit.register(atexit_handler)
+
+ define_new_opts()
+
+ all_opt["power_timeout"]["default"] = "60"
+
+ options = check_input(device_opt, process_input(device_opt))
+
+ docs = {}
+ docs["shortdesc"] = "Fence agent for Aliyun (Aliyun Web Services)"
+ docs["longdesc"] = "fence_aliyun is an I/O Fencing agent for Aliyun"
+ docs["vendorurl"] = "http://www.aliyun.com"
+ show_docs(options, docs)
+
+ run_delay(options)
+
+ if "--region" in options and "--access-key" in options and "--secret-key" in options:
+ region = options["--region"]
+ access_key = options["--access-key"]
+ secret_key = options["--secret-key"]
+ conn = client.AcsClient(access_key, secret_key, region)
+
+
+ # Operate the fencing device
+ result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list)
+ sys.exit(result)
+
+if __name__ == "__main__":
+ main()
From 28b55555abda9b6c278a7f082bb22c4f6f1e2474 Mon Sep 17 00:00:00 2001
From: "feng.changf1" <feng.changf1@alibaba-inc.com>
Date: Tue, 24 Jul 2018 17:18:53 +0800
Subject: [PATCH 2/3] Add Aliyun fence agent.
---
tests/data/metadata/fence_aliyun.xml | 113 +++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 tests/data/metadata/fence_aliyun.xml
diff --git a/tests/data/metadata/fence_aliyun.xml b/tests/data/metadata/fence_aliyun.xml
new file mode 100644
index 00000000..1db692ee
--- /dev/null
+++ b/tests/data/metadata/fence_aliyun.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" ?>
+<resource-agent name="fence_aliyun" shortdesc="Fence agent for Aliyun (Aliyun Web Services)" >
+<longdesc>fence_aliyun is an I/O Fencing agent for Aliyun</longdesc>
+<vendor-url>http://www.aliyun.com</vendor-url>
+<parameters>
+ <parameter name="action" unique="0" required="1">
+ <getopt mixed="-o, --action=[action]" />
+ <content type="string" default="reboot" />
+ <shortdesc lang="en">Fencing action</shortdesc>
+ </parameter>
+ <parameter name="plug" unique="0" required="1" obsoletes="port">
+ <getopt mixed="-n, --plug=[id]" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
+ </parameter>
+ <parameter name="port" unique="0" required="1" deprecated="1">
+ <getopt mixed="-n, --plug=[id]" />
+ <content type="string" />
+ <shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
+ </parameter>
+ <parameter name="region" unique="0" required="0">
+ <getopt mixed="-r, --region=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Region.</shortdesc>
+ </parameter>
+ <parameter name="access_key" unique="0" required="0">
+ <getopt mixed="-a, --access-key=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Access Key.</shortdesc>
+ </parameter>
+ <parameter name="secret_key" unique="0" required="0">
+ <getopt mixed="-s, --secret-key=[name]" />
+ <content type="string" />
+ <shortdesc lang="en">Secret Key.</shortdesc>
+ </parameter>
+ <parameter name="quiet" unique="0" required="0">
+ <getopt mixed="-q, --quiet" />
+ <content type="boolean" />
+ <shortdesc lang="en">Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog.</shortdesc>
+ </parameter>
+ <parameter name="verbose" unique="0" required="0">
+ <getopt mixed="-v, --verbose" />
+ <content type="boolean" />
+ <shortdesc lang="en">Verbose mode</shortdesc>
+ </parameter>
+ <parameter name="debug" unique="0" required="0" deprecated="1">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <content type="string" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="debug_file" unique="0" required="0" obsoletes="debug">
+ <getopt mixed="-D, --debug-file=[debugfile]" />
+ <content type="string" />
+ <shortdesc lang="en">Write debug information to given file</shortdesc>
+ </parameter>
+ <parameter name="version" unique="0" required="0">
+ <getopt mixed="-V, --version" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display version information and exit</shortdesc>
+ </parameter>
+ <parameter name="help" unique="0" required="0">
+ <getopt mixed="-h, --help" />
+ <content type="boolean" />
+ <shortdesc lang="en">Display help and exit</shortdesc>
+ </parameter>
+ <parameter name="separator" unique="0" required="0">
+ <getopt mixed="-C, --separator=[char]" />
+ <content type="string" default="," />
+ <shortdesc lang="en">Separator for CSV created by 'list' operation</shortdesc>
+ </parameter>
+ <parameter name="delay" unique="0" required="0">
+ <getopt mixed="--delay=[seconds]" />
+ <content type="second" default="0" />
+ <shortdesc lang="en">Wait X seconds before fencing is started</shortdesc>
+ </parameter>
+ <parameter name="login_timeout" unique="0" required="0">
+ <getopt mixed="--login-timeout=[seconds]" />
+ <content type="second" default="5" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after login</shortdesc>
+ </parameter>
+ <parameter name="power_timeout" unique="0" required="0">
+ <getopt mixed="--power-timeout=[seconds]" />
+ <content type="second" default="60" />
+ <shortdesc lang="en">Test X seconds for status change after ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="power_wait" unique="0" required="0">
+ <getopt mixed="--power-wait=[seconds]" />
+ <content type="second" default="0" />
+ <shortdesc lang="en">Wait X seconds after issuing ON/OFF</shortdesc>
+ </parameter>
+ <parameter name="shell_timeout" unique="0" required="0">
+ <getopt mixed="--shell-timeout=[seconds]" />
+ <content type="second" default="3" />
+ <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc>
+ </parameter>
+ <parameter name="retry_on" unique="0" required="0">
+ <getopt mixed="--retry-on=[attempts]" />
+ <content type="integer" default="1" />
+ <shortdesc lang="en">Count of attempts to retry power on</shortdesc>
+ </parameter>
+</parameters>
+<actions>
+ <action name="on" automatic="0"/>
+ <action name="off" />
+ <action name="reboot" />
+ <action name="status" />
+ <action name="list" />
+ <action name="list-status" />
+ <action name="monitor" />
+ <action name="metadata" />
+ <action name="validate-all" />
+</actions>
+</resource-agent>
From 53bbd91e91c231c89ae8981238bb15d85d02207b Mon Sep 17 00:00:00 2001
From: "feng.changf1" <feng.changf1@alibaba-inc.com>
Date: Tue, 24 Jul 2018 17:26:45 +0800
Subject: [PATCH 3/3] Fix CI error.
---
agents/aliyun/fence_aliyun.py | 32 +++++++++++++++++---------------
1 file changed, 17 insertions(+), 15 deletions(-)
diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
index ec7d2316..0f24b83e 100644
--- a/agents/aliyun/fence_aliyun.py
+++ b/agents/aliyun/fence_aliyun.py
@@ -1,20 +1,22 @@
#!/usr/bin/python -tt
-import sys, re
-import logging
-import atexit
-import json
-sys.path.append("@FENCEAGENTSLIBDIR@")
-from fencing import *
-from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
-
-from aliyunsdkcore import client
-
-from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
-from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest
-from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest
-from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest
-
+try:
+ import sys, re
+ import logging
+ import atexit
+ import json
+ sys.path.append("@FENCEAGENTSLIBDIR@")
+ from fencing import *
+ from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
+
+ from aliyunsdkcore import client
+
+ from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
+ from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest
+ from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest
+ from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest
+except ImportError:
+ pass
def _send_request(conn, request):
request.set_accept_format('json')
try:

View File

@ -0,0 +1,58 @@
From 8db45537fb470624a754ea1243cc4f349a9b413d Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 24 Jul 2018 13:10:41 +0200
Subject: [PATCH] fence_aliyun: fix CI and add Python detection
---
agents/aliyun/fence_aliyun.py | 19 ++++++++++---------
tests/data/metadata/fence_aliyun.xml | 1 +
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
index 0f24b83e..aa6c0acf 100644
--- a/agents/aliyun/fence_aliyun.py
+++ b/agents/aliyun/fence_aliyun.py
@@ -1,14 +1,14 @@
-#!/usr/bin/python -tt
+#!@PYTHON@ -tt
-try:
- import sys, re
- import logging
- import atexit
- import json
- sys.path.append("@FENCEAGENTSLIBDIR@")
- from fencing import *
- from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
+import sys, re
+import logging
+import atexit
+import json
+sys.path.append("@FENCEAGENTSLIBDIR@")
+from fencing import *
+from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
+try:
from aliyunsdkcore import client
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest
@@ -17,6 +17,7 @@
from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest
except ImportError:
pass
+
def _send_request(conn, request):
request.set_accept_format('json')
try:
diff --git a/tests/data/metadata/fence_aliyun.xml b/tests/data/metadata/fence_aliyun.xml
index 1db692ee..b41d82bf 100644
--- a/tests/data/metadata/fence_aliyun.xml
+++ b/tests/data/metadata/fence_aliyun.xml
@@ -108,6 +108,7 @@
<action name="list-status" />
<action name="monitor" />
<action name="metadata" />
+ <action name="manpage" />
<action name="validate-all" />
</actions>
</resource-agent>

View File

@ -0,0 +1,51 @@
From 790cbaa66f3927a84739af4a1f0e8bba295cdc36 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Mon, 30 Jul 2018 10:43:04 +0200
Subject: [PATCH] fence_aliyun: add logging
---
agents/aliyun/fence_aliyun.py | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
index aa6c0acf..2cda6b7f 100644
--- a/agents/aliyun/fence_aliyun.py
+++ b/agents/aliyun/fence_aliyun.py
@@ -23,9 +23,10 @@ def _send_request(conn, request):
try:
response_str = conn.do_action_with_exception(request)
response_detail = json.loads(response_str)
+ logging.debug("_send_request reponse: %s" % response_detail)
return response_detail
except Exception as e:
- fail_usage("Failed: _send_request failed")
+ fail_usage("Failed: _send_request failed: %s" % e)
def start_instance(conn, instance_id):
request = StartInstanceRequest()
@@ -69,15 +70,22 @@ def get_nodes_list(conn, options):
def get_power_status(conn, options):
state = get_status(conn, options["--plug"])
+
if state == "Running":
- return "on"
+ status = "on"
elif state == "Stopped":
- return "off"
+ status = "off"
else:
- return "unknown"
+ status = "unknown"
+
+ logging.info("get_power_status: %s" % status)
+
+ return status
def set_power_status(conn, options):
+ logging.info("set_power_status: %s" % options["--action"])
+
if (options["--action"]=="off"):
stop_instance(conn, options["--plug"])
elif (options["--action"]=="on"):

View File

@ -0,0 +1,11 @@
diff -uNr a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
--- a/agents/aliyun/fence_aliyun.py 2018-07-24 14:30:29.030311806 +0200
+++ b/agents/aliyun/fence_aliyun.py 2018-07-24 14:31:10.023884949 +0200
@@ -9,6 +9,7 @@
from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay
try:
+ sys.path.insert(0, '/usr/lib/fence-agents/bundled/aliyun')
from aliyunsdkcore import client
from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest

View File

@ -0,0 +1,31 @@
From c21d60fbcf0b11dcbf4f70006c8ffaeac4ca7dbd Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 28 Aug 2018 15:20:10 +0200
Subject: [PATCH] fence_aliyun: list instance names and show up to 100
instances
---
agents/aliyun/fence_aliyun.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
index 2cda6b7f..b3aca12f 100644
--- a/agents/aliyun/fence_aliyun.py
+++ b/agents/aliyun/fence_aliyun.py
@@ -59,13 +59,15 @@ def get_status(conn, instance_id):
def get_nodes_list(conn, options):
result = {}
request = DescribeInstancesRequest()
+ request.set_PageSize(100)
response = _send_request(conn, request)
instance_status = None
if response is not None:
instance_list = response.get('Instances').get('Instance')
for item in instance_list:
instance_id = item.get('InstanceId')
- result[instance_id] = ("", None)
+ instance_name = item.get('InstanceName')
+ result[instance_id] = (instance_name, None)
return result
def get_power_status(conn, options):

View File

@ -0,0 +1,31 @@
From 588f935b1f79c8355d461fe9f8597151fbcd7fa2 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 30 Aug 2018 09:11:58 +0200
Subject: [PATCH] fence_aliyun: correct indentation for *key in help
---
agents/aliyun/fence_aliyun.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/agents/aliyun/fence_aliyun.py b/agents/aliyun/fence_aliyun.py
index 2cda6b7f..7d04c5bb 100644
--- a/agents/aliyun/fence_aliyun.py
+++ b/agents/aliyun/fence_aliyun.py
@@ -106,7 +106,7 @@ def define_new_opts():
all_opt["access_key"] = {
"getopt" : "a:",
"longopt" : "access-key",
- "help" : "-a, --access-key=[name] Access Key",
+ "help" : "-a, --access-key=[name] Access Key",
"shortdesc" : "Access Key.",
"required" : "0",
"order" : 3
@@ -114,7 +114,7 @@ def define_new_opts():
all_opt["secret_key"] = {
"getopt" : "s:",
"longopt" : "secret-key",
- "help" : "-s, --secret-key=[name] Secret Key",
+ "help" : "-s, --secret-key=[name] Secret Key",
"shortdesc" : "Secret Key.",
"required" : "0",
"order" : 4

View File

@ -0,0 +1,22 @@
From 70bd4ffa245ef7e8b7698228bab3b41c240d50d2 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 4 Sep 2018 12:35:07 +0200
Subject: [PATCH] fence_cisco_ucs: encode POSTFIELDS
---
agents/cisco_ucs/fence_cisco_ucs.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/cisco_ucs/fence_cisco_ucs.py b/agents/cisco_ucs/fence_cisco_ucs.py
index d509b3e0..ec311754 100644
--- a/agents/cisco_ucs/fence_cisco_ucs.py
+++ b/agents/cisco_ucs/fence_cisco_ucs.py
@@ -111,7 +111,7 @@ def send_command(opt, command, timeout):
web_buffer = io.BytesIO()
conn.setopt(pycurl.URL, url.encode("ascii"))
conn.setopt(pycurl.HTTPHEADER, ["Content-type: text/xml"])
- conn.setopt(pycurl.POSTFIELDS, command)
+ conn.setopt(pycurl.POSTFIELDS, command.encode("ascii"))
conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write)
conn.setopt(pycurl.TIMEOUT, timeout)
if "--ssl" in opt or "--ssl-secure" in opt:

View File

@ -0,0 +1,232 @@
From 15635df9d12ce693f473d5ebcd5b7cacb81e2295 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Mon, 16 Jul 2018 11:14:16 +0200
Subject: [PATCH] fence_compute/fence_evacuate: workaround for compute-domain
regression
---
agents/compute/fence_compute.py | 24 +++++++++++++++++++-----
agents/evacuate/fence_evacuate.py | 24 +++++++++++++++++++-----
tests/data/metadata/fence_compute.xml | 24 ++++++++++++++++++++++--
tests/data/metadata/fence_evacuate.xml | 24 ++++++++++++++++++++++--
4 files changed, 82 insertions(+), 14 deletions(-)
diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py
index ec2d093c..aac9b296 100644
--- a/agents/compute/fence_compute.py
+++ b/agents/compute/fence_compute.py
@@ -353,7 +353,7 @@ def define_new_opts():
"default" : "",
"order": 1,
}
- all_opt["user_domain"] = {
+ all_opt["user-domain"] = {
"getopt" : "u:",
"longopt" : "user-domain",
"help" : "-u, --user-domain=[name] Keystone v3 User Domain",
@@ -362,7 +362,7 @@ def define_new_opts():
"default" : "Default",
"order": 2,
}
- all_opt["project_domain"] = {
+ all_opt["project-domain"] = {
"getopt" : "P:",
"longopt" : "project-domain",
"help" : "-d, --project-domain=[name] Keystone v3 Project Domain",
@@ -433,6 +433,14 @@ def define_new_opts():
"default" : "False",
"order": 5,
}
+ all_opt["compute-domain"] = {
+ "getopt" : ":",
+ "longopt" : "compute-domain",
+ "help" : "--compute-domain=[string] Replaced by --domain",
+ "required" : "0",
+ "shortdesc" : "Replaced by domain",
+ "order": 6,
+ }
def set_multi_power_fn(connection, options, set_power_fn, get_power_fn, retry_attempts=1):
for _ in range(retry_attempts):
@@ -450,9 +458,10 @@ def main():
global override_status
atexit.register(atexit_handler)
- device_opt = ["login", "passwd", "tenant_name", "auth_url", "fabric_fencing",
- "no_login", "no_password", "port", "domain", "project_domain", "user_domain",
- "no_shared_storage", "endpoint_type", "record_only", "instance_filtering", "insecure", "region_name"]
+ device_opt = ["login", "passwd", "tenant_name", "auth_url", "fabric_fencing", "no_login",
+ "no_password", "port", "domain", "compute-domain", "project-domain",
+ "user-domain", "no_shared_storage", "endpoint_type", "record_only",
+ "instance_filtering", "insecure", "region_name"]
define_new_opts()
all_opt["shell_timeout"]["default"] = "180"
@@ -470,6 +479,11 @@ def main():
run_delay(options)
+ # workaround to avoid regressions
+ if "--compute-domain" in options and options["--compute-domain"]:
+ options["--domain"] = options["--compute-domain"]
+ del options["--domain"]
+
logging.debug("Running "+options["--action"])
connection = create_nova_connection(options)
diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py
index 615dede7..529a60dd 100644
--- a/agents/evacuate/fence_evacuate.py
+++ b/agents/evacuate/fence_evacuate.py
@@ -287,7 +287,7 @@ def define_new_opts():
"default" : "",
"order": 1,
}
- all_opt["user_domain"] = {
+ all_opt["user-domain"] = {
"getopt" : "u:",
"longopt" : "user-domain",
"help" : "-u, --user-domain=[name] Keystone v3 User Domain",
@@ -296,7 +296,7 @@ def define_new_opts():
"default" : "Default",
"order": 2,
}
- all_opt["project_domain"] = {
+ all_opt["project-domain"] = {
"getopt" : "P:",
"longopt" : "project-domain",
"help" : "-d, --project-domain=[name] Keystone v3 Project Domain",
@@ -358,14 +358,22 @@ def define_new_opts():
"default" : "False",
"order": 5,
}
+ all_opt["compute-domain"] = {
+ "getopt" : ":",
+ "longopt" : "compute-domain",
+ "help" : "--compute-domain=[string] Replaced by --domain",
+ "required" : "0",
+ "shortdesc" : "Replaced by domain",
+ "order": 6,
+ }
def main():
atexit.register(atexit_handler)
device_opt = ["login", "passwd", "tenant_name", "auth_url",
- "no_login", "no_password", "port", "domain", "project_domain",
- "user_domain", "no_shared_storage", "endpoint_type",
- "instance_filtering", "insecure", "region_name"]
+ "no_login", "no_password", "port", "domain", "compute-domain",
+ "project-domain", "user-domain", "no_shared_storage",
+ "endpoint_type", "instance_filtering", "insecure", "region_name"]
define_new_opts()
all_opt["shell_timeout"]["default"] = "180"
@@ -380,6 +388,12 @@ def main():
run_delay(options)
+ # workaround to avoid regressions
+ if "--compute-domain" in options and options["--compute-domain"]:
+ options["--domain"] = options["--compute-domain"]
+ del options["--domain"]
+
+
connection = create_nova_connection(options)
# Un-evacuating a server doesn't make sense
diff --git a/tests/data/metadata/fence_compute.xml b/tests/data/metadata/fence_compute.xml
index e1dac97c..1dcbfc54 100644
--- a/tests/data/metadata/fence_compute.xml
+++ b/tests/data/metadata/fence_compute.xml
@@ -73,12 +73,22 @@
<content type="boolean" default="False" />
<shortdesc lang="en">Allow Insecure TLS Requests</shortdesc>
</parameter>
- <parameter name="project_domain" unique="0" required="0">
+ <parameter name="project-domain" unique="0" required="0" deprecated="1">
<getopt mixed="-d, --project-domain=[name]" />
<content type="string" default="Default" />
<shortdesc lang="en">Keystone v3 Project Domain</shortdesc>
</parameter>
- <parameter name="user_domain" unique="0" required="0">
+ <parameter name="project_domain" unique="0" required="0" obsoletes="project-domain">
+ <getopt mixed="-d, --project-domain=[name]" />
+ <content type="string" default="Default" />
+ <shortdesc lang="en">Keystone v3 Project Domain</shortdesc>
+ </parameter>
+ <parameter name="user-domain" unique="0" required="0" deprecated="1">
+ <getopt mixed="-u, --user-domain=[name]" />
+ <content type="string" default="Default" />
+ <shortdesc lang="en">Keystone v3 User Domain</shortdesc>
+ </parameter>
+ <parameter name="user_domain" unique="0" required="0" obsoletes="user-domain">
<getopt mixed="-u, --user-domain=[name]" />
<content type="string" default="Default" />
<shortdesc lang="en">Keystone v3 User Domain</shortdesc>
@@ -103,6 +113,16 @@
<content type="string" default="False" />
<shortdesc lang="en">Only record the target as needing evacuation</shortdesc>
</parameter>
+ <parameter name="compute-domain" unique="0" required="0" deprecated="1">
+ <getopt mixed="--compute-domain=[string]" />
+ <content type="string" />
+ <shortdesc lang="en">Replaced by domain</shortdesc>
+ </parameter>
+ <parameter name="compute_domain" unique="0" required="0" obsoletes="compute-domain">
+ <getopt mixed="--compute-domain=[string]" />
+ <content type="string" />
+ <shortdesc lang="en">Replaced by domain</shortdesc>
+ </parameter>
<parameter name="quiet" unique="0" required="0">
<getopt mixed="-q, --quiet" />
<content type="boolean" />
diff --git a/tests/data/metadata/fence_evacuate.xml b/tests/data/metadata/fence_evacuate.xml
index 6f8bd0a4..4f1f6a58 100644
--- a/tests/data/metadata/fence_evacuate.xml
+++ b/tests/data/metadata/fence_evacuate.xml
@@ -73,12 +73,22 @@
<content type="boolean" default="False" />
<shortdesc lang="en">Allow Insecure TLS Requests</shortdesc>
</parameter>
- <parameter name="project_domain" unique="0" required="0">
+ <parameter name="project-domain" unique="0" required="0" deprecated="1">
<getopt mixed="-d, --project-domain=[name]" />
<content type="string" default="Default" />
<shortdesc lang="en">Keystone v3 Project Domain</shortdesc>
</parameter>
- <parameter name="user_domain" unique="0" required="0">
+ <parameter name="project_domain" unique="0" required="0" obsoletes="project-domain">
+ <getopt mixed="-d, --project-domain=[name]" />
+ <content type="string" default="Default" />
+ <shortdesc lang="en">Keystone v3 Project Domain</shortdesc>
+ </parameter>
+ <parameter name="user-domain" unique="0" required="0" deprecated="1">
+ <getopt mixed="-u, --user-domain=[name]" />
+ <content type="string" default="Default" />
+ <shortdesc lang="en">Keystone v3 User Domain</shortdesc>
+ </parameter>
+ <parameter name="user_domain" unique="0" required="0" obsoletes="user-domain">
<getopt mixed="-u, --user-domain=[name]" />
<content type="string" default="Default" />
<shortdesc lang="en">Keystone v3 User Domain</shortdesc>
@@ -98,6 +108,16 @@
<content type="boolean" default="False" />
<shortdesc lang="en">Disable functionality for dealing with shared storage</shortdesc>
</parameter>
+ <parameter name="compute-domain" unique="0" required="0" deprecated="1">
+ <getopt mixed="--compute-domain=[string]" />
+ <content type="string" />
+ <shortdesc lang="en">Replaced by domain</shortdesc>
+ </parameter>
+ <parameter name="compute_domain" unique="0" required="0" obsoletes="compute-domain">
+ <getopt mixed="--compute-domain=[string]" />
+ <content type="string" />
+ <shortdesc lang="en">Replaced by domain</shortdesc>
+ </parameter>
<parameter name="quiet" unique="0" required="0">
<getopt mixed="-q, --quiet" />
<content type="boolean" />
--
2.17.1

View File

@ -0,0 +1,20 @@
diff -uNr a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py
--- a/agents/evacuate/fence_evacuate.py 2018-06-28 14:24:54.000000000 +0200
+++ b/agents/evacuate/fence_evacuate.py 2018-07-11 09:08:56.975072003 +0200
@@ -74,12 +74,15 @@
}
def _is_server_evacuable(server, evac_flavors, evac_images):
+ reason = "flavor "+server.flavor.get('id')
if server.flavor.get('id') in evac_flavors:
return True
if hasattr(server.image, 'get'):
if server.image.get('id') in evac_images:
return True
- logging.debug("Instance %s is not evacuable" % server.image.get('id'))
+ reason = reason +" and image "+server.image.get('id')
+
+ logging.debug("Instance is not evacuable: no match for %s" % reason)
return False
def _get_evacuable_flavors(connection):

View File

@ -0,0 +1,674 @@
From 59ae9d00060da5329d7ca538974498292bbe1d91 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Tue, 26 Jun 2018 10:18:29 -0300
Subject: [PATCH 1/7] fence_gce: add support for stackdriver logging
Add --logging option to enable sending logs to google stackdriver
---
agents/gce/fence_gce.py | 65 +++++++++++++++++++++++++++++++++++++--
tests/data/metadata/fence_gce.xml | 5 +++
2 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 3abb5207..3af5bfc8 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -1,12 +1,19 @@
#!@PYTHON@ -tt
import atexit
+import logging
+import platform
import sys
+import time
sys.path.append("@FENCEAGENTSLIBDIR@")
import googleapiclient.discovery
from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action
+
+LOGGER = logging
+
+
def translate_status(instance_status):
"Returns on | off | unknown."
if instance_status == "RUNNING":
@@ -27,6 +34,7 @@ def get_nodes_list(conn, options):
return result
+
def get_power_status(conn, options):
try:
instance = conn.instances().get(
@@ -38,18 +46,37 @@ def get_power_status(conn, options):
fail_usage("Failed: get_power_status: {}".format(str(err)))
+def wait_for_operation(conn, project, zone, operation):
+ while True:
+ result = conn.zoneOperations().get(
+ project=project,
+ zone=zone,
+ operation=operation['name']).execute()
+ if result['status'] == 'DONE':
+ if 'error' in result:
+ raise Exception(result['error'])
+ return
+ time.sleep(1)
+
+
def set_power_status(conn, options):
try:
if options["--action"] == "off":
- conn.instances().stop(
+ LOGGER.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"]))
+ operation = conn.instances().stop(
project=options["--project"],
zone=options["--zone"],
instance=options["--plug"]).execute()
+ wait_for_operation(conn, options["--project"], options["--zone"], operation)
+ LOGGER.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"]))
elif options["--action"] == "on":
- conn.instances().start(
+ LOGGER.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"]))
+ operation = conn.instances().start(
project=options["--project"],
zone=options["--zone"],
instance=options["--plug"]).execute()
+ wait_for_operation(conn, options["--project"], options["--zone"], operation)
+ LOGGER.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"]))
except Exception as err:
fail_usage("Failed: set_power_status: {}".format(str(err)))
@@ -71,11 +98,24 @@ def define_new_opts():
"required" : "1",
"order" : 3
}
+ all_opt["logging"] = {
+ "getopt" : ":",
+ "longopt" : "logging",
+ "help" : "--logging=[bool] Logging, true/false",
+ "shortdesc" : "Stackdriver-logging support.",
+ "longdesc" : "If enabled (set to true), IP failover logs will be posted to stackdriver logging.",
+ "required" : "0",
+ "default" : "false",
+ "order" : 4
+ }
def main():
conn = None
+ global LOGGER
+
+ hostname = platform.node()
- device_opt = ["port", "no_password", "zone", "project"]
+ device_opt = ["port", "no_password", "zone", "project", "logging"]
atexit.register(atexit_handler)
@@ -97,6 +137,25 @@ def main():
run_delay(options)
+ # Prepare logging
+ logging_env = options.get('--logging')
+ if logging_env:
+ logging_env = logging_env.lower()
+ if any(x in logging_env for x in ['yes', 'true', 'enabled']):
+ try:
+ import google.cloud.logging.handlers
+ client = google.cloud.logging.Client()
+ handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname)
+ formatter = logging.Formatter('gcp:stonish "%(message)s"')
+ LOGGER = logging.getLogger(hostname)
+ handler.setFormatter(formatter)
+ LOGGER.addHandler(handler)
+ LOGGER.setLevel(logging.INFO)
+ except ImportError:
+ LOGGER.error('Couldn\'t import google.cloud.logging, '
+ 'disabling Stackdriver-logging support')
+
+ # Prepare cli
try:
credentials = None
if tuple(googleapiclient.__version__) < tuple("1.6.0"):
diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml
index 2a147f21..805ecc6b 100644
--- a/tests/data/metadata/fence_gce.xml
+++ b/tests/data/metadata/fence_gce.xml
@@ -30,6 +30,11 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui
<content type="string" />
<shortdesc lang="en">Project ID.</shortdesc>
</parameter>
+ <parameter name="logging" unique="0" required="0">
+ <getopt mixed="--logging=[bool]" />
+ <content type="string" default="false" />
+ <shortdesc lang="en">Stackdriver-logging support.</shortdesc>
+ </parameter>
<parameter name="quiet" unique="0" required="0">
<getopt mixed="-q, --quiet" />
<content type="boolean" />
From bb34acd8b0b150599c393d56dd81a7d8185b27d3 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Tue, 26 Jun 2018 10:44:41 -0300
Subject: [PATCH 2/7] fence_gce: set project and zone as not required
Try to retrieve the GCE project if the script is being executed inside a
GCE machine if --project is not provided.
Try to retrieve the zone automatically from GCE if --zone is not
provided.
---
agents/gce/fence_gce.py | 63 +++++++++++++++++++++++++++++++++++++--
tests/data/metadata/fence_gce.xml | 4 +--
2 files changed, 63 insertions(+), 4 deletions(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 3af5bfc8..e53dc5a6 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -12,6 +12,8 @@
LOGGER = logging
+METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/'
+METADATA_HEADERS = {'Metadata-Flavor': 'Google'}
def translate_status(instance_status):
@@ -81,13 +83,56 @@ def set_power_status(conn, options):
fail_usage("Failed: set_power_status: {}".format(str(err)))
+def get_instance(conn, project, zone, instance):
+ request = conn.instances().get(
+ project=project, zone=zone, instance=instance)
+ return request.execute()
+
+
+def get_zone(conn, project, instance):
+ request = conn.instances().aggregatedList(project=project)
+ while request is not None:
+ response = request.execute()
+ zones = response.get('items', {})
+ for zone in zones.values():
+ for inst in zone.get('instances', []):
+ if inst['name'] == instance:
+ return inst['zone'].split("/")[-1]
+ request = conn.instances().aggregatedList_next(
+ previous_request=request, previous_response=response)
+ raise Exception("Unable to find instance %s" % (instance))
+
+
+def get_metadata(metadata_key, params=None, timeout=None):
+ """Performs a GET request with the metadata headers.
+
+ Args:
+ metadata_key: string, the metadata to perform a GET request on.
+ params: dictionary, the query parameters in the GET request.
+ timeout: int, timeout in seconds for metadata requests.
+
+ Returns:
+ HTTP response from the GET request.
+
+ Raises:
+ urlerror.HTTPError: raises when the GET request fails.
+ """
+ timeout = timeout or 60
+ metadata_url = os.path.join(METADATA_SERVER, metadata_key)
+ params = urlparse.urlencode(params or {})
+ url = '%s?%s' % (metadata_url, params)
+ request = urlrequest.Request(url, headers=METADATA_HEADERS)
+ request_opener = urlrequest.build_opener(urlrequest.ProxyHandler({}))
+ return request_opener.open(request, timeout=timeout * 1.1).read()
+
+
def define_new_opts():
all_opt["zone"] = {
"getopt" : ":",
"longopt" : "zone",
"help" : "--zone=[name] Zone, e.g. us-central1-b",
"shortdesc" : "Zone.",
- "required" : "1",
+ "required" : "0",
"order" : 2
}
all_opt["project"] = {
@@ -95,7 +140,7 @@ def define_new_opts():
"longopt" : "project",
"help" : "--project=[name] Project ID",
"shortdesc" : "Project ID.",
- "required" : "1",
+ "required" : "0",
"order" : 3
}
all_opt["logging"] = {
@@ -109,6 +154,7 @@ def define_new_opts():
"order" : 4
}
+
def main():
conn = None
global LOGGER
@@ -165,6 +211,19 @@ def main():
except Exception as err:
fail_usage("Failed: Create GCE compute v1 connection: {}".format(str(err)))
+ # Get project and zone
+ if not options.get("--project"):
+ try:
+ options["--project"] = get_metadata('project/project-id')
+ except Exception as err:
+ fail_usage("Failed retrieving GCE project. Please provide --project option: {}".format(str(err)))
+
+ if not options.get("--zone"):
+ try:
+ options["--zone"] = get_zone(conn, options['--project'], options['--plug'])
+ except Exception as err:
+ fail_usage("Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err)))
+
# Operate the fencing device
result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list)
sys.exit(result)
diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml
index 805ecc6b..507b8385 100644
--- a/tests/data/metadata/fence_gce.xml
+++ b/tests/data/metadata/fence_gce.xml
@@ -20,12 +20,12 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui
<content type="string" />
<shortdesc lang="en">Physical plug number on device, UUID or identification of machine</shortdesc>
</parameter>
- <parameter name="zone" unique="0" required="1">
+ <parameter name="zone" unique="0" required="0">
<getopt mixed="--zone=[name]" />
<content type="string" />
<shortdesc lang="en">Zone.</shortdesc>
</parameter>
- <parameter name="project" unique="0" required="1">
+ <parameter name="project" unique="0" required="0">
<getopt mixed="--project=[name]" />
<content type="string" />
<shortdesc lang="en">Project ID.</shortdesc>
From 8ae1af8068d1718a861a25bf954e14392384fa55 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Wed, 4 Jul 2018 09:25:46 -0300
Subject: [PATCH 3/7] fence_gce: add power cycle as default method
Add function to power cycle an instance and set cycle as the default
method to reboot.
---
agents/gce/fence_gce.py | 21 +++++++++++++++++++--
tests/data/metadata/fence_gce.xml | 8 ++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index e53dc5a6..3f77dc24 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -83,6 +83,21 @@ def set_power_status(conn, options):
fail_usage("Failed: set_power_status: {}".format(str(err)))
+def power_cycle(conn, options):
+ try:
+ LOGGER.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"]))
+ operation = conn.instances().reset(
+ project=options["--project"],
+ zone=options["--zone"],
+ instance=options["--plug"]).execute()
+ wait_for_operation(conn, options["--project"], options["--zone"], operation)
+ LOGGER.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"]))
+ return True
+ except Exception as err:
+ LOGGER.error("Failed: power_cycle: {}".format(str(err)))
+ return False
+
+
def get_instance(conn, project, zone, instance):
request = conn.instances().get(
project=project, zone=zone, instance=instance)
@@ -161,13 +176,15 @@ def main():
hostname = platform.node()
- device_opt = ["port", "no_password", "zone", "project", "logging"]
+ device_opt = ["port", "no_password", "zone", "project", "logging", "method"]
atexit.register(atexit_handler)
define_new_opts()
all_opt["power_timeout"]["default"] = "60"
+ all_opt["method"]["default"] = "cycle"
+ all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)"
options = check_input(device_opt, process_input(device_opt))
@@ -225,7 +242,7 @@ def main():
fail_usage("Failed retrieving GCE zone. Please provide --zone option: {}".format(str(err)))
# Operate the fencing device
- result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list)
+ result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list, power_cycle)
sys.exit(result)
if __name__ == "__main__":
diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml
index 507b8385..f522550f 100644
--- a/tests/data/metadata/fence_gce.xml
+++ b/tests/data/metadata/fence_gce.xml
@@ -10,6 +10,14 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui
<content type="string" default="reboot" />
<shortdesc lang="en">Fencing action</shortdesc>
</parameter>
+ <parameter name="method" unique="0" required="0">
+ <getopt mixed="-m, --method=[method]" />
+ <content type="select" default="cycle" >
+ <option value="onoff" />
+ <option value="cycle" />
+ </content>
+ <shortdesc lang="en">Method to fence</shortdesc>
+ </parameter>
<parameter name="plug" unique="0" required="1" obsoletes="port">
<getopt mixed="-n, --plug=[id]" />
<content type="string" />
From 68644764695b79a3b75826fe009ea7da675677f7 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Thu, 5 Jul 2018 11:04:32 -0300
Subject: [PATCH 4/7] fence_gce: add missing imports to retrieve the project
---
agents/gce/fence_gce.py | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 3f77dc24..9b7b5e55 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -2,9 +2,18 @@
import atexit
import logging
+import os
import platform
import sys
import time
+if sys.version_info >= (3, 0):
+ # Python 3 imports.
+ import urllib.parse as urlparse
+ import urllib.request as urlrequest
+else:
+ # Python 2 imports.
+ import urllib as urlparse
+ import urllib2 as urlrequest
sys.path.append("@FENCEAGENTSLIBDIR@")
import googleapiclient.discovery
From f8f3f11187341622c26e4e439dfda6a37ad660b0 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Thu, 5 Jul 2018 11:05:32 -0300
Subject: [PATCH 5/7] fence_gce: s/--loging/--stackdriver-logging/
---
agents/gce/fence_gce.py | 42 ++++++++++++++++++---------------------
tests/data/metadata/fence_gce.xml | 11 +++++++---
2 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 9b7b5e55..a6befe39 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -167,14 +167,13 @@ def define_new_opts():
"required" : "0",
"order" : 3
}
- all_opt["logging"] = {
- "getopt" : ":",
- "longopt" : "logging",
- "help" : "--logging=[bool] Logging, true/false",
+ all_opt["stackdriver-logging"] = {
+ "getopt" : "",
+ "longopt" : "stackdriver-logging",
+ "help" : "--stackdriver-logging Enable Logging to Stackdriver",
"shortdesc" : "Stackdriver-logging support.",
- "longdesc" : "If enabled (set to true), IP failover logs will be posted to stackdriver logging.",
+ "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging.",
"required" : "0",
- "default" : "false",
"order" : 4
}
@@ -185,7 +184,7 @@ def main():
hostname = platform.node()
- device_opt = ["port", "no_password", "zone", "project", "logging", "method"]
+ device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", "method"]
atexit.register(atexit_handler)
@@ -210,22 +209,19 @@ def main():
run_delay(options)
# Prepare logging
- logging_env = options.get('--logging')
- if logging_env:
- logging_env = logging_env.lower()
- if any(x in logging_env for x in ['yes', 'true', 'enabled']):
- try:
- import google.cloud.logging.handlers
- client = google.cloud.logging.Client()
- handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname)
- formatter = logging.Formatter('gcp:stonish "%(message)s"')
- LOGGER = logging.getLogger(hostname)
- handler.setFormatter(formatter)
- LOGGER.addHandler(handler)
- LOGGER.setLevel(logging.INFO)
- except ImportError:
- LOGGER.error('Couldn\'t import google.cloud.logging, '
- 'disabling Stackdriver-logging support')
+ if options.get('--stackdriver-logging'):
+ try:
+ import google.cloud.logging.handlers
+ client = google.cloud.logging.Client()
+ handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname)
+ formatter = logging.Formatter('gcp:stonish "%(message)s"')
+ LOGGER = logging.getLogger(hostname)
+ handler.setFormatter(formatter)
+ LOGGER.addHandler(handler)
+ LOGGER.setLevel(logging.INFO)
+ except ImportError:
+ LOGGER.error('Couldn\'t import google.cloud.logging, '
+ 'disabling Stackdriver-logging support')
# Prepare cli
try:
diff --git a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml
index f522550f..79b82ebb 100644
--- a/tests/data/metadata/fence_gce.xml
+++ b/tests/data/metadata/fence_gce.xml
@@ -38,9 +38,14 @@ For instructions see: https://cloud.google.com/compute/docs/tutorials/python-gui
<content type="string" />
<shortdesc lang="en">Project ID.</shortdesc>
</parameter>
- <parameter name="logging" unique="0" required="0">
- <getopt mixed="--logging=[bool]" />
- <content type="string" default="false" />
+ <parameter name="stackdriver-logging" unique="0" required="0" deprecated="1">
+ <getopt mixed="--stackdriver-logging" />
+ <content type="boolean" />
+ <shortdesc lang="en">Stackdriver-logging support.</shortdesc>
+ </parameter>
+ <parameter name="stackdriver_logging" unique="0" required="0" obsoletes="stackdriver-logging">
+ <getopt mixed="--stackdriver-logging" />
+ <content type="boolean" />
<shortdesc lang="en">Stackdriver-logging support.</shortdesc>
</parameter>
<parameter name="quiet" unique="0" required="0">
From 9ae0a072424fa982e1d18a2cb661628c38601c3a Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Sat, 7 Jul 2018 18:42:01 -0300
Subject: [PATCH 6/7] fence_gce: use root logger for stackdriver
---
agents/gce/fence_gce.py | 29 +++++++++++++++--------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index a6befe39..1d5095ae 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -20,7 +20,6 @@
from fencing import fail_usage, run_delay, all_opt, atexit_handler, check_input, process_input, show_docs, fence_action
-LOGGER = logging
METADATA_SERVER = 'http://metadata.google.internal/computeMetadata/v1/'
METADATA_HEADERS = {'Metadata-Flavor': 'Google'}
@@ -73,37 +72,37 @@ def wait_for_operation(conn, project, zone, operation):
def set_power_status(conn, options):
try:
if options["--action"] == "off":
- LOGGER.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"]))
+ logging.info("Issuing poweroff of %s in zone %s" % (options["--plug"], options["--zone"]))
operation = conn.instances().stop(
project=options["--project"],
zone=options["--zone"],
instance=options["--plug"]).execute()
wait_for_operation(conn, options["--project"], options["--zone"], operation)
- LOGGER.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"]))
+ logging.info("Poweroff of %s in zone %s complete" % (options["--plug"], options["--zone"]))
elif options["--action"] == "on":
- LOGGER.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"]))
+ logging.info("Issuing poweron of %s in zone %s" % (options["--plug"], options["--zone"]))
operation = conn.instances().start(
project=options["--project"],
zone=options["--zone"],
instance=options["--plug"]).execute()
wait_for_operation(conn, options["--project"], options["--zone"], operation)
- LOGGER.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"]))
+ logging.info("Poweron of %s in zone %s complete" % (options["--plug"], options["--zone"]))
except Exception as err:
fail_usage("Failed: set_power_status: {}".format(str(err)))
def power_cycle(conn, options):
try:
- LOGGER.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"]))
+ logging.info('Issuing reset of %s in zone %s' % (options["--plug"], options["--zone"]))
operation = conn.instances().reset(
project=options["--project"],
zone=options["--zone"],
instance=options["--plug"]).execute()
wait_for_operation(conn, options["--project"], options["--zone"], operation)
- LOGGER.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"]))
+ logging.info('Reset of %s in zone %s complete' % (options["--plug"], options["--zone"]))
return True
except Exception as err:
- LOGGER.error("Failed: power_cycle: {}".format(str(err)))
+ logging.error("Failed: power_cycle: {}".format(str(err)))
return False
@@ -180,7 +179,6 @@ def define_new_opts():
def main():
conn = None
- global LOGGER
hostname = platform.node()
@@ -209,18 +207,21 @@ def main():
run_delay(options)
# Prepare logging
- if options.get('--stackdriver-logging'):
+ if options.get('--stackdriver-logging') is not None:
try:
import google.cloud.logging.handlers
client = google.cloud.logging.Client()
handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname)
+ handler.setLevel(logging.INFO)
formatter = logging.Formatter('gcp:stonish "%(message)s"')
- LOGGER = logging.getLogger(hostname)
handler.setFormatter(formatter)
- LOGGER.addHandler(handler)
- LOGGER.setLevel(logging.INFO)
+ root_logger = logging.getLogger()
+ if options.get('--verbose') is None:
+ root_logger.setLevel(logging.INFO)
+ logging.getLogger("googleapiclient").setLevel(logging.ERROR)
+ root_logger.addHandler(handler)
except ImportError:
- LOGGER.error('Couldn\'t import google.cloud.logging, '
+ logging.error('Couldn\'t import google.cloud.logging, '
'disabling Stackdriver-logging support')
# Prepare cli
From a52e643708908539d6e5fdb5d36a6cea935e4481 Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Wed, 11 Jul 2018 17:16:49 -0300
Subject: [PATCH 7/7] fence_gce: minor changes in logging
- Remove hostname (use --plug instead).
- Supress messages from googleapiclient and oauth2client if not error in
non verbose mode.
- s/stonish/stonith
---
agents/gce/fence_gce.py | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 1d5095ae..3eca0139 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -3,7 +3,6 @@
import atexit
import logging
import os
-import platform
import sys
import time
if sys.version_info >= (3, 0):
@@ -180,8 +179,6 @@ def define_new_opts():
def main():
conn = None
- hostname = platform.node()
-
device_opt = ["port", "no_password", "zone", "project", "stackdriver-logging", "method"]
atexit.register(atexit_handler)
@@ -207,18 +204,20 @@ def main():
run_delay(options)
# Prepare logging
- if options.get('--stackdriver-logging') is not None:
+ if options.get('--verbose') is None:
+ logging.getLogger('googleapiclient').setLevel(logging.ERROR)
+ logging.getLogger('oauth2client').setLevel(logging.ERROR)
+ if options.get('--stackdriver-logging') is not None and options.get('--plug'):
try:
import google.cloud.logging.handlers
client = google.cloud.logging.Client()
- handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=hostname)
+ handler = google.cloud.logging.handlers.CloudLoggingHandler(client, name=options['--plug'])
handler.setLevel(logging.INFO)
- formatter = logging.Formatter('gcp:stonish "%(message)s"')
+ formatter = logging.Formatter('gcp:stonith "%(message)s"')
handler.setFormatter(formatter)
root_logger = logging.getLogger()
if options.get('--verbose') is None:
root_logger.setLevel(logging.INFO)
- logging.getLogger("googleapiclient").setLevel(logging.ERROR)
root_logger.addHandler(handler)
except ImportError:
logging.error('Couldn\'t import google.cloud.logging, '

View File

@ -0,0 +1,25 @@
From 8e801d513b9a500ac0d717476aadc1cdabc0a92e Mon Sep 17 00:00:00 2001
From: Helen Koike <helen.koike@collabora.com>
Date: Thu, 19 Jul 2018 13:13:53 -0300
Subject: [PATCH] fence_gce: filter call to aggregatedList
Don't list all the instances in the project, filter only the one we are
interested in.
---
agents/gce/fence_gce.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
index 3eca0139..93cd1180 100644
--- a/agents/gce/fence_gce.py
+++ b/agents/gce/fence_gce.py
@@ -112,7 +112,8 @@ def get_instance(conn, project, zone, instance):
def get_zone(conn, project, instance):
- request = conn.instances().aggregatedList(project=project)
+ fl = 'name="%s"' % instance
+ request = conn.instances().aggregatedList(project=project, filter=fl)
while request is not None:
response = request.execute()
zones = response.get('items', {})

View File

@ -0,0 +1,34 @@
diff -uNr a/agents/gce/fence_gce.py b/agents/gce/fence_gce.py
--- a/agents/gce/fence_gce.py 2018-07-30 16:09:45.811531118 +0200
+++ b/agents/gce/fence_gce.py 2018-07-30 16:31:28.970202508 +0200
@@ -174,9 +174,9 @@
all_opt["stackdriver-logging"] = {
"getopt" : "",
"longopt" : "stackdriver-logging",
- "help" : "--stackdriver-logging Enable Logging to Stackdriver",
- "shortdesc" : "Stackdriver-logging support.",
- "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging.",
+ "help" : "--stackdriver-logging Enable Logging to Stackdriver. Using stackdriver logging requires additional libraries (google-cloud-logging).",
+ "shortdesc" : "Stackdriver-logging support. Requires additional libraries (google-cloud-logging).",
+ "longdesc" : "If enabled IP failover logs will be posted to stackdriver logging. Using stackdriver logging requires additional libraries (google-cloud-logging).",
"required" : "0",
"order" : 4
}
diff -uNr a/tests/data/metadata/fence_gce.xml b/tests/data/metadata/fence_gce.xml
--- a/tests/data/metadata/fence_gce.xml 2018-07-30 16:09:45.548532576 +0200
+++ b/tests/data/metadata/fence_gce.xml 2018-07-30 16:32:05.392988450 +0200
@@ -41,12 +41,12 @@
<parameter name="stackdriver-logging" unique="0" required="0" deprecated="1">
<getopt mixed="--stackdriver-logging" />
<content type="boolean" />
- <shortdesc lang="en">Stackdriver-logging support.</shortdesc>
+ <shortdesc lang="en">Stackdriver-logging support. Requires additional libraries (google-cloud-logging).</shortdesc>
</parameter>
<parameter name="stackdriver_logging" unique="0" required="0" obsoletes="stackdriver-logging">
<getopt mixed="--stackdriver-logging" />
<content type="boolean" />
- <shortdesc lang="en">Stackdriver-logging support.</shortdesc>
+ <shortdesc lang="en">Stackdriver-logging support. Requires additional libraries (google-cloud-logging).</shortdesc>
</parameter>
<parameter name="quiet" unique="0" required="0">
<getopt mixed="-q, --quiet" />

View File

@ -0,0 +1,26 @@
From bd1b11884f33f5fce5ca7618c9f87b540592e1b6 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Mon, 2 Jul 2018 16:36:41 +0200
Subject: [PATCH] fence_ilo3/fence_ipmilan: show correct default method (onoff)
in help
---
agents/ipmilan/fence_ipmilan.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/ipmilan/fence_ipmilan.py b/agents/ipmilan/fence_ipmilan.py
index 453d7365..9610f1c6 100644
--- a/agents/ipmilan/fence_ipmilan.py
+++ b/agents/ipmilan/fence_ipmilan.py
@@ -171,7 +171,7 @@ def main():
all_opt["lanplus"]["default"] = "1"
all_opt["ipport"]["default"] = "623"
- all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)\n" \
+ all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: onoff)\n" \
"WARNING! This fence agent might report success before the node is powered off. " \
"You should use -m/method onoff if your fence device works correctly with that option."
--
2.17.1

View File

@ -0,0 +1,33 @@
diff -uNr a/agents/ilo_ssh/fence_ilo_ssh.py b/agents/ilo_ssh/fence_ilo_ssh.py
--- a/agents/ilo_ssh/fence_ilo_ssh.py 2018-06-18 12:14:35.000000000 +0200
+++ b/agents/ilo_ssh/fence_ilo_ssh.py 2018-06-28 12:26:14.274615003 +0200
@@ -54,7 +54,8 @@
device via ssh and reboot a specified outlet. "
docs["vendorurl"] = "http://www.hp.com"
docs["symlink"] = [("fence_ilo3_ssh", "Fence agent for HP iLO3 over SSH"),
- ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH")]
+ ("fence_ilo4_ssh", "Fence agent for HP iLO4 over SSH"),
+ ("fence_ilo5_ssh", "Fence agent for HP iLO5 over SSH")]
show_docs(options, docs)
options["eol"] = "\r"
diff -uNr a/agents/ipmilan/fence_ipmilan.py b/agents/ipmilan/fence_ipmilan.py
--- a/agents/ipmilan/fence_ipmilan.py 2018-06-18 12:14:35.000000000 +0200
+++ b/agents/ipmilan/fence_ipmilan.py 2018-06-28 12:26:14.275614990 +0200
@@ -169,6 +169,8 @@
all_opt["lanplus"]["default"] = "1"
elif os.path.basename(sys.argv[0]) == "fence_ilo4":
all_opt["lanplus"]["default"] = "1"
+ elif os.path.basename(sys.argv[0]) == "fence_ilo5":
+ all_opt["lanplus"]["default"] = "1"
all_opt["ipport"]["default"] = "623"
all_opt["method"]["help"] = "-m, --method=[method] Method to fence (onoff|cycle) (Default: cycle)\n" \
@@ -187,6 +189,7 @@
docs["vendorurl"] = ""
docs["symlink"] = [("fence_ilo3", "Fence agent for HP iLO3"),
("fence_ilo4", "Fence agent for HP iLO4"),
+ ("fence_ilo5", "Fence agent for HP iLO5"),
("fence_imm", "Fence agent for IBM Integrated Management Module"),
("fence_idrac", "Fence agent for Dell iDRAC")]
show_docs(options, docs)

View File

@ -0,0 +1,36 @@
From ac83d8ce3d8dd868b0e887528e7c269cee4dcac8 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 31 Jul 2018 15:57:38 +0200
Subject: [PATCH] fence_kdump: fix strncpy issue
---
agents/kdump/fence_kdump.c | 2 +-
agents/kdump/fence_kdump_send.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/agents/kdump/fence_kdump.c b/agents/kdump/fence_kdump.c
index e2f3cd80..768a9344 100644
--- a/agents/kdump/fence_kdump.c
+++ b/agents/kdump/fence_kdump.c
@@ -351,7 +351,7 @@ get_options_node (fence_kdump_opts_t *opts)
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICSERV;
- strncpy (node->name, opts->nodename, sizeof (node->name));
+ strncpy (node->name, opts->nodename, sizeof (node->name) - 1);
snprintf (node->port, sizeof (node->port), "%d", opts->ipport);
node->info = NULL;
diff --git a/agents/kdump/fence_kdump_send.c b/agents/kdump/fence_kdump_send.c
index d668bed3..638f8c97 100644
--- a/agents/kdump/fence_kdump_send.c
+++ b/agents/kdump/fence_kdump_send.c
@@ -116,7 +116,7 @@ get_options_node (fence_kdump_opts_t *opts)
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICSERV;
- strncpy (node->name, opts->nodename, sizeof (node->name));
+ strncpy (node->name, opts->nodename, sizeof (node->name) - 1);
snprintf (node->port, sizeof (node->port), "%d", opts->ipport);
node->info = NULL;

View File

@ -0,0 +1,176 @@
From 199b1efee0ba1f01c27ca689a15465cf4a258ee6 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Mon, 22 Jan 2018 11:27:28 +0100
Subject: [PATCH] fence_mpath: add watchdog support
---
agents/Makefile.am | 11 ++++++++
agents/mpath/fence_mpath.py | 50 ++++++++++++++++++++++++++++++++++---
configure.ac | 6 +++++
make/fencebuild.mk | 2 +-
tests/data/metadata/fence_mpath.xml | 2 +-
5 files changed, 66 insertions(+), 5 deletions(-)
diff --git a/agents/Makefile.am b/agents/Makefile.am
index 2524a3ab..833d2af5 100644
--- a/agents/Makefile.am
+++ b/agents/Makefile.am
@@ -50,6 +50,11 @@ zvm_fence_zvm_SOURCES = zvm/fence_zvm.c
zvm_fence_zvm_CFLAGS = -D_GNU_SOURCE -Izvm
endif
+if BUILD_FENCE_MPATH
+mpathdatadir = $(CLUSTERDATA)
+mpathdata_SCRIPTS = mpath/fence_mpath_check mpath/fence_mpath_check_hardreboot
+endif
+
if BUILD_FENCE_SCSI
scsidatadir = $(CLUSTERDATA)
scsidata_SCRIPTS = scsi/fence_scsi_check scsi/fence_scsi_check_hardreboot
@@ -72,6 +77,12 @@ manual/fence_ack_manual: manual/fence_ack_manual.in
-e 's#@clustervarrun@#${CLUSTERVARRUN}#g' \
> $@
+mpath/fence_mpath_check: mpath/fence_mpath
+ cp $^ $@
+
+mpath/fence_mpath_check_hardreboot: mpath/fence_mpath
+ cp $^ $@
+
scsi/fence_scsi_check: scsi/fence_scsi
cp $^ $@
diff --git a/agents/mpath/fence_mpath.py b/agents/mpath/fence_mpath.py
index ac5bc794..d9ac2ef5 100644
--- a/agents/mpath/fence_mpath.py
+++ b/agents/mpath/fence_mpath.py
@@ -143,25 +143,63 @@ def dev_write(options, dev):
store_fh.write(dev + "\t" + options["--key"] + "\n")
store_fh.close()
-def dev_read(options):
+def dev_read(options, fail=True):
dev_key = {}
file_path = options["--store-path"] + "/mpath.devices"
try:
store_fh = open(file_path, "r")
except IOError:
- fail_usage("Failed: Cannot open file \"" + file_path + "\"")
+ if fail:
+ fail_usage("Failed: Cannot open file \"" + file_path + "\"")
+ else:
+ return None
# get not empty lines from file
for (device, key) in [line.strip().split() for line in store_fh if line.strip()]:
dev_key[device] = key
store_fh.close()
return dev_key
+def mpath_check_get_verbose():
+ try:
+ f = open("/etc/sysconfig/watchdog", "r")
+ except IOError:
+ return False
+ match = re.search(r"^\s*verbose=yes", "".join(f.readlines()), re.MULTILINE)
+ f.close()
+ return bool(match)
+
+def mpath_check(hardreboot=False):
+ if len(sys.argv) >= 3 and sys.argv[1] == "repair":
+ return int(sys.argv[2])
+ options = {}
+ options["--mpathpersist-path"] = "/usr/sbin/mpathpersist"
+ options["--store-path"] = "/var/run/cluster"
+ options["--power-timeout"] = "5"
+ if mpath_check_get_verbose():
+ logging.getLogger().setLevel(logging.DEBUG)
+ devs = dev_read(options, fail=False)
+ if not devs:
+ logging.error("No devices found")
+ return 0
+ for dev, key in list(devs.items()):
+ if key in get_registration_keys(options, dev):
+ logging.debug("key " + key + " registered with device " + dev)
+ return 0
+ else:
+ logging.debug("key " + key + " not registered with device " + dev)
+ logging.debug("key " + key + " registered with any devices")
+
+ if hardreboot == True:
+ libc = ctypes.cdll['libc.so.6']
+ libc.reboot(0x1234567)
+ return 2
+
def define_new_opts():
all_opt["devices"] = {
"getopt" : "d:",
"longopt" : "devices",
"help" : "-d, --devices=[devices] List of devices to use for current operation",
- "required" : "1",
+ "required" : "0",
"shortdesc" : "List of devices to use for current operation. Devices can \
be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). \
Each device must support SCSI-3 persistent reservations.",
@@ -205,6 +243,12 @@ def main():
define_new_opts()
+ # fence_mpath_check
+ if os.path.basename(sys.argv[0]) == "fence_mpath_check":
+ sys.exit(mpath_check())
+ elif os.path.basename(sys.argv[0]) == "fence_mpath_check_hardreboot":
+ sys.exit(mpath_check(hardreboot=True))
+
options = check_input(device_opt, process_input(device_opt), other_conditions=True)
docs = {}
diff --git a/configure.ac b/configure.ac
index e8b24211..24b857b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -148,6 +148,11 @@ if echo "$AGENTS_LIST" | grep -q -E "all|manual"; then
AGENTS_LIST=$(echo "$AGENTS_LIST" | sed -E "s/manual( |$)//")
fi
+FENCE_MPATH=0
+if echo "$AGENTS_LIST" | grep -q -E "all|mpath"; then
+ FENCE_MPATH=1
+fi
+
FENCE_SCSI=0
if echo "$AGENTS_LIST" | grep -q -E "all|scsi"; then
FENCE_SCSI=1
@@ -312,6 +317,7 @@ AC_SUBST([SNMPBIN])
AC_SUBST([AGENTS_LIST])
AM_CONDITIONAL(BUILD_FENCE_KDUMP, test $FENCE_KDUMP -eq 1)
AM_CONDITIONAL(BUILD_FENCE_MANUAL, test $FENCE_MANUAL -eq 1)
+AM_CONDITIONAL(BUILD_FENCE_MPATH, test $FENCE_MPATH -eq 1)
AM_CONDITIONAL(BUILD_FENCE_SCSI, test $FENCE_SCSI -eq 1)
AM_CONDITIONAL(BUILD_FENCE_ZVM, test $FENCE_ZVM -eq 1)
AM_CONDITIONAL(BUILD_XENAPILIB, test $XENAPILIB -eq 1)
diff --git a/make/fencebuild.mk b/make/fencebuild.mk
index e08d5200..6a7c6f63 100644
--- a/make/fencebuild.mk
+++ b/make/fencebuild.mk
@@ -51,7 +51,7 @@ $(TARGET):
$(call gen_agent_from_py)
clean: clean-man
- rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(scsidata_SCRIPTS) */*.pyc *.pyc */*.wiki
+ rm -f $(CLEAN_TARGET:%.8=%) $(CLEAN_TARGET_ADDITIONAL) $(mpathdata_SCRIPTS) $(scsidata_SCRIPTS) */*.pyc */*.wiki
if [ "$(abs_builddir)" = "$(abs_top_builddir)/lib" ]; then \
rm -f $(TARGET); \
diff --git a/tests/data/metadata/fence_mpath.xml b/tests/data/metadata/fence_mpath.xml
index f384e50b..bbe9ad2b 100644
--- a/tests/data/metadata/fence_mpath.xml
+++ b/tests/data/metadata/fence_mpath.xml
@@ -9,7 +9,7 @@ The fence_mpath agent works by having a unique key for each node that has to be
<content type="string" default="off" />
<shortdesc lang="en">Fencing action</shortdesc>
</parameter>
- <parameter name="devices" unique="0" required="1">
+ <parameter name="devices" unique="0" required="0">
<getopt mixed="-d, --devices=[devices]" />
<content type="string" />
<shortdesc lang="en">List of devices to use for current operation. Devices can be comma-separated list of device-mapper multipath devices (eg. /dev/mapper/3600508b400105df70000e00000ac0000 or /dev/mapper/mpath1). Each device must support SCSI-3 persistent reservations.</shortdesc>

10
SOURCES/fix-version.patch Normal file
View File

@ -0,0 +1,10 @@
diff -uNr a/.tarball-version b/.tarball-version
--- a/.tarball-version 1970-01-01 01:00:00.000000000 +0100
+++ b/.tarball-version 2018-08-20 10:42:03.876068353 +0200
@@ -0,0 +1 @@
+4.2.1
diff -uNr a/.version b/.version
--- a/.version 1970-01-01 01:00:00.000000000 +0100
+++ b/.version 2018-08-20 10:52:35.712060731 +0200
@@ -0,0 +1 @@
+4.2.1

View File

@ -0,0 +1,74 @@
From 29f93ed6f7f79cad801bf08ad9172c8a62183435 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Tue, 14 Aug 2018 12:33:41 +0200
Subject: [PATCH] fence_compute/fence_evacuate/fence_rhevm: dont use has_key
(not supported in Python 3)
---
agents/compute/fence_compute.py | 4 ++--
agents/evacuate/fence_evacuate.py | 4 ++--
agents/rhevm/fence_rhevm.py | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py
index ec2d093c..254e2670 100644
--- a/agents/compute/fence_compute.py
+++ b/agents/compute/fence_compute.py
@@ -311,7 +311,7 @@ def create_nova_connection(options):
region_name=options["--region-name"],
endpoint_type=options["--endpoint-type"],
session=keystone_session, auth=keystone_auth,
- http_log_debug=options.has_key("--verbose"))
+ http_log_debug="--verbose" in options)
else:
# OSP >= 11
# ArgSpec(args=['version'], varargs='args', keywords='kwargs', defaults=None)
@@ -319,7 +319,7 @@ def create_nova_connection(options):
region_name=options["--region-name"],
endpoint_type=options["--endpoint-type"],
session=keystone_session, auth=keystone_auth,
- http_log_debug=options.has_key("--verbose"))
+ http_log_debug="--verbose" in options)
try:
nova.hypervisors.list()
diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py
index 615dede7..6818c44f 100644
--- a/agents/evacuate/fence_evacuate.py
+++ b/agents/evacuate/fence_evacuate.py
@@ -245,7 +245,7 @@ def create_nova_connection(options):
region_name=options["--region-name"],
endpoint_type=options["--endpoint-type"],
session=keystone_session, auth=keystone_auth,
- http_log_debug=options.has_key("--verbose"))
+ http_log_debug="--verbose" in options)
else:
# OSP >= 11
# ArgSpec(args=['version'], varargs='args', keywords='kwargs', defaults=None)
@@ -253,7 +253,7 @@ def create_nova_connection(options):
region_name=options["--region-name"],
endpoint_type=options["--endpoint-type"],
session=keystone_session, auth=keystone_auth,
- http_log_debug=options.has_key("--verbose"))
+ http_log_debug="--verbose" in options)
try:
nova.hypervisors.list()
diff --git a/agents/rhevm/fence_rhevm.py b/agents/rhevm/fence_rhevm.py
index 0594e66b..c06b7c39 100644
--- a/agents/rhevm/fence_rhevm.py
+++ b/agents/rhevm/fence_rhevm.py
@@ -74,11 +74,11 @@ def send_command(opt, command, method="GET"):
url = "https:"
else:
url = "http:"
- if opt.has_key("--api-path"):
+ if "--api-path" in opt:
api_path = opt["--api-path"]
else:
api_path = "/ovirt-engine/api"
- if opt.has_key("--disable-http-filter"):
+ if "--disable-http-filter" in opt:
http_filter = 'false'
else:
http_filter = 'true'

1191
SPECS/fence-agents.spec Normal file

File diff suppressed because it is too large Load Diff