Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/fence/agents/powerman/Makefile.am b/fence/agents/powerman/Makefile.am
new file mode 100644
index 00000000..99fe199d
--- /dev/null
+++ b/fence/agents/powerman/Makefile.am
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+TARGET = fence_powerman
+
+SRC = $(TARGET).py
+
+EXTRA_DIST = $(SRC)
+
+sbin_SCRIPTS = $(TARGET)
+
+man_MANS = $(TARGET).8
+
+FENCE_TEST_ARGS = -l test -p test -a test -n 1
+
+include $(top_srcdir)/make/fencebuild.mk
+include $(top_srcdir)/make/fenceman.mk
+include $(top_srcdir)/make/agentpycheck.mk
diff --git a/fence/agents/powerman/fence_powerman.8 b/fence/agents/powerman/fence_powerman.8
new file mode 100644
index 00000000..2923cdee
--- /dev/null
+++ b/fence/agents/powerman/fence_powerman.8
@@ -0,0 +1,221 @@
+
+.TH FENCE_AGENT 8 2009-10-20 "fence_powerman (Fence Agent)"
+.SH NAME
+fence_powerman - Fence Agent for Powerman
+.SH DESCRIPTION
+.P
+This is a Pacemaker Fence Agent for the Powerman management utility that was designed for LLNL systems.
+.P
+fence_powerman accepts options on the command line as well
+as from stdin. Fenced sends parameters through stdin when it execs the
+agent. fence_powerman can be run by itself with command
+line options. This is useful for testing and for turning outlets on or off
+from scripts.
+
+Vendor URL: https://github.com/chaos/powerman
+.SH PARAMETERS
+
+
+.TP
+.B -o, --action=[action]
+.
+Fencing action (Default Value: reboot)
+
+.TP
+.B -4, --inet4-only
+.
+Forces agent to use IPv4 addresses only
+
+.TP
+.B -6, --inet6-only
+.
+Forces agent to use IPv6 addresses only
+
+.TP
+.B -a, --ip=[ip]
+.
+IP address or hostname of fencing device
+
+.TP
+.B -u, --ipport=[port]
+.
+TCP/UDP port to use for connection with device (Default Value: 10101)
+
+.TP
+.B -n, --plug=[ip]
+.
+IP address or hostname of fencing device (together with --port-as-ip)
+
+.TP
+.B -v, --verbose
+.
+Verbose mode
+
+.TP
+.B -D, --debug-file=[debugfile]
+.
+Write debug information to given file
+
+.TP
+.B -V, --version
+.
+Display version information and exit
+
+.TP
+.B -h, --help
+.
+Display help and exit
+
+.TP
+.B --delay=[seconds]
+.
+Wait X seconds before fencing is started (Default Value: 3)
+
+.TP
+.B --login-timeout=[seconds]
+.
+Wait X seconds for cmd prompt after login (Default Value: 5)
+
+.TP
+.B --port-as-ip
+.
+Make "port/plug" to be an alias to IP address
+
+.TP
+.B --power-timeout=[seconds]
+.
+Test X seconds for status change after ON/OFF (Default Value: 20)
+
+.TP
+.B --power-wait=[seconds]
+.
+Wait X seconds after issuing ON/OFF (Default Value: 3)
+
+.TP
+.B --shell-timeout=[seconds]
+.
+Wait X seconds for cmd prompt after issuing command (Default Value: 3)
+
+.TP
+.B --retry-on=[attempts]
+.
+Count of attempts to retry power on (Default Value: 1)
+
+.SH ACTIONS
+
+
+.TP
+\fBon \fP
+Power on machine.
+
+.TP
+\fBoff \fP
+Power off machine.
+
+.TP
+\fBreboot \fP
+Reboot machine.
+
+.TP
+\fBstatus \fP
+This returns the status of the plug/virtual machine.
+
+.TP
+\fBmonitor \fP
+Check the health of fence device
+
+.TP
+\fBmetadata \fP
+Display the XML metadata describing this resource.
+
+.TP
+\fBvalidate-all \fP
+Validate if all required parameters are entered.
+
+.SH STDIN PARAMETERS
+
+
+.TP
+.B action
+.
+Fencing action (Default Value: reboot)
+
+.TP
+.B inet4_only
+.
+Forces agent to use IPv4 addresses only
+
+.TP
+.B inet6_only
+.
+Forces agent to use IPv6 addresses only
+
+.TP
+.B ipaddr
+.
+IP address or hostname of fencing device
+
+.TP
+.B ipport
+.
+TCP/UDP port to use for connection with device (Default Value: 10101)
+
+.TP
+.B port
+.
+IP address or hostname of fencing device (together with --port-as-ip)
+
+.TP
+.B verbose
+.
+Verbose mode
+
+.TP
+.B debug
+.
+Write debug information to given file
+
+.TP
+.B version
+.
+Display version information and exit
+
+.TP
+.B help
+.
+Display help and exit
+
+.TP
+.B delay
+.
+Wait X seconds before fencing is started (Default Value: 3)
+
+.TP
+.B login_timeout
+.
+Wait X seconds for cmd prompt after login (Default Value: 5)
+
+.TP
+.B port_as_ip
+.
+Make "port/plug" to be an alias to IP address
+
+.TP
+.B power_timeout
+.
+Test X seconds for status change after ON/OFF (Default Value: 20)
+
+.TP
+.B power_wait
+.
+Wait X seconds after issuing ON/OFF (Default Value: 3)
+
+.TP
+.B shell_timeout
+.
+Wait X seconds for cmd prompt after issuing command (Default Value: 3)
+
+.TP
+.B retry_on
+.
+Count of attempts to retry power on (Default Value: 1)
diff --git a/fence/agents/powerman/fence_powerman.py b/fence/agents/powerman/fence_powerman.py
new file mode 100755
index 00000000..f168e28d
--- /dev/null
+++ b/fence/agents/powerman/fence_powerman.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python
+import os
+import time
+from datetime import datetime
+import sys
+import subprocess
+import re
+import atexit
+sys.path.append("@FENCEAGENTSLIBDIR@")
+from fencing import *
+from fencing import run_delay
+import logging
+
+
+#BEGIN_VERSION_GENERATION
+RELEASE_VERSION="Powerman Fencing Agent"
+REDHAT_COPYRIGHT=""
+BUILD_DATE=""
+#END_VERSION_GENERATION
+
+
+#### important!!! #######
+class PowerMan:
+ """Python wrapper for calling powerman commands
+
+ This class makes calls to a powerman deamon for a cluster of computers.
+ The make-up of such a call looks something like:
+ $ pm -h elssd1:10101 <option> <node>
+ where option is something like --off, --on, --cycle and where node is
+ elssd8, or whatever values are setup in powerman.conf (***this is key,
+ because otherwise this code will not work!)
+ """
+ program_name = "powerman"
+
+ def __init__(self, server_name, port="10101"):
+ """
+ Args:
+ server_name: (string) host or ip of powerman server
+ port: (str) port number that the powerman server is listening on
+ """
+ self.server_name = server_name
+ self.port = port
+ self.server_and_port = server_name + ":" + str(port)
+ # this is a list of the command and its options. For example:
+ # ['powerman', '--server-host', 'elssd1:10101']
+ self.base_cmd = [
+ self.program_name,
+ "--server-host",
+ self.server_and_port
+ ]
+
+ def _run(self, cmd):
+ # Args:
+ # cmd: (list) commands and arguments to pass to the program_name
+
+ # add the 2 command lists together to get whole command to run
+ run_this = self.base_cmd + cmd
+ try:
+ popen = subprocess.Popen(run_this, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+ out = popen.communicate()
+ except OSError as e:
+ logging.debug("_run command error: %s\n", e)
+ sys.exit(1)
+
+ result = out[0].decode().strip()
+ return (result, popen.returncode)
+
+ def is_running(self):
+ """simple query to see if powerman server is responding. Returns boolean"""
+ cmd = ["-q"] # just check if we get a response from the server
+ result, ret_code = self._run(cmd)
+ if ret_code != 0:
+ return False
+ return True
+
+ def on(self, host):
+ logging.debug("PowerMan on: %s\n", host)
+ cmd = ["--on", host]
+ try:
+ result, ret_code = self._run(cmd)
+ except OSError as e:
+ logging.debug("PowerMan Error: The command '--on' failed: %s\n", e)
+ return -1
+ except ValueError as e:
+ logging.debug("PowerMan Error: Popen: invalid arguments: %s\n", e)
+ return -1
+ logging.debug("result: %s ret_code: %s\n", result, ret_code)
+ return ret_code
+
+ def off(self, host):
+ logging.debug("PowerMan off: %s\n", host)
+ cmd = ["--off", host]
+ try:
+ result, ret_code = self._run(cmd)
+ except OSError as e:
+ logging.debug("PowerMan Error: The command '%s' failed: %s\n", cmd, e)
+ return -1
+ except ValueError as e:
+ logging.debug("PowerMan Error: Popen: invalid arguments: %s\n", e)
+ return -1
+ logging.debug("%s\n", result)
+ return ret_code
+
+ def query(self, host):
+ cmd = ["--query", host]
+ try:
+ result, ret_code = self._run(cmd)
+ except OSError as e:
+ logging.debug("PowerMan Error: The command '%s' failed: %s\n", cmd, e)
+ return -1
+ except ValueError as e:
+ logging.debug("PowerMan Error: Popen: invalid arguments: %s\n", e)
+ return -1
+ if ret_code < 0:
+ # there was an error with the command
+ return ret_code
+ else:
+ res = result.split('\n')
+ res = [r.split() for r in res]
+ # find the host in command's returned output
+ for lst in res:
+ if lst[0] == 'No' and lst[1] == 'such' and lst[2] == 'nodes:':
+ return -1
+ if host in lst:
+ return lst[0][:-1] # lst[0] would be 'off:'-- this removes the colon
+ # host isn't in the output
+ return -1
+
+
+def get_power_status(conn, options):
+ logging.debug("get_power_status function:\noptions: %s\n", str(options))
+ pm = PowerMan(options['--ip'], options['--ipport'])
+ # if Pacemaker is checking the status of the Powerman server...
+ if options['--action'] == 'monitor':
+ if pm.is_running():
+ logging.debug("Powerman is running\n")
+ return "on"
+ logging.debug("Powerman is NOT running\n")
+ return "off"
+ else:
+ status = pm.query(options['--plug'])
+ if isinstance(int, type(status)):
+ # query only returns ints on error
+ logging.debug("get_power_status: query returned %s\n", str(status))
+ fail(EC_STATUS)
+ return status
+
+
+def set_power_status(conn, options):
+ logging.debug("set_power_status function:\noptions: %s", str(options))
+ pm = PowerMan(options['--ip'], options['--ipport'])
+
+ action = options["--action"]
+ if action == "on":
+ pm.on(options['--plug'])
+ elif action == "off":
+ pm.off(options['--plug'])
+
+ return
+
+
+def reboot(conn, options):
+ logging.debug("reboot function:\noptions: %s", str(options))
+ pm = PowerMan(options['--ip'], options['--ipport'])
+ res = pm.off(options['--plug'])
+ if res < 0:
+ logging.debug("reboot: power off failed!\n")
+ return False
+ time.sleep(2)
+ res = pm.on(options['--plug'])
+ if res < 0:
+ logging.debug("reboot: power on failed!\n")
+ return False
+ return True
+
+
+def get_list(conn, options):
+ # TODO: make this function return a dictionary of hosts and their statuses
+ # by iterating over options['--plugs'] (I think???) and querying powerman
+ logging.debug("get_list function:\noptions: %s", str(options))
+ outlets = {'elssd8': 'on', 'elssd9': 'on'}
+ return outlets
+
+
+def define_new_opts():
+ """add elements to all_opt dict if you need to define new options"""
+ pass
+
+
+def main():
+ device_opt = [
+ 'ipaddr',
+ 'no_password',
+ 'no_login',
+ ]
+
+ atexit.register(atexit_handler)
+
+ define_new_opts()
+
+ # redefine default values for the options given by fencing.py
+ # these 3 different values are derived from the lssd test cluster and may
+ # need to adjusted depending on how other systems fare
+ all_opt['ipport']['default'] = '10101'
+ all_opt['delay']['default'] = '3'
+ all_opt['power_wait']['default'] = '3'
+
+ options = check_input(device_opt, process_input(device_opt))
+ logging.debug("fence_powerman.main: options: %s", str(options))
+ docs = {}
+ docs["shortdesc"] = "Fence Agent for Powerman"
+ docs["longdesc"] = "This is a Pacemaker Fence Agent for the \
+Powerman management utility that was designed for LLNL systems."
+ docs["vendorurl"] = "https://github.com/chaos/powerman"
+ show_docs(options, docs)
+
+ ## Do the delay of the fence device
+ run_delay(options)
+
+ if options["--action"] in ["off", "reboot"]:
+ # add extra delay if rebooting
+ time.sleep(int(options["--delay"]))
+
+ # call the fencing.fence_action function, passing in my various fence functions
+ result = fence_action(
+ None,
+ options,
+ set_power_status,
+ get_power_status,
+ None,
+ reboot
+ )
+
+ sys.exit(result)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/data/metadata/fence_powerman.xml b/tests/data/metadata/fence_powerman.xml
new file mode 100644
index 00000000..df77e015
--- /dev/null
+++ b/tests/data/metadata/fence_powerman.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" ?>
+<resource-agent name="fence_powerman" shortdesc="Fence Agent for Powerman" >
+<longdesc>This is a Pacemaker Fence Agent for the Powerman management utility that was designed for LLNL systems.</longdesc>
+<vendor-url>https://github.com/chaos/powerman</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="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">
+ <getopt mixed="-a, --ip=[ip]" />
+ <content type="string" />
+ <shortdesc lang="en">IP address or hostname of fencing device</shortdesc>
+ </parameter>
+ <parameter name="ipport" unique="0" required="0">
+ <getopt mixed="-u, --ipport=[port]" />
+ <content type="integer" default="10101" />
+ <shortdesc lang="en">TCP/UDP port to use for connection with device</shortdesc>
+ </parameter>
+ <parameter name="port" unique="0" required="0">
+ <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="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">
+ <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="delay" unique="0" required="0">
+ <getopt mixed="--delay=[seconds]" />
+ <content type="second" default="3" />
+ <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="power_wait" unique="0" required="0">
+ <getopt mixed="--power-wait=[seconds]" />
+ <content type="second" default="3" />
+ <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="monitor" />
+ <action name="metadata" />
+ <action name="validate-all" />
+</actions>
+</resource-agent>

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jul 20, 8:38 PM (1 d, 9 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2081433
Default Alt Text
(15 KB)

Event Timeline