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