diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py index b0caed7c..18389361 100755 --- a/agents/ibm_powervs/fence_ibm_powervs.py +++ b/agents/ibm_powervs/fence_ibm_powervs.py @@ -1,267 +1,267 @@ #!@PYTHON@ -tt import sys import pycurl, io, json import logging import atexit import time sys.path.append("@FENCEAGENTSLIBDIR@") from fencing import * from fencing import fail, run_delay, EC_LOGIN_DENIED, EC_STATUS state = { "ACTIVE": "on", "SHUTOFF": "off", "ERROR": "unknown" } def get_token(conn, options): try: command = "identity/token" action = "grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey={}".format(options["--token"]) res = send_command(conn, command, "POST", action, printResult=False) except Exception as e: logging.debug("Failed: {}".format(e)) return "TOKEN_IS_MISSING_OR_WRONG" return res["access_token"] def get_list(conn, options): outlets = {} try: command = "cloud-instances/{}/pvm-instances".format(options["--instance"]) res = send_command(conn, command) except Exception as e: logging.debug("Failed: {}".format(e)) return outlets for r in res["pvmInstances"]: if "--verbose" in options: logging.debug(json.dumps(r, indent=2)) outlets[r["pvmInstanceID"]] = (r["serverName"], state[r["status"]]) return outlets def get_power_status(conn, options): try: command = "cloud-instances/{}/pvm-instances/{}".format( options["--instance"], options["--plug"]) res = send_command(conn, command) result = get_list(conn, options)[options["--plug"]][1] except KeyError as e: logging.debug("Failed: Unable to get status for {}".format(e)) fail(EC_STATUS) return result def set_power_status(conn, options): action = { "on" : '{"action" : "start"}', "off" : '{"action" : "immediate-shutdown"}', }[options["--action"]] try: send_command(conn, "cloud-instances/{}/pvm-instances/{}/action".format( options["--instance"], options["--plug"]), "POST", action) except Exception as e: logging.debug("Failed: Unable to set power to {} for {}".format(options["--action"], e)) fail(EC_STATUS) def connect(opt, token): conn = pycurl.Curl() ## setup correct URL conn.base_url = "https://" + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" if opt["--api-type"] == "private": conn.base_url = "https://private." + opt["--region"] + ".power-iaas.cloud.ibm.com/pcloud/v1/" if opt["--verbose-level"] < 3: conn.setopt(pycurl.VERBOSE, 0) conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) conn.setopt(pycurl.SSL_VERIFYPEER, 1) conn.setopt(pycurl.SSL_VERIFYHOST, 2) conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) # set auth token for later requests conn.setopt(pycurl.HTTPHEADER, [ "Content-Type: application/json", "Authorization: Bearer {}".format(token), "CRN: {}".format(opt["--crn"]), "User-Agent: curl", ]) return conn def auth_connect(opt): conn = pycurl.Curl() # setup correct URL conn.base_url = "https://iam.cloud.ibm.com/" if opt["--verbose-level"] > 1: conn.setopt(pycurl.VERBOSE, 1) conn.setopt(pycurl.CONNECTTIMEOUT,int(opt["--shell-timeout"])) conn.setopt(pycurl.TIMEOUT, int(opt["--shell-timeout"])) conn.setopt(pycurl.SSL_VERIFYPEER, 1) conn.setopt(pycurl.SSL_VERIFYHOST, 2) conn.setopt(pycurl.PROXY, "{}".format(opt["--proxy"])) # set auth token for later requests conn.setopt(pycurl.HTTPHEADER, [ "Content-type: application/x-www-form-urlencoded", "Accept: application/json", "User-Agent: curl", ]) return conn def disconnect(conn): conn.close() def send_command(conn, command, method="GET", action=None, printResult=True): url = conn.base_url + command conn.setopt(pycurl.URL, url.encode("ascii")) web_buffer = io.BytesIO() if method == "GET": conn.setopt(pycurl.POST, 0) if method == "POST": conn.setopt(pycurl.POSTFIELDS, action) if method == "DELETE": conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") conn.setopt(pycurl.WRITEFUNCTION, web_buffer.write) try: conn.perform() except Exception as e: logging.error("send_command(): {}".format(e)) raise(e) rc = conn.getinfo(pycurl.HTTP_CODE) result = web_buffer.getvalue().decode("UTF-8") web_buffer.close() if rc != 200: if len(result) > 0: raise Exception("{}: {}".format(rc,result)) else: raise Exception("Remote returned {} for request to {}".format(rc, url)) if len(result) > 0: result = json.loads(result) logging.debug("url: {}".format(url)) logging.debug("method: {}".format(method)) logging.debug("response code: {}".format(rc)) if printResult: logging.debug("result: {}\n".format(result)) return result def define_new_opts(): all_opt["token"] = { "getopt" : ":", "longopt" : "token", "help" : "--token=[token] API Token", "required" : "1", "shortdesc" : "API Token", "order" : 0 } all_opt["crn"] = { "getopt" : ":", "longopt" : "crn", "help" : "--crn=[crn] CRN", "required" : "1", "shortdesc" : "CRN", "order" : 0 } all_opt["instance"] = { "getopt" : ":", "longopt" : "instance", "help" : "--instance=[instance] PowerVS Instance", "required" : "1", "shortdesc" : "PowerVS Instance", "order" : 0 } all_opt["region"] = { "getopt" : ":", "longopt" : "region", "help" : "--region=[region] Region", "required" : "1", "shortdesc" : "Region", "order" : 0 } all_opt["api-type"] = { "getopt" : ":", "longopt" : "api-type", "help" : "--api-type=[public|private] API-type: 'public' (default) or 'private'", "required" : "0", "shortdesc" : "API-type (public|private)", "order" : 0 } all_opt["proxy"] = { "getopt" : ":", "longopt" : "proxy", "help" : "--proxy=[http://<URL>:<PORT>] Proxy: 'http://<URL>:<PORT>'", "required" : "0", "shortdesc" : "Network proxy", "order" : 0 } def main(): device_opt = [ "token", "crn", "instance", "region", "api-type", "proxy", "port", "no_password", ] atexit.register(atexit_handler) define_new_opts() - all_opt["shell_timeout"]["default"] = "15" + all_opt["shell_timeout"]["default"] = "500" all_opt["power_timeout"]["default"] = "30" all_opt["power_wait"]["default"] = "1" - all_opt["stonith_status_sleep"]["default"] = "3" + all_opt["stonith_status_sleep"]["default"] = "2" all_opt["api-type"]["default"] = "private" all_opt["proxy"]["default"] = "" options = check_input(device_opt, process_input(device_opt)) docs = {} docs["shortdesc"] = "Fence agent for IBM PowerVS" docs["longdesc"] = """fence_ibm_powervs is an I/O Fencing agent which can be \ used with IBM PowerVS to fence virtual machines.""" docs["vendorurl"] = "https://www.ibm.com" show_docs(options, docs) #### ## Fence operations #### run_delay(options) auth_conn = auth_connect(options) token = get_token(auth_conn, options) disconnect(auth_conn) conn = connect(options, token) atexit.register(disconnect, conn) result = fence_action(conn, options, set_power_status, get_power_status, get_list) sys.exit(result) if __name__ == "__main__": main() diff --git a/tests/data/metadata/fence_ibm_powervs.xml b/tests/data/metadata/fence_ibm_powervs.xml index 40c49411..326bc237 100644 --- a/tests/data/metadata/fence_ibm_powervs.xml +++ b/tests/data/metadata/fence_ibm_powervs.xml @@ -1,148 +1,148 @@ <?xml version="1.0" ?> <resource-agent name="fence_ibm_powervs" shortdesc="Fence agent for IBM PowerVS" > <longdesc>fence_ibm_powervs is an I/O Fencing agent which can be used with IBM PowerVS to fence virtual machines.</longdesc> <vendor-url>https://www.ibm.com</vendor-url> <parameters> <parameter name="api-type" unique="0" required="0" deprecated="1"> <getopt mixed="--api-type=[public|private]" /> <content type="string" default="private" /> <shortdesc lang="en">API-type (public|private)</shortdesc> </parameter> <parameter name="api_type" unique="0" required="0" obsoletes="api-type"> <getopt mixed="--api-type=[public|private]" /> <content type="string" default="private" /> <shortdesc lang="en">API-type (public|private)</shortdesc> </parameter> <parameter name="crn" unique="0" required="1"> <getopt mixed="--crn=[crn]" /> <content type="string" /> <shortdesc lang="en">CRN</shortdesc> </parameter> <parameter name="instance" unique="0" required="1"> <getopt mixed="--instance=[instance]" /> <content type="string" /> <shortdesc lang="en">PowerVS Instance</shortdesc> </parameter> <parameter name="proxy" unique="0" required="0"> <getopt mixed="--proxy=[http://<URL>:<PORT>]" /> <content type="string" default="" /> <shortdesc lang="en">Network proxy</shortdesc> </parameter> <parameter name="region" unique="0" required="1"> <getopt mixed="--region=[region]" /> <content type="string" /> <shortdesc lang="en">Region</shortdesc> </parameter> <parameter name="token" unique="0" required="1"> <getopt mixed="--token=[token]" /> <content type="string" /> <shortdesc lang="en">API Token</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="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="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. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity.</shortdesc> </parameter> <parameter name="verbose_level" unique="0" required="0"> <getopt mixed="--verbose-level" /> <content type="integer" /> <shortdesc lang="en">Level of debugging detail in output. Defaults to the number of --verbose flags specified on the command line, or to 1 if verbose=1 in a stonith device configuration (i.e., on stdin).</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]" /> <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="disable_timeout" unique="0" required="0"> <getopt mixed="--disable-timeout=[true/false]" /> <content type="string" /> <shortdesc lang="en">Disable timeout (true/false) (default: true when run from Pacemaker 2.0+)</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="30" /> <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="1" /> <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="15" /> + <content type="second" default="500" /> <shortdesc lang="en">Wait X seconds for cmd prompt after issuing command</shortdesc> </parameter> <parameter name="stonith_status_sleep" unique="0" required="0"> <getopt mixed="--stonith-status-sleep=[seconds]" /> - <content type="second" default="3" /> + <content type="second" default="2" /> <shortdesc lang="en">Sleep X seconds between status calls during a STONITH action</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="manpage" /> <action name="validate-all" /> </actions> </resource-agent>