Resolve agent redfish compilation fail

This commit is contained in:
liqiuyu 2020-11-20 11:45:58 +08:00
parent 3b3a7211a7
commit 44639ffac9
48 changed files with 3819 additions and 12 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

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,23 @@
From 33a638ff624839d7fa2d409479c348abee57763e Mon Sep 17 00:00:00 2001
From: dwannamaker-onr <dwannamaker@onr.com>
Date: Tue, 25 Jun 2019 15:28:00 -0400
Subject: [PATCH] Fixed issue with SUSPENDED VMs
If any VMs in the vCenter are suspended, you get a KeyError because that state is not expected. This breaks list and monitor actions.
---
agents/vmware_rest/fence_vmware_rest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/vmware_rest/fence_vmware_rest.py b/agents/vmware_rest/fence_vmware_rest.py
index b544d385..53b4066d 100644
--- a/agents/vmware_rest/fence_vmware_rest.py
+++ b/agents/vmware_rest/fence_vmware_rest.py
@@ -8,7 +8,7 @@
from fencing import *
from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS
-state = {"POWERED_ON": "on", 'POWERED_OFF': "off"}
+state = {"POWERED_ON": "on", 'POWERED_OFF': "off", 'SUSPENDED': "off"}
def get_power_status(conn, options):
res = send_command(conn, "vcenter/vm?filter.names={}".format(options["--plug"]))["value"]

View File

@ -0,0 +1,43 @@
From 2735a4ee096f87fda2e94029db7f059d7be28464 Mon Sep 17 00:00:00 2001
From: Oyvind Albrigtsen <oalbrigt@redhat.com>
Date: Thu, 5 Sep 2019 10:28:18 +0200
Subject: [PATCH] fence_zvmip: fix Python 3 issues
---
agents/zvm/fence_zvmip.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/agents/zvm/fence_zvmip.py b/agents/zvm/fence_zvmip.py
index 5fbe53e4..e6bb01d1 100644
--- a/agents/zvm/fence_zvmip.py
+++ b/agents/zvm/fence_zvmip.py
@@ -37,7 +37,7 @@ def open_socket(options):
return conn
def smapi_pack_string(string):
- return struct.pack("!i%ds" % (len(string)), len(string), string)
+ return struct.pack("!i%ds" % (len(string)), len(string), string.encode("UTF-8"))
def prepare_smapi_command(options, smapi_function, additional_args):
packet_size = 3*INT4 + len(smapi_function) + len(options["--username"]) + len(options["--password"])
@@ -126,7 +126,7 @@ def get_list_of_images(options, command, data_as_plug):
data = ""
while True:
- read_data = conn.recv(1024, socket.MSG_WAITALL)
+ read_data = conn.recv(1024, socket.MSG_WAITALL).decode("UTF-8")
data += read_data
if array_len == len(data):
break
@@ -136,9 +136,9 @@ def get_list_of_images(options, command, data_as_plug):
parsed_len = 0
while parsed_len < array_len:
- string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4])[0]
+ string_len = struct.unpack("!i", data[parsed_len:parsed_len+INT4].encode("UTF-8"))[0]
parsed_len += INT4
- image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len])[0]
+ image_name = struct.unpack("!%ds" % (string_len), data[parsed_len:parsed_len+string_len].encode("UTF-8"))[0].decode("UTF-8")
parsed_len += string_len
images.add(image_name)

View File

@ -0,0 +1,42 @@
From 099758a41bbb153c4a13a89de57cdcb72e1f1ea7 Mon Sep 17 00:00:00 2001
From: Michele Baldessari <michele@acksyn.org>
Date: Fri, 11 Oct 2019 10:39:53 +0200
Subject: [PATCH] fence_compute: Invert the force-down/service disable order
In OpenStack Train we first observed that IHA was not working via
https://bugzilla.redhat.com/show_bug.cgi?id=1760213
The reason for this is that nova has made the disabling of the compute
service depend on the compute node being up via:
https://review.opendev.org/#/c/654596/
By first calling force-down, the subsequence service-disable API
call won't wait for the reachability of the compute node any
longer and the whole operation has the same outcome.
Tested this on an OSP Train environment and we correctly
got Instance HA working again and we observed the VMs being
restarted on the available compute nodes.
Co-Authored-By: Luca Miccini <lmiccini@redhat.com>
---
agents/compute/fence_compute.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py
index a94bdc46..c08a9dbe 100644
--- a/agents/compute/fence_compute.py
+++ b/agents/compute/fence_compute.py
@@ -117,11 +117,11 @@ def set_power_status_off(connection, options):
if status in [ "off" ]:
return
- connection.services.disable(options["--plug"], 'nova-compute')
try:
# Until 2.53
connection.services.force_down(
options["--plug"], "nova-compute", force_down=True)
+ connection.services.disable(options["--plug"], 'nova-compute')
except Exception as e:
# Something went wrong when we tried to force the host down.
# That could come from either an incompatible API version

Binary file not shown.

View File

