Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4525090
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
17 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py
index 73dfe0ab..ec9a0c11 100755
--- a/agents/ibm_powervs/fence_ibm_powervs.py
+++ b/agents/ibm_powervs/fence_ibm_powervs.py
@@ -1,299 +1,323 @@
#!@PYTHON@ -tt
import sys
-import pycurl, io, json
+import pycurl
+import io
+import 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
+from fencing import all_opt, atexit_handler, check_input, process_input, show_docs, fence_action, fail, run_delay, EC_STATUS
state = {
"ACTIVE": "on",
"SHUTOFF": "off",
"HARD_REBOOT": "on",
"SOFT_REBOOT": "on",
"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"]
+ try:
+ if options["--token"][0] == '@':
+ key_file = options["--token"][1:]
+ try:
+ # read the API key from a file
+ with open(key_file, "r") as f:
+ try:
+ keys = json.loads(f.read())
+ # data seems to be in json format
+ # return the value of the item with the key 'Apikey'
+ api_key = keys.get("Apikey", "")
+ if not api_key:
+ # backward compatibility: former key name was 'apikey'
+ api_key = keys.get("apikey", "")
+ # data is text, return as is
+ except ValueError:
+ api_key = f.read().strip()
+ except FileNotFoundError:
+ logging.debug("Failed: Cannot open file {}".format(key_file))
+ return "TOKEN_IS_MISSING_OR_WRONG"
+ else:
+ api_key = options["--token"]
+ command = "identity/token"
+ action = "grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey&apikey={}".format(api_key)
+ 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 options["--verbose-level"] > 1:
logging.debug(json.dumps(r, indent=2))
- outlets[r["pvmInstanceID"]] = (r["serverName"], state[r["status"]])
+ outlets[r["pvmInstanceID"]] = (r["serverName"], state.get(r["status"], "unknown"))
return outlets
def get_power_status(conn, options):
outlets = {}
logging.debug("Info: getting power status for LPAR " + options["--plug"] + " instance " + options["--instance"])
try:
command = "cloud-instances/{}/pvm-instances/{}".format(
options["--instance"], options["--plug"])
res = send_command(conn, command)
outlets[res["pvmInstanceID"]] = (res["serverName"], state[res["status"]])
if options["--verbose-level"] > 1:
logging.debug(json.dumps(res, indent=2))
result = outlets[options["--plug"]][1]
logging.debug("Info: Status: {}".format(result))
except KeyError as e:
try:
result = get_list(conn, options)[options["--plug"]][1]
except KeyError as ex:
logging.debug("Failed: Unable to get status for {}".format(ex))
fail(EC_STATUS)
return result
def set_power_status(conn, options):
action = {
"on" : '{"action" : "start"}',
"off" : '{"action" : "immediate-shutdown"}',
}[options["--action"]]
logging.debug("Info: set power status to " + options["--action"] + " for LPAR " + options["--plug"] + " instance " + options["--instance"])
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 reboot_cycle(conn, options):
action = {
"reboot" : '{"action" : "hard-reboot"}',
}[options["--action"]]
logging.debug("Info: start reboot cycle with action " + options["--action"] + " for LPAR " + options["--plug"] + " instance " + options["--instance"])
try:
send_command(conn, "cloud-instances/{}/pvm-instances/{}/action".format(
options["--instance"], options["--plug"]), "POST", action)
except Exception as e:
result = get_power_status(conn, options)
logging.debug("Info: Status {}".format(result))
if result == "off":
return True
else:
logging.debug("Failed: Unable to cycle with {} for {}".format(options["--action"], e))
fail(EC_STATUS)
- return True
+ return True
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["--api-type"] == "private":
+ conn.base_url = "https://private.iam.cloud.ibm.com/"
+ else:
+ 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",
"method",
]
atexit.register(atexit_handler)
define_new_opts()
all_opt["shell_timeout"]["default"] = "500"
- all_opt["power_timeout"]["default"] = "30"
- all_opt["power_wait"]["default"] = "1"
- all_opt["stonith_status_sleep"]["default"] = "2"
+ all_opt["power_timeout"]["default"] = "120"
+ all_opt["power_wait"]["default"] = "15"
+ all_opt["stonith_status_sleep"]["default"] = "10"
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 a Power Fencing agent which can be \
-used with IBM PowerVS to fence virtual machines."""
+ docs["longdesc"] = """fence_ibm_powervs is a power fencing agent for \
+IBM Power Virtual Server (IBM PowerVS) to fence virtual server instances."""
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, reboot_cycle)
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 c1dc034d..ec59e1b5 100644
--- a/tests/data/metadata/fence_ibm_powervs.xml
+++ b/tests/data/metadata/fence_ibm_powervs.xml
@@ -1,161 +1,161 @@
<?xml version="1.0" ?>
<resource-agent name="fence_ibm_powervs" shortdesc="Fence agent for IBM PowerVS" >
-<longdesc>fence_ibm_powervs is a Power Fencing agent which can be used with IBM PowerVS to fence virtual machines.</longdesc>
+<longdesc>fence_ibm_powervs is a power fencing agent for IBM Power Virtual Server (IBM PowerVS) to fence virtual server instances.</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="method" unique="0" required="0">
<getopt mixed="-m, --method=[method]" />
<content type="select" default="onoff" >
<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" />
<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="plug_separator" unique="0" required="0">
<getopt mixed="--plug-separator=[char]" />
<content type="string" default="," />
<shortdesc lang="en">Separator for plug parameter when specifying more than 1 plug</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" />
+ <content type="second" default="120" />
<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" />
+ <content type="second" default="15" />
<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="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="2" />
+ <content type="second" default="10" />
<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>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 26, 5:43 PM (22 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1958747
Default Alt Text
(17 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment