From 98623bf7985bbec6633137a3f63ff0c2127237f7 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Thu, 4 Dec 2025 11:31:16 +0000 Subject: [PATCH] Import from AlmaLinux stable repository --- ...nce_ibm_vpc-add-apikey-file-support.patch} | 0 ...88-fence_sbd-improve-error-handling.patch} | 0 SOURCES/RHEL-68321-1-fence_nutanix_ahv.patch | 790 ++++++++++++++++++ ...-2-fence_nutanix_ahv-update-metadata.patch | 39 + ...ence_aws-add-skipshutdown-parameter.patch} | 4 +- ...EVICE-if-devices-parameter-isnt-set.patch} | 0 ...RHEL-82193-fence_kubevirt-force-off.patch} | 0 ...-fence_ibm_vpc-refresh-bearer-token.patch} | 0 ...cuate-dont-use-deprecated-getargspec.patch | 38 + ...rvs-fix-plaintext-token-file-support.patch | 21 + ...-pkg_resources-suppress-UserWarning.patch} | 0 SPECS/fence-agents.spec | 87 +- 12 files changed, 951 insertions(+), 28 deletions(-) rename SOURCES/{RHEL-107529-fence_ibm_vpc-add-apikey-file-support.patch => RHEL-107505-fence_ibm_vpc-add-apikey-file-support.patch} (100%) rename SOURCES/{RHEL-92695-1-fence_sbd-improve-error-handling.patch => RHEL-13088-fence_sbd-improve-error-handling.patch} (100%) create mode 100644 SOURCES/RHEL-68321-1-fence_nutanix_ahv.patch create mode 100644 SOURCES/RHEL-68321-2-fence_nutanix_ahv-update-metadata.patch rename SOURCES/{RHEL-109923-fence_aws-add-skipshutdown-parameter.patch => RHEL-7601-fence_aws-add-skipshutdown-parameter.patch} (98%) rename SOURCES/{RHEL-92695-2-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch => RHEL-79798-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch} (100%) rename SOURCES/{RHEL-96183-fence_kubevirt-force-off.patch => RHEL-82193-fence_kubevirt-force-off.patch} (100%) rename SOURCES/{RHEL-83488-fence_ibm_vpc-refresh-bearer-token.patch => RHEL-83255-fence_ibm_vpc-refresh-bearer-token.patch} (100%) create mode 100644 SOURCES/RHEL-84448-fence_compute-fence_evacuate-dont-use-deprecated-getargspec.patch create mode 100644 SOURCES/RHEL-88568-fence_ibm_powervs-fix-plaintext-token-file-support.patch rename SOURCES/{RHEL-95903-pkg_resources-suppress-UserWarning.patch => RHEL-95901-pkg_resources-suppress-UserWarning.patch} (100%) diff --git a/SOURCES/RHEL-107529-fence_ibm_vpc-add-apikey-file-support.patch b/SOURCES/RHEL-107505-fence_ibm_vpc-add-apikey-file-support.patch similarity index 100% rename from SOURCES/RHEL-107529-fence_ibm_vpc-add-apikey-file-support.patch rename to SOURCES/RHEL-107505-fence_ibm_vpc-add-apikey-file-support.patch diff --git a/SOURCES/RHEL-92695-1-fence_sbd-improve-error-handling.patch b/SOURCES/RHEL-13088-fence_sbd-improve-error-handling.patch similarity index 100% rename from SOURCES/RHEL-92695-1-fence_sbd-improve-error-handling.patch rename to SOURCES/RHEL-13088-fence_sbd-improve-error-handling.patch diff --git a/SOURCES/RHEL-68321-1-fence_nutanix_ahv.patch b/SOURCES/RHEL-68321-1-fence_nutanix_ahv.patch new file mode 100644 index 0000000..15509f2 --- /dev/null +++ b/SOURCES/RHEL-68321-1-fence_nutanix_ahv.patch @@ -0,0 +1,790 @@ +--- a/agents/nutanix_ahv/fence_nutanix_ahv.py 1970-01-01 01:00:00.000000000 +0100 ++++ b/agents/nutanix_ahv/fence_nutanix_ahv.py 2025-02-25 16:27:56.973414013 +0100 +@@ -0,0 +1,583 @@ ++#!@PYTHON@ -tt ++ ++# AHV Fence agent ++# Compatible with Nutanix v4 API ++ ++ ++import atexit ++import logging ++import sys ++import time ++import uuid ++import requests ++from requests.adapters import HTTPAdapter ++from requests.packages.urllib3.util.retry import Retry ++ ++sys.path.append("@FENCEAGENTSLIBDIR@") ++from fencing import * ++from fencing import fail, EC_LOGIN_DENIED, EC_GENERIC_ERROR, EC_TIMED_OUT, run_delay, EC_BAD_ARGS ++ ++ ++V4_VERSION = '4.0' ++MIN_TIMEOUT = 60 ++PC_PORT = 9440 ++POWER_STATES = {"ON": "on", "OFF": "off", "PAUSED": "off", "UNKNOWN": "unknown"} ++MAX_RETRIES = 5 ++ ++ ++class NutanixClientException(Exception): ++ pass ++ ++ ++class AHVFenceAgentException(Exception): ++ pass ++ ++ ++class TaskTimedOutException(Exception): ++ pass ++ ++ ++class InvalidArgsException(Exception): ++ pass ++ ++ ++class NutanixClient: ++ def __init__(self, username, password, disable_warnings=False): ++ self.username = username ++ self.password = password ++ self.valid_status_codes = [200, 202] ++ self.disable_warnings = disable_warnings ++ self.session = requests.Session() ++ self.session.auth = (self.username, self.password) ++ ++ retry_strategy = Retry(total=MAX_RETRIES, ++ backoff_factor=1, ++ status_forcelist=[429, 500, 503]) ++ ++ self.session.mount("https://", HTTPAdapter(max_retries=retry_strategy)) ++ ++ def request(self, url, method='GET', headers=None, **kwargs): ++ ++ if self.disable_warnings: ++ requests.packages.urllib3.disable_warnings() ++ ++ if headers: ++ self.session.headers.update(headers) ++ ++ response = None ++ ++ try: ++ logging.debug("Sending %s request to %s", method, url) ++ response = self.session.request(method, url, **kwargs) ++ response.raise_for_status() ++ except requests.exceptions.SSLError as err: ++ logging.error("Secure connection failed, verify SSL certificate") ++ logging.error("Error message: %s", err) ++ raise NutanixClientException("Secure connection failed") from err ++ except requests.exceptions.RequestException as err: ++ logging.error("API call failed: %s", response.text) ++ logging.error("Error message: %s", err) ++ raise NutanixClientException(f"API call failed: {err}") from err ++ except Exception as err: ++ logging.error("API call failed: %s", response.text) ++ logging.error("Unknown error %s", err) ++ raise NutanixClientException(f"API call failed: {err}") from err ++ ++ if response.status_code not in self.valid_status_codes: ++ logging.error("API call returned status code %s", response.status_code) ++ raise NutanixClientException(f"API call failed: {response}") ++ ++ return response ++ ++ ++class NutanixV4Client(NutanixClient): ++ def __init__(self, host=None, username=None, password=None, ++ verify=True, disable_warnings=False): ++ self.host = host ++ self.username = username ++ self.password = password ++ self.verify = verify ++ self.base_url = f"https://{self.host}:{PC_PORT}/api" ++ self.vm_url = f"{self.base_url}/vmm/v{V4_VERSION}/ahv/config/vms" ++ self.task_url = f"{self.base_url}/prism/v{V4_VERSION}/config/tasks" ++ super().__init__(username, password, disable_warnings) ++ ++ def _get_headers(self, vm_uuid=None): ++ resp = None ++ headers = {'Accept':'application/json', ++ 'Content-Type': 'application/json'} ++ ++ if vm_uuid: ++ try: ++ resp = self._get_vm(vm_uuid) ++ except AHVFenceAgentException as err: ++ logging.error("Unable to retrieve etag") ++ raise AHVFenceAgentException from err ++ ++ etag_str = resp.headers['Etag'] ++ request_id = str(uuid.uuid1()) ++ headers['If-Match'] = etag_str ++ headers['Ntnx-Request-Id'] = request_id ++ ++ return headers ++ ++ def _get_all_vms(self, filter_str=None, limit=None): ++ vm_url = self.vm_url ++ ++ if filter_str and limit: ++ vm_url = f"{vm_url}?$filter={filter_str}&$limit={limit}" ++ elif filter_str and not limit: ++ vm_url = f"{vm_url}?$filter={filter_str}" ++ elif limit and not filter_str: ++ vm_url = f"{vm_url}?$limit={limit}" ++ ++ logging.debug("Getting info for all VMs, %s", vm_url) ++ header_str = self._get_headers() ++ ++ try: ++ resp = self.request(url=vm_url, method='GET', ++ headers=header_str, verify=self.verify) ++ except NutanixClientException as err: ++ logging.error("Unable to retrieve VM info") ++ raise AHVFenceAgentException from err ++ ++ vms = resp.json() ++ return vms ++ ++ def _get_vm_uuid(self, vm_name): ++ vm_uuid = None ++ resp = None ++ ++ if not vm_name: ++ logging.error("VM name was not provided") ++ raise AHVFenceAgentException("VM name not provided") ++ ++ try: ++ filter_str = f"name eq '{vm_name}'" ++ resp = self._get_all_vms(filter_str=filter_str) ++ except AHVFenceAgentException as err: ++ logging.error("Failed to get VM info for VM %s", vm_name) ++ raise AHVFenceAgentException from err ++ ++ if not resp or not isinstance(resp, dict): ++ logging.error("Failed to retrieve VM UUID for VM %s", vm_name) ++ raise AHVFenceAgentException(f"Failed to get VM UUID for {vm_name}") ++ ++ if 'data' not in resp: ++ err = f"Error: Unsuccessful match for VM name: {vm_name}" ++ logging.error("Failed to retrieve VM UUID for VM %s", vm_name) ++ raise AHVFenceAgentException(err) ++ ++ for vm in resp['data']: ++ if vm['name'] == vm_name: ++ vm_uuid = vm['extId'] ++ break ++ ++ return vm_uuid ++ ++ def _get_vm(self, vm_uuid): ++ if not vm_uuid: ++ logging.error("VM UUID was not provided") ++ raise AHVFenceAgentException("VM UUID not provided") ++ ++ vm_url = self.vm_url + f"/{vm_uuid}" ++ logging.debug("Getting config information for VM, %s", vm_uuid) ++ ++ try: ++ header_str = self._get_headers() ++ resp = self.request(url=vm_url, method='GET', ++ headers=header_str, verify=self.verify) ++ except NutanixClientException as err: ++ logging.error("Failed to retrieve VM details " ++ "for VM UUID: %s", vm_uuid) ++ raise AHVFenceAgentException from err ++ except AHVFenceAgentException as err: ++ logging.error("Failed to retrieve etag from headers") ++ raise AHVFenceAgentException from err ++ ++ return resp ++ ++ def _power_on_off_vm(self, power_state=None, vm_uuid=None): ++ resp = None ++ vm_url = None ++ ++ if not vm_uuid: ++ logging.error("VM UUID was not provided") ++ raise AHVFenceAgentException("VM UUID not provided") ++ if not power_state: ++ logging.error("Requested VM power state is None") ++ raise InvalidArgsException ++ ++ power_state = power_state.lower() ++ ++ if power_state == 'on': ++ vm_url = self.vm_url + f"/{vm_uuid}/$actions/power-on" ++ logging.debug("Sending request to power on VM, %s", vm_uuid) ++ elif power_state == 'off': ++ vm_url = self.vm_url + f"/{vm_uuid}/$actions/power-off" ++ logging.debug("Sending request to power off VM, %s", vm_uuid) ++ else: ++ logging.error("Invalid power state specified: %s", power_state) ++ raise InvalidArgsException ++ ++ try: ++ headers_str = self._get_headers(vm_uuid) ++ resp = self.request(url=vm_url, method='POST', ++ headers=headers_str, verify=self.verify) ++ except NutanixClientException as err: ++ logging.error("Failed to power off VM %s", vm_uuid) ++ raise AHVFenceAgentException from err ++ except AHVFenceAgentException as err: ++ logging.error("Failed to retrieve etag from headers") ++ raise AHVFenceAgentException from err ++ ++ return resp ++ ++ def _power_cycle_vm(self, vm_uuid): ++ if not vm_uuid: ++ logging.error("VM UUID was not provided") ++ raise AHVFenceAgentException("VM UUID not provided") ++ ++ resp = None ++ vm_url = self.vm_url + f"/{vm_uuid}/$actions/power-cycle" ++ logging.debug("Sending request to power cycle VM, %s", vm_uuid) ++ ++ try: ++ header_str = self._get_headers(vm_uuid) ++ resp = self.request(url=vm_url, method='POST', ++ headers=header_str, verify=self.verify) ++ except NutanixClientException as err: ++ logging.error("Failed to power on VM %s", vm_uuid) ++ raise AHVFenceAgentException from err ++ except AHVFenceAgentException as err: ++ logging.error("Failed to retrieve etag from headers") ++ raise AHVFenceAgentException from err ++ ++ return resp ++ ++ def _wait_for_task(self, task_uuid, timeout=None): ++ if not task_uuid: ++ logging.error("Task UUID was not provided") ++ raise AHVFenceAgentException("Task UUID not provided") ++ ++ task_url = f"{self.task_url}/{task_uuid}" ++ header_str = self._get_headers() ++ task_resp = None ++ interval = 5 ++ task_status = None ++ ++ if not timeout: ++ timeout = MIN_TIMEOUT ++ else: ++ try: ++ timeout = int(timeout) ++ except ValueError: ++ timeout = MIN_TIMEOUT ++ ++ while task_status != 'SUCCEEDED': ++ if timeout <= 0: ++ raise TaskTimedOutException(f"Task timed out: {task_uuid}") ++ ++ time.sleep(interval) ++ timeout = timeout - interval ++ ++ try: ++ task_resp = self.request(url=task_url, method='GET', ++ headers=header_str, verify=self.verify) ++ task_status = task_resp.json()['data']['status'] ++ except NutanixClientException as err: ++ logging.error("Unable to retrieve task status") ++ raise AHVFenceAgentException from err ++ except Exception as err: ++ logging.error("Unknown error") ++ raise AHVFenceAgentException from err ++ ++ if task_status == 'FAILED': ++ raise AHVFenceAgentException(f"Task failed, task uuid: {task_uuid}") ++ ++ def list_vms(self, filter_str=None, limit=None): ++ vms = None ++ vm_list = {} ++ ++ try: ++ vms = self._get_all_vms(filter_str, limit) ++ except NutanixClientException as err: ++ logging.error("Failed to retrieve VM list") ++ raise AHVFenceAgentException from err ++ ++ if not vms or not isinstance(vms, dict): ++ logging.error("Failed to retrieve VM list") ++ raise AHVFenceAgentException("Unable to get VM list") ++ ++ if 'data' not in vms: ++ err = "Got invalid or empty VM list" ++ logging.debug(err) ++ else: ++ for vm in vms['data']: ++ vm_name = vm['name'] ++ ext_id = vm['extId'] ++ power_state = vm['powerState'] ++ vm_list[vm_name] = (ext_id, power_state) ++ ++ return vm_list ++ ++ def get_power_state(self, vm_name=None, vm_uuid=None): ++ resp = None ++ power_state = None ++ ++ if not vm_name and not vm_uuid: ++ logging.error("Require at least one of VM name or VM UUID") ++ raise InvalidArgsException("No arguments provided") ++ ++ if not vm_uuid: ++ try: ++ vm_uuid = self._get_vm_uuid(vm_name) ++ except AHVFenceAgentException as err: ++ logging.error("Unable to retrieve UUID of VM, %s", vm_name) ++ raise AHVFenceAgentException from err ++ ++ try: ++ resp = self._get_vm(vm_uuid) ++ except AHVFenceAgentException as err: ++ logging.error("Unable to retrieve power state of VM %s", vm_uuid) ++ raise AHVFenceAgentException from err ++ ++ try: ++ power_state = resp.json()['data']['powerState'] ++ except AHVFenceAgentException as err: ++ logging.error("Failed to retrieve power state of VM %s", vm_uuid) ++ raise AHVFenceAgentException from err ++ ++ return POWER_STATES[power_state] ++ ++ def set_power_state(self, vm_name=None, vm_uuid=None, ++ power_state='off', timeout=None): ++ resp = None ++ current_power_state = None ++ power_state = power_state.lower() ++ ++ if not timeout: ++ timeout = MIN_TIMEOUT ++ ++ if not vm_name and not vm_uuid: ++ logging.error("Require at least one of VM name or VM UUID") ++ raise InvalidArgsException("No arguments provided") ++ ++ if not vm_uuid: ++ vm_uuid = self._get_vm_uuid(vm_name) ++ ++ try: ++ current_power_state = self.get_power_state(vm_uuid=vm_uuid) ++ except AHVFenceAgentException as err: ++ raise AHVFenceAgentException from err ++ ++ if current_power_state.lower() == power_state.lower(): ++ logging.debug("VM already powered %s", power_state.lower()) ++ return ++ ++ if power_state.lower() == 'on': ++ resp = self._power_on_off_vm(power_state, vm_uuid) ++ elif power_state.lower() == 'off': ++ resp = self._power_on_off_vm(power_state, vm_uuid) ++ ++ task_id = resp.json()['data']['extId'] ++ ++ try: ++ self._wait_for_task(task_id, timeout) ++ except AHVFenceAgentException as err: ++ logging.error("Failed to power %s VM", power_state.lower()) ++ logging.error("VM power %s task failed", power_state.lower()) ++ raise AHVFenceAgentException from err ++ except TaskTimedOutException as err: ++ logging.error("Timed out powering %s VM %s", ++ power_state.lower(), vm_uuid) ++ raise TaskTimedOutException from err ++ ++ logging.debug("Powered %s VM, %s successfully", ++ power_state.lower(), vm_uuid) ++ ++ def power_cycle_vm(self, vm_name=None, vm_uuid=None, timeout=None): ++ resp = None ++ status = None ++ ++ if not timeout: ++ timeout = MIN_TIMEOUT ++ ++ if not vm_name and not vm_uuid: ++ logging.error("Require at least one of VM name or VM UUID") ++ raise InvalidArgsException("No arguments provided") ++ ++ if not vm_uuid: ++ vm_uuid = self._get_vm_uuid(vm_name) ++ ++ resp = self._power_cycle_vm(vm_uuid) ++ task_id = resp.json()['data']['extId'] ++ ++ try: ++ self._wait_for_task(task_id, timeout) ++ except AHVFenceAgentException as err: ++ logging.error("Failed to power-cycle VM %s", vm_uuid) ++ logging.error("VM power-cycle task failed with status, %s", status) ++ raise AHVFenceAgentException from err ++ except TaskTimedOutException as err: ++ logging.error("Timed out power-cycling VM %s", vm_uuid) ++ raise TaskTimedOutException from err ++ ++ ++ logging.debug("Power-cycled VM, %s", vm_uuid) ++ ++ ++def connect(options): ++ host = options["--ip"] ++ username = options["--username"] ++ password = options["--password"] ++ verify_ssl = True ++ disable_warnings = False ++ ++ if "--ssl-insecure" in options: ++ verify_ssl = False ++ disable_warnings = True ++ ++ client = NutanixV4Client(host, username, password, ++ verify_ssl, disable_warnings) ++ ++ try: ++ client.list_vms(limit=1) ++ except AHVFenceAgentException as err: ++ logging.error("Connection to Prism Central Failed") ++ logging.error(err) ++ fail(EC_LOGIN_DENIED) ++ ++ return client ++ ++def get_list(client, options): ++ vm_list = None ++ ++ filter_str = options.get("--filter", None) ++ limit = options.get("--limit", None) ++ ++ try: ++ vm_list = client.list_vms(filter_str, limit) ++ except AHVFenceAgentException as err: ++ logging.error("Failed to list VMs") ++ logging.error(err) ++ fail(EC_GENERIC_ERROR) ++ ++ return vm_list ++ ++def get_power_status(client, options): ++ vmid = None ++ name = None ++ power_state = None ++ ++ vmid = options.get("--uuid", None) ++ name = options.get("--plug", None) ++ ++ if not vmid and not name: ++ logging.error("Need VM name or VM UUID for power op") ++ fail(EC_BAD_ARGS) ++ try: ++ power_state = client.get_power_state(vm_name=name, vm_uuid=vmid) ++ except AHVFenceAgentException: ++ fail(EC_GENERIC_ERROR) ++ except InvalidArgsException: ++ fail(EC_BAD_ARGS) ++ ++ return power_state ++ ++def set_power_status(client, options): ++ action = options["--action"].lower() ++ timeout = options.get("--power-timeout", None) ++ vmid = options.get("--uuid", None) ++ name = options.get("--plug", None) ++ ++ if not name and not vmid: ++ logging.error("Need VM name or VM UUID to set power state of a VM") ++ fail(EC_BAD_ARGS) ++ ++ try: ++ client.set_power_state(vm_name=name, vm_uuid=vmid, ++ power_state=action, timeout=timeout) ++ except AHVFenceAgentException as err: ++ logging.error(err) ++ fail(EC_GENERIC_ERROR) ++ except TaskTimedOutException as err: ++ logging.error(err) ++ fail(EC_TIMED_OUT) ++ except InvalidArgsException: ++ fail(EC_BAD_ARGS) ++ ++def power_cycle(client, options): ++ timeout = options.get("--power-timeout", None) ++ vmid = options.get("--uuid", None) ++ name = options.get("--plug", None) ++ ++ if not name and not vmid: ++ logging.error("Need VM name or VM UUID to set power cycling a VM") ++ fail(EC_BAD_ARGS) ++ ++ try: ++ client.power_cycle_vm(vm_name=name, vm_uuid=vmid, timeout=timeout) ++ except AHVFenceAgentException as err: ++ logging.error(err) ++ fail(EC_GENERIC_ERROR) ++ except TaskTimedOutException as err: ++ logging.error(err) ++ fail(EC_TIMED_OUT) ++ except InvalidArgsException: ++ fail(EC_BAD_ARGS) ++ ++def define_new_opts(): ++ all_opt["filter"] = { ++ "getopt": ":", ++ "longopt": "filter", ++ "help": """ ++ --filter=[filter] Filter list, list VMs actions. ++ --filter=\"name eq 'node1-vm'\" ++ --filter=\"startswith(name,'node')\" ++ --filter=\"name in ('node1-vm','node-3-vm')\" """, ++ "required": "0", ++ "shortdesc": "Filter list, get_list" ++ "e.g: \"name eq 'node1-vm'\"", ++ "order": 2 ++ } ++ ++def main(): ++ device_opt = [ ++ "ipaddr", ++ "login", ++ "passwd", ++ "ssl", ++ "notls", ++ "web", ++ "port", ++ "filter", ++ "method", ++ "disable_timeout", ++ "power_timeout" ++ ] ++ ++ atexit.register(atexit_handler) ++ define_new_opts() ++ ++ all_opt["power_timeout"]["default"] = str(MIN_TIMEOUT) ++ options = check_input(device_opt, process_input(device_opt)) ++ docs = {} ++ docs["shortdesc"] = "Fencing agent for Nutanix AHV Cluster VMs." ++ docs["longdesc"] = """fence_ahv is a power fencing agent for \ ++virtual machines deployed on Nutanix AHV cluster with the AHV cluster \ ++being managed by Prism Central.""" ++ docs["vendorurl"] = "https://www.nutanix.com" ++ show_docs(options, docs) ++ run_delay(options) ++ client = connect(options) ++ ++ result = fence_action(client, options, set_power_status, get_power_status, ++ get_list, reboot_cycle_fn=power_cycle ++ ) ++ ++ sys.exit(result) ++ ++ ++if __name__ == "__main__": ++ main() +--- a/tests/data/metadata/fence_nutanix_ahv.xml 1970-01-01 01:00:00.000000000 +0100 ++++ b/tests/data/metadata/fence_nutanix_ahv.xml 2025-02-25 16:27:56.959413680 +0100 +@@ -0,0 +1,201 @@ ++ ++ ++fence_ahv is a power fencing agent for virtual machines deployed on Nutanix AHV cluster with the AHV cluster being managed by Prism Central. ++https://www.nutanix.com ++ ++ ++ ++ ++ Fencing action ++ ++ ++ ++ ++ IP address or hostname of fencing device ++ ++ ++ ++ ++ IP address or hostname of fencing device ++ ++ ++ ++ ++ TCP/UDP port to use for connection with device ++ ++ ++ ++ ++ Login name ++ ++ ++ ++ ++ ++ Method to fence ++ ++ ++ ++ ++ Disable TLS negotiation and force SSL3.0. This should only be used for devices that do not support TLS1.0 and up. ++ ++ ++ ++ ++ Login password or passphrase ++ ++ ++ ++ ++ Script to run to retrieve password ++ ++ ++ ++ ++ Login password or passphrase ++ ++ ++ ++ ++ Script to run to retrieve password ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Physical plug number on device, UUID or identification of machine ++ ++ ++ ++ ++ Use SSL connection with verifying certificate ++ ++ ++ ++ ++ Use SSL connection without verifying certificate ++ ++ ++ ++ ++ Use SSL connection with verifying certificate ++ ++ ++ ++ ++ Login name ++ ++ ++ ++ ++ Filter list, get_liste.g: "name eq 'node1-vm'" ++ ++ ++ ++ ++ Disable logging to stderr. Does not affect --verbose or --debug-file or logging to syslog. ++ ++ ++ ++ ++ Verbose mode. Multiple -v flags can be stacked on the command line (e.g., -vvv) to increase verbosity. ++ ++ ++ ++ ++ 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). ++ ++ ++ ++ ++ Write debug information to given file ++ ++ ++ ++ Write debug information to given file ++ ++ ++ ++ ++ Display version information and exit ++ ++ ++ ++ ++ Display help and exit ++ ++ ++ ++ ++ Separator for plug parameter when specifying more than 1 plug ++ ++ ++ ++ ++ Separator for CSV created by 'list' operation ++ ++ ++ ++ ++ Wait X seconds before fencing is started ++ ++ ++ ++ ++ Disable timeout (true/false) (default: true when run from Pacemaker 2.0+) ++ ++ ++ ++ ++ Wait X seconds for cmd prompt after login ++ ++ ++ ++ ++ Test X seconds for status change after ON/OFF ++ ++ ++ ++ ++ Wait X seconds after issuing ON/OFF ++ ++ ++ ++ ++ Wait X seconds for cmd prompt after issuing command ++ ++ ++ ++ ++ Sleep X seconds between status calls during a STONITH action ++ ++ ++ ++ ++ Count of attempts to retry power on ++ ++ ++ ++ Path to gnutls-cli binary ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ diff --git a/SOURCES/RHEL-68321-2-fence_nutanix_ahv-update-metadata.patch b/SOURCES/RHEL-68321-2-fence_nutanix_ahv-update-metadata.patch new file mode 100644 index 0000000..ccd6867 --- /dev/null +++ b/SOURCES/RHEL-68321-2-fence_nutanix_ahv-update-metadata.patch @@ -0,0 +1,39 @@ +From 345a609a34ea153e168b15d48eb8f2dd8d017f04 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 23 Apr 2025 15:25:13 +0200 +Subject: [PATCH] fence_nutanix_ahv: update metadata to fix incorrect agent + name and align with other agents metadata + +--- + agents/nutanix_ahv/fence_nutanix_ahv.py | 4 ++-- + tests/data/metadata/fence_nutanix_ahv.xml | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/agents/nutanix_ahv/fence_nutanix_ahv.py b/agents/nutanix_ahv/fence_nutanix_ahv.py +index 67e6d907c..c18d6a46e 100644 +--- a/agents/nutanix_ahv/fence_nutanix_ahv.py ++++ b/agents/nutanix_ahv/fence_nutanix_ahv.py +@@ -563,8 +563,8 @@ def main(): + all_opt["power_timeout"]["default"] = str(MIN_TIMEOUT) + options = check_input(device_opt, process_input(device_opt)) + docs = {} +- docs["shortdesc"] = "Fencing agent for Nutanix AHV Cluster VMs." +- docs["longdesc"] = """fence_ahv is a power fencing agent for \ ++ docs["shortdesc"] = "Fence agent for Nutanix AHV Cluster VMs." ++ docs["longdesc"] = """fence_nutanix_ahv is a Power Fencing agent for \ + virtual machines deployed on Nutanix AHV cluster with the AHV cluster \ + being managed by Prism Central.""" + docs["vendorurl"] = "https://www.nutanix.com" +diff --git a/tests/data/metadata/fence_nutanix_ahv.xml b/tests/data/metadata/fence_nutanix_ahv.xml +index bbc307b1d..2de4b01ad 100644 +--- a/tests/data/metadata/fence_nutanix_ahv.xml ++++ b/tests/data/metadata/fence_nutanix_ahv.xml +@@ -1,6 +1,6 @@ + +- +-fence_ahv is a power fencing agent for virtual machines deployed on Nutanix AHV cluster with the AHV cluster being managed by Prism Central. ++ ++fence_nutanix_ahv is a Power Fencing agent for virtual machines deployed on Nutanix AHV cluster with the AHV cluster being managed by Prism Central. + https://www.nutanix.com + + diff --git a/SOURCES/RHEL-109923-fence_aws-add-skipshutdown-parameter.patch b/SOURCES/RHEL-7601-fence_aws-add-skipshutdown-parameter.patch similarity index 98% rename from SOURCES/RHEL-109923-fence_aws-add-skipshutdown-parameter.patch rename to SOURCES/RHEL-7601-fence_aws-add-skipshutdown-parameter.patch index 747b97e..ca1548b 100644 --- a/SOURCES/RHEL-109923-fence_aws-add-skipshutdown-parameter.patch +++ b/SOURCES/RHEL-7601-fence_aws-add-skipshutdown-parameter.patch @@ -61,7 +61,7 @@ index 5459a06c4..cddca4580 100644 + "help" : "--skip-os-shutdown=[true|false] Uses SkipOsShutdown flag", + "shortdesc" : "Use SkipOsShutdown flag to stop the EC2 instance", + "required" : "0", -+ "default" : "false", ++ "default" : "true", + "order" : 8 + } @@ -84,7 +84,7 @@ index ad471c797..c53873bbe 100644 + + -+ ++ + Use SkipOsShutdown flag to stop the EC2 instance + diff --git a/SOURCES/RHEL-92695-2-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch b/SOURCES/RHEL-79798-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch similarity index 100% rename from SOURCES/RHEL-92695-2-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch rename to SOURCES/RHEL-79798-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch diff --git a/SOURCES/RHEL-96183-fence_kubevirt-force-off.patch b/SOURCES/RHEL-82193-fence_kubevirt-force-off.patch similarity index 100% rename from SOURCES/RHEL-96183-fence_kubevirt-force-off.patch rename to SOURCES/RHEL-82193-fence_kubevirt-force-off.patch diff --git a/SOURCES/RHEL-83488-fence_ibm_vpc-refresh-bearer-token.patch b/SOURCES/RHEL-83255-fence_ibm_vpc-refresh-bearer-token.patch similarity index 100% rename from SOURCES/RHEL-83488-fence_ibm_vpc-refresh-bearer-token.patch rename to SOURCES/RHEL-83255-fence_ibm_vpc-refresh-bearer-token.patch diff --git a/SOURCES/RHEL-84448-fence_compute-fence_evacuate-dont-use-deprecated-getargspec.patch b/SOURCES/RHEL-84448-fence_compute-fence_evacuate-dont-use-deprecated-getargspec.patch new file mode 100644 index 0000000..8942c92 --- /dev/null +++ b/SOURCES/RHEL-84448-fence_compute-fence_evacuate-dont-use-deprecated-getargspec.patch @@ -0,0 +1,38 @@ +From deadda03cb331b766d83e332f06af9a53906a2a8 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 21 Mar 2025 12:21:06 +0100 +Subject: [PATCH] fence_compute/fence_evacuate: dont use deprecated + inspect.getargspec() + +/usr/sbin/fence_compute:288: DeprecationWarning: inspect.getargspec() is deprecated since Python 3.0, use inspect.signature() or inspect.getfullargspec() +--- + agents/compute/fence_compute.py | 2 +- + agents/evacuate/fence_evacuate.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/agents/compute/fence_compute.py b/agents/compute/fence_compute.py +index d862dca3f..01b535bb3 100644 +--- a/agents/compute/fence_compute.py ++++ b/agents/compute/fence_compute.py +@@ -285,7 +285,7 @@ def create_nova_connection(options): + + nova_versions = [ "2.11", "2" ] + for version in nova_versions: +- clientargs = inspect.getargspec(client.Client).varargs ++ clientargs = inspect.getfullargspec(client.Client).varargs + # Some versions of Openstack prior to Ocata only + # supported positional arguments for username, + # password, and tenant. +diff --git a/agents/evacuate/fence_evacuate.py b/agents/evacuate/fence_evacuate.py +index 53d6fd15b..1ea020f69 100644 +--- a/agents/evacuate/fence_evacuate.py ++++ b/agents/evacuate/fence_evacuate.py +@@ -221,7 +221,7 @@ def create_nova_connection(options): + + versions = [ "2.11", "2" ] + for version in versions: +- clientargs = inspect.getargspec(client.Client).varargs ++ clientargs = inspect.getfullargspec(client.Client).varargs + + # Some versions of Openstack prior to Ocata only + # supported positional arguments for username, diff --git a/SOURCES/RHEL-88568-fence_ibm_powervs-fix-plaintext-token-file-support.patch b/SOURCES/RHEL-88568-fence_ibm_powervs-fix-plaintext-token-file-support.patch new file mode 100644 index 0000000..3eeb9c7 --- /dev/null +++ b/SOURCES/RHEL-88568-fence_ibm_powervs-fix-plaintext-token-file-support.patch @@ -0,0 +1,21 @@ +From 988cbd9fb600261106d5da1db6a7bf9cde218eaa Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 25 Apr 2025 16:38:03 +0200 +Subject: [PATCH] fence_ibm_powervs: fix plaintext token file support + +--- + agents/ibm_powervs/fence_ibm_powervs.py | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/agents/ibm_powervs/fence_ibm_powervs.py b/agents/ibm_powervs/fence_ibm_powervs.py +index ec9a0c11d..d408e8727 100755 +--- a/agents/ibm_powervs/fence_ibm_powervs.py ++++ b/agents/ibm_powervs/fence_ibm_powervs.py +@@ -35,6 +35,7 @@ def get_token(conn, options): + api_key = keys.get("apikey", "") + # data is text, return as is + except ValueError: ++ f.seek(0) + api_key = f.read().strip() + except FileNotFoundError: + logging.debug("Failed: Cannot open file {}".format(key_file)) diff --git a/SOURCES/RHEL-95903-pkg_resources-suppress-UserWarning.patch b/SOURCES/RHEL-95901-pkg_resources-suppress-UserWarning.patch similarity index 100% rename from SOURCES/RHEL-95903-pkg_resources-suppress-UserWarning.patch rename to SOURCES/RHEL-95901-pkg_resources-suppress-UserWarning.patch diff --git a/SPECS/fence-agents.spec b/SPECS/fence-agents.spec index 103b481..73d72dc 100644 --- a/SPECS/fence-agents.spec +++ b/SPECS/fence-agents.spec @@ -57,7 +57,7 @@ Name: fence-agents Summary: Set of unified programs capable of host isolation ("fencing") Version: 4.10.0 -Release: 86%{?alphatag:.%{alphatag}}%{?dist}.11 +Release: 98%{?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 @@ -244,12 +244,16 @@ Patch59: RHEL-56138-fence_mpath-1-support-hex-key-format.patch Patch60: RHEL-56138-fence_mpath-2-fix-unfencing-issue-use-MULTILINE-avoid-duplicates.patch Patch61: RHEL-62206-fence_ibm_powervs-add-private-endpoint-and-token-file-support.patch Patch62: RHEL-76493-fence_azure_arm-use-azure-identity.patch -Patch63: RHEL-83488-fence_ibm_vpc-refresh-bearer-token.patch -Patch64: RHEL-92695-1-fence_sbd-improve-error-handling.patch -Patch65: RHEL-92695-2-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch -Patch66: RHEL-107529-fence_ibm_vpc-add-apikey-file-support.patch -Patch67: RHEL-109923-fence_aws-add-skipshutdown-parameter.patch -Patch68: RHEL-96183-fence_kubevirt-force-off.patch +Patch63: RHEL-83255-fence_ibm_vpc-refresh-bearer-token.patch +Patch64: RHEL-84448-fence_compute-fence_evacuate-dont-use-deprecated-getargspec.patch +Patch65: RHEL-79798-fence_sbd-get-devices-from-SBD_DEVICE-if-devices-parameter-isnt-set.patch +Patch66: RHEL-68321-1-fence_nutanix_ahv.patch +Patch67: RHEL-68321-2-fence_nutanix_ahv-update-metadata.patch +Patch68: RHEL-88568-fence_ibm_powervs-fix-plaintext-token-file-support.patch +Patch69: RHEL-13088-fence_sbd-improve-error-handling.patch +Patch70: RHEL-82193-fence_kubevirt-force-off.patch +Patch71: RHEL-107505-fence_ibm_vpc-add-apikey-file-support.patch +Patch72: RHEL-7601-fence_aws-add-skipshutdown-parameter.patch ### HA support libs/utils ### # all archs @@ -257,9 +261,9 @@ Patch1000: bz2217902-1-kubevirt-fix-bundled-dateutil-CVE-2007-4559.patch # cloud (x86_64 only) Patch2000: bz2217902-2-aws-azure-fix-bundled-dateutil-CVE-2007-4559.patch Patch2001: RHEL-43562-fix-bundled-urllib3-CVE-2024-37891.patch -Patch2002: RHEL-95903-pkg_resources-suppress-UserWarning.patch +Patch2002: RHEL-95901-pkg_resources-suppress-UserWarning.patch -%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt lpar mpath redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti +%global supportedagents amt_ws apc apc_snmp bladecenter brocade cisco_mds cisco_ucs compute drac5 eaton_snmp emerson eps evacuate hpblade ibmblade ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp ilo_ssh intelmodular ipdu ipmilan kdump kubevirt lpar mpath nutanix_ahv redfish rhevm rsa rsb sbd scsi vmware_rest vmware_soap wti %ifarch x86_64 %global testagents virsh heuristics_ping aliyun aws azure_arm gce openstack virt %endif @@ -438,8 +442,12 @@ BuildRequires: %{systemd_units} %patch -p1 -P 64 %patch -p1 -P 65 %patch -p1 -P 66 -%patch -p1 -P 67 -F2 +%patch -p1 -P 67 %patch -p1 -P 68 +%patch -p1 -P 69 +%patch -p1 -P 70 +%patch -p1 -P 71 +%patch -p1 -P 72 -F2 # prevent compilation of something that won't get used anyway sed -i.orig 's|FENCE_ZVM=1|FENCE_ZVM=0|' configure.ac @@ -1283,6 +1291,19 @@ Device Mapper Multipath. %{_datadir}/cluster/fence_mpath_check* %{_mandir}/man8/fence_mpath.8* +%package nutanix-ahv +License: GPL-2.0-or-later AND LGPL-2.0-or-later +Summary: Fence agent for Nutanix AHV +Requires: python3-requests +Requires: fence-agents-common = %{version}-%{release} +BuildArch: noarch +Obsoletes: fence-agents < 3.1.13 +%description nutanix-ahv +Fence agent for Nutanix AHV clusters. +%files nutanix-ahv +%{_sbindir}/fence_nutanix_ahv +%{_mandir}/man8/fence_nutanix_ahv.8* + %ifarch x86_64 ppc64le %package openstack License: GPLv2+ and LGPLv2+ @@ -1547,31 +1568,45 @@ are located on corosync cluster nodes. %endif %changelog -* Thu Sep 11 2025 Oyvind Albrigtsen - 4.10.0-86.11 -- fence_kubevirt: use hard poweroff - Resolves: RHEL-96183 - -* Tue Aug 19 2025 Oyvind Albrigtsen - 4.10.0-86.10 +* Tue Aug 19 2025 Oyvind Albrigtsen - 4.10.0-98 - fence_aws: add "skip_os_shutdown" parameter to allow hard poweroff - Resolves: RHEL-109923 + Resolves: RHEL-7601 -* Tue Aug 12 2025 Oyvind Albrigtsen - 4.10.0-86.9 +* Tue Aug 12 2025 Oyvind Albrigtsen - 4.10.0-97 - fence_ibm_vpc: add apikey file support - Resolves: RHEL-107529 + Resolves: RHEL-107505 -* Thu Jul 17 2025 Oyvind Albrigtsen - 4.10.0-86.8 +* Thu Jun 26 2025 Oyvind Albrigtsen - 4.10.0-96 - bundled setuptools: fix CVE-2025-47273 - Resolves: RHEL-95903 + Resolves: RHEL-95901 -* Wed May 21 2025 Oyvind Albrigtsen - 4.10.0-86.4 -- fence_sbd: improve error handling and get devices from SBD_DEVICE env - variable if devices parameter isnt set - Resolves: RHEL-92695 +* Thu Jun 12 2025 Oyvind Albrigtsen - 4.10.0-95 +- fence_kubevirt: use hard poweroff + Resolves: RHEL-82193 -* Fri Mar 14 2025 Oyvind Albrigtsen - 4.10.0-86.3 +* Wed May 21 2025 Oyvind Albrigtsen - 4.10.0-92 +- fence_sbd: improve error handling + Resolves: RHEL-13088 + +* Mon Apr 28 2025 Oyvind Albrigtsen - 4.10.0-91 +- fence_ibm_powervs: fix plaintext token file support + Resolves: RHEL-88568 + +* Wed Apr 23 2025 Oyvind Albrigtsen - 4.10.0-90 +- fence_nutanix_ahv: new fence agent + Resolves: RHEL-68321 + +* Tue Mar 25 2025 Oyvind Albrigtsen - 4.10.0-88 +- fence_compute/fence_evacuate: dont use deprecated inspect.getargspec() + Resolves: RHEL-84448 +- fence_sbd: get devices from SBD_DEVICE env variable if devices + parameter isnt set + Resolves: RHEL-79798 + +* Fri Mar 14 2025 Oyvind Albrigtsen - 4.10.0-87 - fence_ibm_vpc: refresh bearer-token if token data is corrupt, and avoid edge-case of writing empty token file - Resolves: RHEL-83488 + Resolves: RHEL-83255 * Tue Mar 11 2025 Oyvind Albrigtsen - 4.10.0-86 - bundled jinja2: fix CVE-2025-27516