Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F2822236
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/agents/aws/fence_aws.py b/agents/aws/fence_aws.py
index 8322df9e..c947bf29 100644
--- a/agents/aws/fence_aws.py
+++ b/agents/aws/fence_aws.py
@@ -1,208 +1,223 @@
#!@PYTHON@ -tt
import sys, re
import logging
import atexit
sys.path.append("@FENCEAGENTSLIBDIR@")
from fencing import *
from fencing import fail, fail_usage, run_delay, EC_STATUS, SyslogLibHandler
import requests
from requests import HTTPError
try:
import boto3
from botocore.exceptions import ConnectionError, ClientError, EndpointConnectionError, NoRegionError
except ImportError:
pass
logger = logging.getLogger("fence_aws")
logger.propagate = False
logger.setLevel(logging.INFO)
logger.addHandler(SyslogLibHandler())
logging.getLogger('botocore.vendored').propagate = False
def get_instance_id():
try:
token = requests.put('http://169.254.169.254/latest/api/token', headers={"X-aws-ec2-metadata-token-ttl-seconds" : "21600"}).content.decode("UTF-8")
r = requests.get('http://169.254.169.254/latest/meta-data/instance-id', headers={"X-aws-ec2-metadata-token" : token}).content.decode("UTF-8")
return r
except HTTPError as http_err:
logger.error('HTTP error occurred while trying to access EC2 metadata server: %s', http_err)
except Exception as err:
logger.error('A fatal error occurred while trying to access EC2 metadata server: %s', err)
return None
def get_nodes_list(conn, options):
logger.info("Starting monitor operation")
result = {}
try:
- for instance in conn.instances.all():
- result[instance.id] = ("", None)
+ if "--filter" in options:
+ filter_key = options["--filter"].split("=")[0].strip()
+ filter_value = options["--filter"].split("=")[1].strip()
+ filter = [{ "Name": filter_key, "Values": [filter_value] }]
+ for instance in conn.instances.filter(Filters=filter):
+ result[instance.id] = ("", None)
+ else:
+ for instance in conn.instances.all():
+ result[instance.id] = ("", None)
except ClientError:
fail_usage("Failed: Incorrect Access Key or Secret Key.")
except EndpointConnectionError:
fail_usage("Failed: Incorrect Region.")
except ConnectionError as e:
fail_usage("Failed: Unable to connect to AWS: " + str(e))
except Exception as e:
logger.error("Failed to get node list: %s", e)
logger.debug("Monitor operation OK: %s",result)
return result
def get_power_status(conn, options):
logger.debug("Starting status operation")
try:
instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [options["--plug"]]}])
state = list(instance)[0].state["Name"]
logger.info("Status operation for EC2 instance %s returned state: %s",options["--plug"],state.upper())
if state == "running":
return "on"
elif state == "stopped":
return "off"
else:
return "unknown"
except ClientError:
fail_usage("Failed: Incorrect Access Key or Secret Key.")
except EndpointConnectionError:
fail_usage("Failed: Incorrect Region.")
except IndexError:
fail(EC_STATUS)
except Exception as e:
logging.error("Failed to get power status: %s", e)
fail(EC_STATUS)
def get_self_power_status(conn, instance_id):
try:
instance = conn.instances.filter(Filters=[{"Name": "instance-id", "Values": [instance_id]}])
state = list(instance)[0].state["Name"]
if state == "running":
logging.debug("Captured my (%s) state and it %s - returning OK - Proceeding with fencing",instance_id,state.upper())
return "ok"
else:
logging.debug("Captured my (%s) state it is %s - returning Alert - Unable to fence other nodes",instance_id,state.upper())
return "alert"
except ClientError:
fail_usage("Failed: Incorrect Access Key or Secret Key.")
except EndpointConnectionError:
fail_usage("Failed: Incorrect Region.")
except IndexError:
return "fail"
def set_power_status(conn, options):
my_instance = get_instance_id()
try:
if (options["--action"]=="off"):
if (get_self_power_status(conn,my_instance) == "ok"):
conn.instances.filter(InstanceIds=[options["--plug"]]).stop(Force=True)
logger.info("Called StopInstance API call for %s", options["--plug"])
else:
logger.info("Skipping fencing as instance is not in running status")
elif (options["--action"]=="on"):
conn.instances.filter(InstanceIds=[options["--plug"]]).start()
except Exception as e:
logger.error("Failed to power %s %s: %s", \
options["--action"], options["--plug"], e)
def define_new_opts():
all_opt["region"] = {
"getopt" : "r:",
"longopt" : "region",
- "help" : "-r, --region=[region] Region, e.g. us-east-1",
+ "help" : "-r, --region=[region] Region, e.g. us-east-1",
"shortdesc" : "Region.",
"required" : "0",
"order" : 2
}
all_opt["access_key"] = {
"getopt" : "a:",
"longopt" : "access-key",
"help" : "-a, --access-key=[key] Access Key",
"shortdesc" : "Access Key.",
"required" : "0",
"order" : 3
}
all_opt["secret_key"] = {
"getopt" : "s:",
"longopt" : "secret-key",
"help" : "-s, --secret-key=[key] Secret Key",
"shortdesc" : "Secret Key.",
"required" : "0",
"order" : 4
}
+ all_opt["filter"] = {
+ "getopt" : ":",
+ "longopt" : "filter",
+ "help" : "--filter=[key=value] Filter (e.g. vpc-id=[vpc-XXYYZZAA]",
+ "shortdesc": "Filter for list-action",
+ "required": "0",
+ "order": 5
+ }
all_opt["boto3_debug"] = {
"getopt" : "b:",
"longopt" : "boto3_debug",
- "help" : "-b, --boto3_debug=[option] Boto3 and Botocore library debug logging",
+ "help" : "-b, --boto3_debug=[option] Boto3 and Botocore library debug logging",
"shortdesc": "Boto Lib debug",
"required": "0",
"default": "False",
- "order": 5
+ "order": 6
}
# Main agent method
def main():
conn = None
- device_opt = ["port", "no_password", "region", "access_key", "secret_key", "boto3_debug"]
+ device_opt = ["port", "no_password", "region", "access_key", "secret_key", "filter", "boto3_debug"]
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 AWS (Amazon Web Services)"
docs["longdesc"] = "fence_aws is an I/O Fencing agent for AWS (Amazon Web\
Services). It uses the boto3 library to connect to AWS.\
\n.P\n\
boto3 can be configured with AWS CLI or by creating ~/.aws/credentials.\n\
For instructions see: https://boto3.readthedocs.io/en/latest/guide/quickstart.html#configuration"
docs["vendorurl"] = "http://www.amazon.com"
show_docs(options, docs)
run_delay(options)
if options.get("--verbose") is not None:
lh = logging.FileHandler('/var/log/fence_aws_debug.log')
logger.addHandler(lh)
lhf = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
lh.setFormatter(lhf)
logger.setLevel(logging.DEBUG)
if options["--boto3_debug"].lower() not in ["1", "yes", "on", "true"]:
boto3.set_stream_logger('boto3',logging.INFO)
boto3.set_stream_logger('botocore',logging.CRITICAL)
logging.getLogger('botocore').propagate = False
logging.getLogger('boto3').propagate = False
else:
log_format = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
logging.getLogger('botocore').propagate = False
logging.getLogger('boto3').propagate = False
fdh = logging.FileHandler('/var/log/fence_aws_boto3.log')
fdh.setFormatter(log_format)
logging.getLogger('boto3').addHandler(fdh)
logging.getLogger('botocore').addHandler(fdh)
logging.debug("Boto debug level is %s and sending debug info to /var/log/fence_aws_boto3.log", options["--boto3_debug"])
region = options.get("--region")
access_key = options.get("--access-key")
secret_key = options.get("--secret-key")
try:
conn = boto3.resource('ec2', region_name=region,
aws_access_key_id=access_key,
aws_secret_access_key=secret_key)
except Exception as e:
fail_usage("Failed: Unable to connect to AWS: " + str(e))
# 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()
diff --git a/tests/data/metadata/fence_aws.xml b/tests/data/metadata/fence_aws.xml
index 1f3ab3b9..a767e93c 100644
--- a/tests/data/metadata/fence_aws.xml
+++ b/tests/data/metadata/fence_aws.xml
@@ -1,132 +1,137 @@
<?xml version="1.0" ?>
<resource-agent name="fence_aws" shortdesc="Fence agent for AWS (Amazon Web Services)" >
<longdesc>fence_aws is an I/O Fencing agent for AWS (Amazon WebServices). It uses the boto3 library to connect to AWS.
boto3 can be configured with AWS CLI or by creating ~/.aws/credentials.
For instructions see: https://boto3.readthedocs.io/en/latest/guide/quickstart.html#configuration</longdesc>
<vendor-url>http://www.amazon.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=[region]" />
<content type="string" />
<shortdesc lang="en">Region.</shortdesc>
</parameter>
<parameter name="access_key" unique="0" required="0">
<getopt mixed="-a, --access-key=[key]" />
<content type="string" />
<shortdesc lang="en">Access Key.</shortdesc>
</parameter>
<parameter name="secret_key" unique="0" required="0">
<getopt mixed="-s, --secret-key=[key]" />
<content type="string" />
<shortdesc lang="en">Secret Key.</shortdesc>
</parameter>
+ <parameter name="filter" unique="0" required="0">
+ <getopt mixed="--filter=[key=value]" />
+ <content type="string" />
+ <shortdesc lang="en">Filter for list-action</shortdesc>
+ </parameter>
<parameter name="boto3_debug" unique="0" required="0">
<getopt mixed="-b, --boto3_debug=[option]" />
<content type="string" default="False" />
<shortdesc lang="en">Boto Lib debug</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]" />
<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="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="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="manpage" />
<action name="validate-all" />
</actions>
</resource-agent>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Jan 25, 5:18 AM (9 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1321366
Default Alt Text
(14 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment