diff --git a/RHEL-31488-RHEL-31485-RHEL-31483-fence_aliyun-update.patch b/RHEL-31488-RHEL-31485-RHEL-31483-fence_aliyun-update.patch new file mode 100644 index 0000000..b9bb334 --- /dev/null +++ b/RHEL-31488-RHEL-31485-RHEL-31483-fence_aliyun-update.patch @@ -0,0 +1,209 @@ +--- a/agents/aliyun/fence_aliyun.py 2024-04-04 10:22:53.720906183 +0200 ++++ b/agents/aliyun/fence_aliyun.py 2024-04-04 10:21:47.626425090 +0200 +@@ -1,53 +1,67 @@ + #!@PYTHON@ -tt + +-import sys, re ++import sys + import logging + import atexit + import json ++ + sys.path.append("@FENCEAGENTSLIBDIR@") + from fencing import * +-from fencing import fail, fail_usage, EC_TIMED_OUT, run_delay ++from fencing import fail_usage, run_delay ++ + + try: + sys.path.insert(0, '/usr/lib/fence-agents/support/aliyun') + from aliyunsdkcore import client + from aliyunsdkcore.auth.credentials import EcsRamRoleCredential ++ from aliyunsdkcore.profile import region_provider ++except ImportError as e: ++ logging.warn("The 'aliyunsdkcore' module has been not installed or is unavailable, try to execute the command 'pip install aliyun-python-sdk-core --upgrade' to solve. error: %s" % e) ++ ++ ++try: + from aliyunsdkecs.request.v20140526.DescribeInstancesRequest import DescribeInstancesRequest + from aliyunsdkecs.request.v20140526.StartInstanceRequest import StartInstanceRequest + from aliyunsdkecs.request.v20140526.StopInstanceRequest import StopInstanceRequest + from aliyunsdkecs.request.v20140526.RebootInstanceRequest import RebootInstanceRequest +- from aliyunsdkcore.profile import region_provider +-except ImportError: +- pass ++except ImportError as e: ++ logging.warn("The 'aliyunsdkecs' module has been not installed or is unavailable, try to execute the command 'pip install aliyun-python-sdk-ecs --upgrade' to solve. error: %s" % e) ++ + + def _send_request(conn, request): ++ logging.debug("send request action: %s" % request.get_action_name()) + request.set_accept_format('json') + try: + response_str = conn.do_action_with_exception(request) +- response_detail = json.loads(response_str) +- logging.debug("_send_request reponse: %s" % response_detail) +- return response_detail + except Exception as e: +- fail_usage("Failed: _send_request failed: %s" % e) ++ fail_usage("Failed: send request failed: Error: %s" % e) ++ ++ response_detail = json.loads(response_str) ++ logging.debug("reponse: %s" % response_detail) ++ return response_detail + + def start_instance(conn, instance_id): ++ logging.debug("start instance %s" % instance_id) + request = StartInstanceRequest() + request.set_InstanceId(instance_id) + _send_request(conn, request) + + def stop_instance(conn, instance_id): ++ logging.debug("stop instance %s" % instance_id) + request = StopInstanceRequest() + request.set_InstanceId(instance_id) + request.set_ForceStop('true') + _send_request(conn, request) + + def reboot_instance(conn, instance_id): ++ logging.debug("reboot instance %s" % instance_id) + request = RebootInstanceRequest() + request.set_InstanceId(instance_id) + request.set_ForceStop('true') + _send_request(conn, request) + + def get_status(conn, instance_id): ++ logging.debug("get instance %s status" % instance_id) + request = DescribeInstancesRequest() + request.set_InstanceIds(json.dumps([instance_id])) + response = _send_request(conn, request) +@@ -59,20 +73,30 @@ + return instance_status + + def get_nodes_list(conn, options): ++ logging.debug("start to get nodes list") + result = {} + request = DescribeInstancesRequest() + request.set_PageSize(100) ++ ++ if "--filter" in options: ++ filter_key = options["--filter"].split("=")[0].strip() ++ filter_value = options["--filter"].split("=")[1].strip() ++ params = request.get_query_params() ++ params[filter_key] = filter_value ++ request.set_query_params(params) ++ + response = _send_request(conn, request) +- instance_status = None + if response is not None: + instance_list = response.get('Instances').get('Instance') + for item in instance_list: + instance_id = item.get('InstanceId') + instance_name = item.get('InstanceName') + result[instance_id] = (instance_name, None) ++ logging.debug("get nodes list: %s" % result) + return result + + def get_power_status(conn, options): ++ logging.debug("start to get power(%s) status" % options["--plug"]) + state = get_status(conn, options["--plug"]) + + if state == "Running": +@@ -81,14 +105,11 @@ + status = "off" + else: + status = "unknown" +- +- logging.info("get_power_status: %s" % status) +- ++ logging.debug("the power(%s) status is %s" % (options["--plug"], status)) + return status + +- + def set_power_status(conn, options): +- logging.info("set_power_status: %s" % options["--action"]) ++ logging.info("start to set power(%s) status to %s" % (options["--plug"], options["--action"])) + + if (options["--action"]=="off"): + stop_instance(conn, options["--plug"]) +@@ -97,7 +118,6 @@ + elif (options["--action"]=="reboot"): + reboot_instance(conn, options["--plug"]) + +- + def define_new_opts(): + all_opt["region"] = { + "getopt" : "r:", +@@ -126,17 +146,42 @@ + all_opt["ram_role"] = { + "getopt": ":", + "longopt": "ram-role", +- "help": "--ram-role=[name] Ram Role", ++ "help": "--ram-role=[name] Ram Role", + "shortdesc": "Ram Role.", + "required": "0", + "order": 5 + } ++ all_opt["credentials_file"] = { ++ "getopt": ":", ++ "longopt": "credentials-file", ++ "help": "--credentials-file=[path] Path to aliyun-cli credentials file", ++ "shortdesc": "Path to credentials file", ++ "required": "0", ++ "order": 6 ++ } ++ all_opt["credentials_file_profile"] = { ++ "getopt": ":", ++ "longopt": "credentials-file-profile", ++ "help": "--credentials-file-profile=[profile] Credentials file profile", ++ "shortdesc": "Credentials file profile", ++ "required": "0", ++ "default": "default", ++ "order": 7 ++ } ++ all_opt["filter"] = { ++ "getopt": ":", ++ "longopt": "filter", ++ "help": "--filter=[key=value] Filter (e.g. InstanceIds=[\"i-XXYYZZAA1\",\"i-XXYYZZAA2\"]", ++ "shortdesc": "Filter for list-action.", ++ "required": "0", ++ "order": 8 ++ } + + # Main agent method + def main(): + conn = None + +- device_opt = ["port", "no_password", "region", "access_key", "secret_key", "ram_role"] ++ device_opt = ["port", "no_password", "region", "access_key", "secret_key", "ram_role", "credentials_file", "credentials_file_profile", "filter"] + + atexit.register(atexit_handler) + +@@ -164,8 +209,25 @@ + ram_role = options["--ram-role"] + role = EcsRamRoleCredential(ram_role) + conn = client.AcsClient(region_id=region, credential=role) +- region_provider.modify_point('Ecs', region, 'ecs.%s.aliyuncs.com' % region) +- ++ elif "--credentials-file" in options and "--credentials-file-profile" in options: ++ import os, configparser ++ try: ++ config = configparser.ConfigParser() ++ config.read(os.path.expanduser(options["--credentials-file"])) ++ access_key = config.get(options["--credentials-file-profile"], "aliyun_access_key_id") ++ secret_key = config.get(options["--credentials-file-profile"], "aliyun_access_key_secret") ++ conn = client.AcsClient(access_key, secret_key, region) ++ except Exception as e: ++ fail_usage("Failed: failed to read credentials file: %s" % e) ++ else: ++ fail_usage("Failed: User credentials are not set. Please set the Access Key and the Secret Key, or configure the RAM role.") ++ ++ # Use intranet endpoint to access ECS service ++ try: ++ region_provider.modify_point('Ecs', region, 'ecs.%s.aliyuncs.com' % region) ++ except Exception as e: ++ logging.warn("Failed: failed to modify endpoint to 'ecs.%s.aliyuncs.com': %s" % (region, e)) ++ + # Operate the fencing device + result = fence_action(conn, options, set_power_status, get_power_status, get_nodes_list) + sys.exit(result) diff --git a/fence-agents.spec b/fence-agents.spec index 9828584..6bb5ea7 100644 --- a/fence-agents.spec +++ b/fence-agents.spec @@ -59,7 +59,7 @@ Name: fence-agents Summary: Set of unified programs capable of host isolation ("fencing") Version: 4.10.0 -Release: 69%{?alphatag:.%{alphatag}}%{?dist} +Release: 70%{?alphatag:.%{alphatag}}%{?dist} License: GPLv2+ and LGPLv2+ URL: https://github.com/ClusterLabs/fence-agents Source0: https://fedorahosted.org/releases/f/e/fence-agents/%{name}-%{version}.tar.gz @@ -250,6 +250,7 @@ Patch49: RHEL-14344-fence_zvmip-1-document-user-permissions.patch Patch50: RHEL-14030-1-all-agents-metadata-update-IO-Power-Network.patch Patch51: RHEL-14030-2-fence_cisco_mds-undo-metadata-change.patch Patch52: RHEL-14344-fence_zvmip-2-fix-manpage-formatting.patch +Patch53: RHEL-31488-RHEL-31485-RHEL-31483-fence_aliyun-update.patch ### HA support libs/utils ### # all archs @@ -422,6 +423,7 @@ BuildRequires: %{systemd_units} %patch -p1 -P 50 %patch -p1 -P 51 %patch -p1 -P 52 +%patch -p1 -P 53 # prevent compilation of something that won't get used anyway sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac @@ -1517,6 +1519,11 @@ are located on corosync cluster nodes. %endif %changelog +* Thu Apr 4 2024 Oyvind Albrigtsen - 4.10.0-70 +- fence_aliyun: add credentials file support, filter parameter, and + optimize log output + Resolves: RHEL-31488, RHEL-31485, RHEL-31483 + * Thu Mar 21 2024 Oyvind Albrigtsen - 4.10.0-69 - ha-cloud-support: upgrade bundled pyroute2 libs to fix issue in gcp-vpc-move-route's stop-action