@ -29,16 +29,57 @@
Name: fence-agents
Summary: Set of unified programs capable of host isolation ("fencing")
Version: 4.2.1
Release: 30%{?alphatag:.%{alphatag}}%{?dist}.1
License: GPLv2+ and LGPLv2+
Release: 31
License: GPLv2+ and LGPLv2+ and ASL 2.0 and BSD and MIT and Python-2.0 and Artistic-1.0-Perl
Group: System Environment/Base
URL: https://github.com/ClusterLabs/fence-agents
Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz
Source0: https://github.com/ClusterLabs/fence-agents/archive/v4.2.1.tar.gz
Source1: %{pycryptodome}-%{pycryptodome_version}.tar.gz
Source2: %{aliyunsdkcore}-%{aliyunsdkcore_version}.tar.gz
Source3: %{aliyunsdkecs}-%{aliyunsdkecs_version}.tar.gz
Source4: %{aliyunsdkvpc}-%{aliyunsdkvpc_version}.tar.gz
Patch0: fence_impilan-fence_ilo_ssh-add-ilo5-support.patch
Patch1: fence_mpath-watchdog-support.patch
Patch2: fence_ilo3-fence_ipmilan-show-correct-default-method.patch
Patch3: fence_evacuate-fix-evacuable-tag-mix-issue.patch
Patch4: fence_compute-fence_evacuate-fix-compute-domain.patch
Patch5: fence_gce-1-stackdriver-logging-default-method-cycle.patch
Patch6: fence_gce-2-filter-aggregatedlist.patch
Patch7: fence_aliyun-1.patch
Patch8: fence_aliyun-2.patch
Patch9: fence_aliyun-3-logging.patch
Patch10: fence_aliyun-4-bundled.patch
Patch11: python3-has_key-fixes.patch
Patch12: fence_kdump-fix-strncpy-issue.patch
Patch13: fix-version.patch
Patch14: fence_gce-3-stackdriver-logging-note.patch
Patch15: fence_aliyun-5-list-instance-names.patch
Patch16: fence_aliyun-6-correct-help-indentation.patch
Patch17: fence_cisco_ucs-encode-POSTFIELDS.patch
Patch18: bz1654968-fence_scsi-fix-incorrect-SCSI-key-node-ID-10-or-higher.patch
Patch19: bz1654976-1-fence_scsi-watchdog-retry-support.patch
Patch20: bz1654976-2-build-fix-check_used_options.patch
Patch21: bz1654616-fence_hpblade-fix-log_expect_syntax.patch
Patch22: bz1654973-fence_vmware_soap-cleanup-sigterm.patch
Patch23: bz1650214-fence_azure_arm-bundled.patch
Patch24: bz1666914-1-fence_redfish.patch
Patch25: bz1666914-2-fence_redfish-fail-invalid-cert.patch
Patch26: bz1677327-1-fence_redfish-use-ipport-parameter.patch
Patch27: bz1677327-2-fence_redfish-ip-parameter-backward-compatibility.patch
Patch28: bz1696584-fence_gce-fix-python3-encoding-issue.patch
Patch29: bz1709926-fence_mpath-fix-watchdog-hardreboot.patch
Patch30: bz1709780-fence_rhevm-RHEV-v4-API-support.patch
Patch31: bz1712263-fence_rhevm-1-use-UTF8-encoding.patch
Patch32: bz1712263-fence_rhevm-2-fix-debug-encoding-issues.patch
Patch33: bz1700546-fence_azure_arm-skip_shutdown.patch
Patch34: bz1704228-fence_redfish-full-redfish-spec-compliance.patch
Patch35: bz1714458-fence_scsi-node-id-new-format.patch
Patch36: bz1720198-fence_scsi-watchdog-fix-retry-failing-on-first-try.patch
Patch37: bz1732773-fence_vmware_rest-fix-keyerror-suspended-vms.patch
Patch38: bz1748443-fence_zvmip-python3-fixes.patch
Patch39: bz1762432-fence_compute-disable-service-after-force-down.patch
%if 0%{?fedora} || 0%{?rhel} > 7
%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan mpath kdump redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti
%ifarch x86_64
%global testagents virsh heuristics_ping aliyun aws azure_arm gce
@ -90,6 +131,7 @@ fence-agents-vmware-soap \\
fence-agents-wti \\
EOF)
%endif
# Build dependencies
## general
@ -113,6 +155,46 @@ BuildRequires: python3-google-api-client
%prep
%setup -q -n %{name}-%{version}
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%patch5 -p1
%patch6 -p1
%patch7 -p1
%patch8 -p1
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
%patch24 -p1
%patch25 -p1
%patch26 -p1
%patch27 -p1
%patch28 -p1
%patch29 -p1
%patch30 -p1 -F2
%patch31 -p1 -F2
%patch32 -p1
%patch33 -p1
%patch34 -p1
%patch35 -p1
%patch36 -p1 -F1
%patch37 -p1
%patch38 -p1
%patch39 -p1
# prevent compilation of something that won't get used anyway
sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac
@ -145,7 +227,7 @@ cp %{aliyunsdkvpc_dir}/README.rst %{aliyunsdkvpc}_README.rst
%build
./autogen.sh
%{configure} PYTHON="%{__python3}" --with-agents='%{supportedagents} %{testagents}'
%{configure} PYTHON="%{__python3}" --with-agents='amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan mpath kdump redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti virsh heuristics_ping aliyun aws azure_arm gce'
CFLAGS="$(echo '%{optflags}')" make %{_smp_mflags}
%ifarch x86_64
@ -242,7 +324,40 @@ This package contains support files including the Python fencing library.
License: GPLv2+ and LGPLv2+ and ASL 2.0
Group: System Environment/Base
Summary: Set of unified programs capable of host isolation ("fencing")
Requires: %(echo "%{allfenceagents}" | sed "s/\( \|$\)/ >= %{version}-%{release}\1/g")
Requires: fence-agents-amt-ws >= %{version}
Requires: fence-agents-apc >= %{version}
Requires: fence-agents-apc-snmp >= %{version}
Requires: fence-agents-bladecenter >= %{version}
Requires: fence-agents-brocade >= %{version}
Requires: fence-agents-cisco-mds >= %{version}
Requires: fence-agents-cisco-ucs >= %{version}
Requires: fence-agents-compute >= %{version}
Requires: fence-agents-drac5 >= %{version}
Requires: fence-agents-eaton-snmp >= %{version}
Requires: fence-agents-emerson >= %{version}
Requires: fence-agents-eps >= %{version}
Requires: fence-agents-heuristics-ping >= %{version}
Requires: fence-agents-hpblade >= %{version}
Requires: fence-agents-ibmblade >= %{version}
Requires: fence-agents-ifmib >= %{version}
Requires: fence-agents-ilo2 >= %{version}
Requires: fence-agents-ilo-moonshot >= %{version}
Requires: fence-agents-ilo-mp >= %{version}
Requires: fence-agents-ilo-ssh >= %{version}
Requires: fence-agents-intelmodular >= %{version}
Requires: fence-agents-ipdu >= %{version}
Requires: fence-agents-ipmilan >= %{version}
Requires: fence-agents-kdump >= %{version}
Requires: fence-agents-mpath >= %{version}
Requires: fence-agents-redfish >= %{version}
Requires: fence-agents-rhevm >= %{version}
Requires: fence-agents-rsa >= %{version}
Requires: fence-agents-rsb >= %{version}
Requires: fence-agents-sbd >= %{version}
Requires: fence-agents-scsi >= %{version}
Requires: fence-agents-vmware-rest >= %{version}
Requires: fence-agents-vmware-soap >= %{version}
Requires: fence-agents-wti >= %{version}
%ifarch i686 x86_64
Requires: fence-virt
%endif
@ -744,7 +859,7 @@ Fence agent for RHEV-M via REST API.
%{_sbindir}/fence_rhevm
%{_mandir}/man8/fence_rhevm.8*
%if 0%{?fedora} || 0%{?rhel} > 7
#%if 0%{?fedora} || 0%{?rhel} > 7
%package rsa
License: GPLv2+ and LGPLv2+
Group: System Environment/Base
@ -758,7 +873,7 @@ via telnet or SSH.
%files rsa
%{_sbindir}/fence_rsa
%{_mandir}/man8/fence_rsa.8*
%endif
#%endif
%package rsb
License: GPLv2+ and LGPLv2+
@ -774,7 +889,7 @@ via telnet or SSH.
%{_sbindir}/fence_rsb
%{_mandir}/man8/fence_rsb.8*
%if 0%{?fedora} || 0%{?rhel} > 7
#%if 0%{?fedora} || 0%{?rhel} > 7
%package sbd
License: GPLv2+ and LGPLv2+
Group: System Environment/Base
@ -787,7 +902,7 @@ Fence agent for SBD (storage-based death).
%files sbd
%{_sbindir}/fence_sbd
%{_mandir}/man8/fence_sbd.8*
%endif
#%endif
%package scsi
License: GPLv2+ and LGPLv2+
@ -872,7 +987,8 @@ Fence agent for IBM z/VM over IP.
%endif
%changelog
* Fri Oct 30 2020 liqiuyu <liqiuyu@kylinos.cn> - 4.2.1-31
- Resolve agent redfish compilation fail
* Thu Apr 16 2020 houjian<jian.hou@kylinos.cn> - 4.2.1-30.1
- Init fence-agents project
- Init fence-agents project

5
fence-agents.yaml Normal file
View File

@ -0,0 +1,5 @@
---
version_control: github
src_repo: ClusterLabs/fence-agents
tag_prefix: ^v
separator: "."

344
fence_aliyun-1.patch Normal file
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:

58
fence_aliyun-2.patch Normal file
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
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

Binary file not shown.

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'

BIN
v4.2.1.tar.gz Normal file

Binary file not shown.