Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package fence-agents for openSUSE:Factory 
checked in at 2026-02-25 21:12:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/fence-agents (Old)
 and      /work/SRC/openSUSE:Factory/.fence-agents.new.1977 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "fence-agents"

Wed Feb 25 21:12:40 2026 rev:92 rq:1335070 version:4.17.0+git.1769693386.608dd62

Changes:
--------
--- /work/SRC/openSUSE:Factory/fence-agents/fence-agents.changes        
2025-12-25 19:57:55.751934437 +0100
+++ /work/SRC/openSUSE:Factory/.fence-agents.new.1977/fence-agents.changes      
2026-02-25 21:21:54.786179795 +0100
@@ -1,0 +2,9 @@
+Mon Feb 23 19:09:44 UTC 2026 - [email protected]
+
+- Update to version 4.17.0+git.1769693386.608dd62:
+  * fence_ibm_vpc: fix indentation
+  * fence_dummy: add recorder mode for testing fence_recorder protocol (#647)
+  * Enhancement: better alpine compatibility (#648)
+  * fence_scsi: add "mpath_register_method" parameter to allow only 
registering to the main multipath device
+
+-------------------------------------------------------------------

Old:
----
  fence-agents-4.16.0+git.1765293331.d30fb54b.tar.xz

New:
----
  fence-agents-4.17.0+git.1769693386.608dd62.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ fence-agents.spec ++++++
--- /var/tmp/diff_new_pack.in7I3K/_old  2026-02-25 21:21:55.430206239 +0100
+++ /var/tmp/diff_new_pack.in7I3K/_new  2026-02-25 21:21:55.430206239 +0100
@@ -1,6 +1,7 @@
 #
 # spec file for package fence-agents
 #
+# Copyright (c) 2026 SUSE LLC
 # Copyright (c) 2025 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
@@ -19,7 +20,7 @@
 %define agent_list aliyun alom apc apc_snmp aws azure_arm bladecenter brocade 
cisco_mds cisco_ucs drac5 dummy eaton_snmp eaton_ssh emerson eps evacuate gce 
hds_cb hpblade ibmblade ibmz ibm_powervs ibm_vpc ifmib ilo ilo_moonshot ilo_mp 
ilo_ssh intelmodular ipdu ipmilan ironic kdump lpar mpath netio nutanix_ahv 
powerman pve raritan rcd_serial redfish rsa rsb sanbox2 sbd scsi vbox virsh 
vmware vmware_rest wti zvm
 Name:           fence-agents
 Summary:        Set of unified programs capable of host isolation ("fencing")
-Version:        4.16.0+git.1765293331.d30fb54b
+Version:        4.17.0+git.1769693386.608dd62
 Release:        0
 License:        GPL-2.0-or-later AND LGPL-2.0-or-later
 Group:          Productivity/Clustering/HA

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.in7I3K/_old  2026-02-25 21:21:55.486208539 +0100
+++ /var/tmp/diff_new_pack.in7I3K/_new  2026-02-25 21:21:55.490208703 +0100
@@ -3,6 +3,6 @@
             <param 
name="url">git://github.com/ClusterLabs/fence-agents.git</param>
           <param 
name="changesrevision">8d746be92f191aa289f13a3703031c122a5e6cf3</param></service><service
 name="tar_scm">
                 <param 
name="url">https://github.com/ClusterLabs/fence-agents</param>
-              <param 
name="changesrevision">d30fb54bb7dce92af8c67ca01b3e410552c4183b</param></service></servicedata>
+              <param 
name="changesrevision">608dd62f4d213f8583e96fc5b2e2bd65b0d25108</param></service></servicedata>
 (No newline at EOF)
 

++++++ fence-agents-4.16.0+git.1765293331.d30fb54b.tar.xz -> 
fence-agents-4.17.0+git.1769693386.608dd62.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/.gitignore 
new/fence-agents-4.17.0+git.1769693386.608dd62/.gitignore
--- old/fence-agents-4.16.0+git.1765293331.d30fb54b/.gitignore  1970-01-01 
01:00:00.000000000 +0100
+++ new/fence-agents-4.17.0+git.1769693386.608dd62/.gitignore   2026-01-29 
14:29:46.000000000 +0100
@@ -0,0 +1,75 @@
+*.orig
+*.rej
+*.swp
+Makefile.in
+aclocal.m4
+autoconf
+autoheader
+autom4te.cache
+automake
+autoscan.log
+compile
+configure
+configure.scan
+config.guess
+config.log
+config.sub
+config.status
+Makefile
+depcomp
+install-sh
+libtoolize
+ltmain.sh
+libtool
+make/stamp-h1
+
+# ignore "libtoolized" m4 files, but keep our (enumerated) ones
+/m4/*
+!/m4/ac_python_module.m4
+!/m4/ax*.m4
+
+# make/release.mk related litter
+/.tarball-version
+/tag-*
+
+make/config.h*
+missing
+*.pc
+.deps
+.libs
+*.o
+*.la
+*.lo
+lib/*.py*
+lib/__pycache__
+!lib/*.py.py
+!lib/check_used_options.py
+agents/*/fence_*
+agents/*/.dirstamp
+!agents/*/fence_*.py
+!agents/*/fence_*.c
+!agents/*/fence_*.h
+!agents/kdump/fence_kdump_send.8
+!agents/manual/fence_ack_manual.8
+!agents/zvm/fence_zvm_man_page
+.fence*.tmp
+fence-agents*
+.version
+tests/devices.d/*
+
+y.tab.*
+*.o
+*.lo
+*.la
+.deps
+.libs
+.*version
+*.swp
+agents/virt/client/fence_virt
+agents/virt/client/fence_xvm
+agents/virt/common/libfence_virt.a
+agents/virt/config/config.c
+agents/virt/config/libsimpleconfig.a
+agents/virt/fence_virtd.service
+agents/virt/server/fence_virtd
+fence-virt-*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/dummy/README.md 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/dummy/README.md
--- old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/dummy/README.md      
1970-01-01 01:00:00.000000000 +0100
+++ new/fence-agents-4.17.0+git.1769693386.608dd62/agents/dummy/README.md       
2026-01-29 14:29:46.000000000 +0100
@@ -0,0 +1,352 @@
+# fence_dummy - Testing and Simulation Fence Agent
+
+## Overview
+
+`fence_dummy` is a fence agent for development, testing, and simulation. It 
supports three operating modes:
+
+1. **file** - Status stored in a file (default)
+2. **fail** - Simulated failure scenarios
+3. **recorder** - Request/response coordination with external systems
+
+---
+
+---
+
+## File Mode (Default)
+
+The **file mode** (default) stores power status in a simple text file, making 
it useful for basic testing without complex infrastructure.
+
+### How It Works
+
+- Reads/writes node power state from/to a status file
+- `on` action: Writes "on" to the file
+- `off` action: Writes "off" to the file  
+- `status` action: Reads current state from file (returns "off" if file 
missing)
+- File persists across invocations for state tracking
+
+### Use Cases
+
+- **Basic fence agent testing** in development
+- **Simple state tracking** without external dependencies
+- **Unit testing** fence workflows
+- **Learning fence agent behavior** in isolation
+
+### Configuration
+
+```bash
+# Direct CLI usage
+fence_dummy --plug node1 --action off --status-file /tmp/node1.status
+fence_dummy --plug node1 --action status --status-file /tmp/node1.status
+
+# Create STONITH resource
+pcs stonith create file-fence fence_dummy \
+    plug=compute-node-1 \
+    status_file=/tmp/compute-node-1.status
+```
+
+### Options (File Mode)
+
+| Option | Default | Description |
+| ------ | ------- | ----------- |
+| `--type` | `file` | Mode (default, can be omitted) |
+| `--plug` | (optional) | Node identifier (not used for file operations) |
+| `--status-file` | `/tmp/fence_dummy.status` | File storing power state |
+
+### Example
+
+```bash
+# Turn off node
+$ fence_dummy --plug node1 --action off --status-file /tmp/node1.status
+$ cat /tmp/node1.status
+off
+
+# Check status
+$ fence_dummy --plug node1 --action status --status-file /tmp/node1.status
+Status: OFF
+
+# Turn on node
+$ fence_dummy --plug node1 --action on --status-file /tmp/node1.status
+$ cat /tmp/node1.status
+on
+```
+
+---
+
+## Fail Mode
+
+The **fail mode** (`--type=fail`) simulates fence device failures and 
unexpected behaviors for testing error handling.
+
+### How It Works
+
+- Returns power state **opposite** of what's expected
+- `status` returns random on/off state for specified plug
+- `list` returns a predefined list of fake outlets
+- Useful for testing Pacemaker error recovery and retry logic
+
+### Use Cases
+
+- **Testing error handling** in cluster configurations
+- **Validating retry logic** in Pacemaker
+- **Simulating unreliable fence devices** during development
+- **Chaos engineering** for HA clusters
+
+### Configuration
+
+```bash
+# Direct CLI usage
+fence_dummy --plug node1 --type=fail --action status
+
+# Create STONITH resource (NOT recommended for production!)
+pcs stonith create fail-fence fence_dummy \
+    type=fail \
+    plug=compute-node-1
+```
+
+### Options (Fail Mode)
+
+| Option | Default | Description |
+| ------ | ------- | ----------- |
+| `--type` | `file` | Set to `fail` for failure simulation |
+| `--plug` | (required) | Target outlet/node |
+
+### Behavior
+
+- **`list` action**: Returns fake outlet list `["1", "2"]`
+- **`status` action**: Returns random state (inconsistent results)
+- **`on`/`off` actions**: Succeed but state queries will be inconsistent
+- **`monitor` action**: Returns success (agent is "working")
+
+### Example
+
+```bash
+$ fence_dummy --plug 1 --type=fail --action list
+1,2
+
+$ fence_dummy --plug 1 --type=fail --action status
+Status: ON
+
+$ fence_dummy --plug 1 --type=fail --action status
+Status: OFF  # Inconsistent!
+```
+
+---
+
+## Recorder Mode
+
+The **recorder mode** (`--type=recorder`) implements the fence_recorder 
request/response pattern for coordinating fencing with external systems via 
files.
+
+### How It Works
+
+```text
+Pacemaker → fence_dummy (recorder mode)
+              ↓
+         Write request file
+              ↓
+         Wait for response
+              ↓
+         External system writes response
+              ↓
+         Read response & exit
+```
+
+### Use Cases
+
+- **Testing fence_recorder protocol** without external system dependencies
+- **Simulating external fence coordination** in development
+- **CI/CD testing** of fence request/response workflows
+- **Validating external fence responders** before production
+
+### Configuration
+
+```bash
+# Create directories
+sudo mkdir -p /var/run/fence_dummy/{requests,responses}
+sudo mkdir -p /var/log/cluster
+
+# Create STONITH resource
+pcs stonith create test-fence fence_dummy \
+    type=recorder \
+    plug=compute-node-1 \
+    request_path=/var/run/fence_dummy/requests \
+    response_path=/var/run/fence_dummy/responses \
+    log_path=/var/log/cluster \
+    recorder_timeout=30
+```
+
+### Options (Recorder Mode)
+
+| Option | Default | Description |
+| ------ | ------- | ----------- |
+| `--type` | `file` | Set to `recorder` for request/response mode |
+| `--plug` | (required) | Target node to fence |
+| `--request-path` | `/var/run/fence_dummy/requests` | Directory for fence 
requests |
+| `--response-path` | `/var/run/fence_dummy/responses` | Directory for fence 
responses |
+| `--recorder-timeout` | `60` | Seconds to wait for response |
+| `--recorder-poll-interval` | `0.5` | Seconds between response checks |
+| `--log-path` | `/var/log/cluster` | Directory for fence event logs |
+
+### Logging (Recorder Mode)
+
+Recorder mode enables structured logging to track fence operations:
+
+- **Log file**: `<log-path>/fence-events.log` (also to stderr)
+- **Format**: `[YYYY-MM-DD HH:MM:SS] [LEVEL] message`
+- **Events logged**:
+  - Fence action requested
+  - Fence action completed/failed
+  - Request/response file operations
+  - Errors and timeouts
+
+Example log entries:
+
+```text
+[2026-01-14 13:45:10] [INFO] Fence event: action=off, target=compute-node-1, 
status=requested, details=Fence action off requested
+[2026-01-14 13:45:15] [INFO] Fence response received: success=True, 
message=Fence operation completed successfully, 
timestamp=2026-01-14T13:45:15-06:00
+[2026-01-14 13:45:15] [INFO] Fence event: action=off, target=compute-node-1, 
status=completed, details=Fence action off completed successfully: Fence 
operation completed successfully
+```
+
+> **Note**: In recorder mode, the agent uses a synchronous pattern to wait for 
the external response.
+>
+> - `off`: Writes a request and waits for a success response.
+> - `reboot`: Executed as `off` then `on`. This generates an `off` request 
(wait for success) followed by an `on` action (no-op).
+> - `on`, `status`, `monitor`: These are no-ops that always return success/on 
to satisfy Pacemaker requirements, but do not generate request files.
+
+### Request File Format
+
+**File**: `<request-path>/<node-name>-<uuid>.json`
+
+```json
+{
+  "request_id": "550e8400-e29b-41d4-a716-446655440000",
+  "timestamp": "2026-01-06T14:30:00-06:00",
+  "action": "off",
+  "target_node": "compute-node-1",
+  "recorder_node": "control-node"
+}
+```
+
+### Response File Format
+
+**File**: `<response-path>/<node-name>-<uuid>.json`
+
+```json
+{
+  "request_id": "550e8400-e29b-41d4-a716-446655440000",
+  "timestamp": "2026-01-06T14:30:05-06:00",
+  "success": true,
+  "message": "Fence operation completed successfully",
+  "action_performed": "off",
+  "target_node": "compute-node-1",
+  "recorder_node": "responder-system"
+}
+```
+
+### Example: Simulating an External Responder
+
+```bash
+#!/bin/bash
+# Simple fence responder for testing
+
+REQUEST_DIR="/var/run/fence_dummy/requests"
+RESPONSE_DIR="/var/run/fence_dummy/responses"
+
+while true; do
+    for request in "$REQUEST_DIR"/*.json; do
+        [ -e "$request" ] || continue
+
+        # Extract request_id and node name from request file
+        request_id=$(jq -r '.request_id' "$request")
+        target_node=$(jq -r '.target_node' "$request")
+
+        # Write response
+        response_file="$RESPONSE_DIR/$(basename "$request")"
+        timestamp=$(date +"%Y-%m-%dT%H:%M:%S%z" | sed 's/\([0-9][0-9]\)$/:\1/')
+        cat > "$response_file" <<EOF
+{
+  "request_id": "$request_id",
+  "timestamp": "$timestamp",
+  "success": true,
+  "message": "Simulated fence of $target_node",
+  "action_performed": "off",
+  "target_node": "$target_node",
+  "recorder_node": "$(hostname)"
+}
+EOF
+
+        echo "Responded to fence request for $target_node"
+        rm "$request"
+    done
+    sleep 1
+done
+```
+
+---
+
+## Common Options (All Modes)
+
+### Random Sleep
+
+Simulate slow fence devices by adding random delays:
+
+| Option | Default | Description |
+| ------ | ------- | ----------- |
+| `--random_sleep_range` | (disabled) | Maximum sleep time in seconds (random 
1-N) |
+
+```bash
+# Sleep 1-30 seconds before taking action (any mode)
+fence_dummy --plug node1 --action off --random_sleep_range=30
+
+# Combine with recorder mode
+fence_dummy --type=recorder --plug node1 --action off \
+    --random_sleep_range=10 \
+    --request-path=/var/run/fence_dummy/requests \
+    --response-path=/var/run/fence_dummy/responses
+```
+
+### Standard Fence Actions
+
+All modes support standard fence agent actions:
+
+- **`on`**: Turn on the node/outlet
+- **`off`**: Turn off the node/outlet (primary fence action)
+- **`reboot`**: Reboot the node (implemented as off + on)
+- **`status`**: Query current power state
+- **`monitor`**: Check if fence agent is functioning (always succeeds)
+- **`list`**: List available outlets (fail mode only)
+- **`metadata`**: Output XML metadata for Pacemaker
+
+---
+
+## Comparison of Modes
+
+| Feature | File Mode | Fail Mode | Recorder Mode |
+| ------- | --------- | --------- | ------------- |
+| **Default** | ✓ | | |
+| **State Persistence** | File-based | None | External system |
+| **External Dependencies** | None | None | Response writer |
+| **Reliable Results** | ✓ | ✗ (intentionally) | ✓ (if responder works) |
+| **Async Operation** | No | No | Yes (waits for response) |
+| **Logging** | Minimal | Minimal | Structured logs |
+| **Use Case** | Basic testing | Error simulation | External coordination |
+| **Production Use** | Testing only | Never | Testing only |
+
+---
+
+## Installation
+
+```bash
+# Build from source
+./autogen.sh
+./configure
+make
+sudo make install
+
+# Verify installation
+fence_dummy -o metadata
+```
+
+## See Also
+
+- `fence_recorder` - Production fence agent for NNF storage coordination
+- [Pacemaker documentation](https://clusterlabs.org/pacemaker/)
+- Fence agent development: `/usr/share/doc/fence-agents/`
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/dummy/fence_dummy.py 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/dummy/fence_dummy.py
--- old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/dummy/fence_dummy.py 
2025-12-09 16:15:31.000000000 +0100
+++ new/fence-agents-4.17.0+git.1769693386.608dd62/agents/dummy/fence_dummy.py  
2026-01-29 14:29:46.000000000 +0100
@@ -4,12 +4,25 @@
 import logging
 import time
 import atexit
+import os
+import json
+import socket
+import uuid
+from datetime import datetime
+
 sys.path.append("@FENCEAGENTSLIBDIR@")
 from fencing import *
-from fencing import fail_usage, run_delay
+from fencing import fail, fail_usage, run_delay
 
 plug_status = "on"
 
+# Defaults for recorder mode
+DEFAULT_REQUEST_PATH = "@FENCETMPDIR@/fence_dummy/requests"
+DEFAULT_RESPONSE_PATH = "@FENCETMPDIR@/fence_dummy/responses"
+DEFAULT_RECORDER_TIMEOUT = 60
+DEFAULT_RECORDER_POLL_INTERVAL = 0.5
+DEFAULT_LOG_PATH = "@LOGDIR@"
+
 def get_power_status_file(conn, options):
        del conn
 
@@ -71,11 +84,188 @@
 
        return result
 
+# Recorder mode logging functions
+def setup_recorder_logging(log_path):
+       """Initialize logging with the specified log directory (recorder mode 
only)
+       
+       Adds an additional file handler to log fence events to a separate file.
+       Keeps the default root logger format for pacemaker.log compatibility.
+       
+       Note: The root logger level must be set to INFO to allow INFO messages
+       through to handlers. fencing.py sets it to WARNING by default unless
+       --verbose is specified.
+       """
+       os.makedirs(log_path, exist_ok=True)
+       fence_log = os.path.join(log_path, "fence-events.log")
+       
+       # Add file handler for fence events (keeps existing root logger 
handlers)
+       file_handler = logging.FileHandler(fence_log)
+       file_handler.setLevel(logging.INFO)
+       file_handler.setFormatter(logging.Formatter('[%(asctime)s] 
[%(levelname)s] %(message)s', '%Y-%m-%d %H:%M:%S'))
+       
+       # Set root logger level to INFO to allow our INFO messages through
+       # (fencing.py defaults to WARNING unless --verbose is set)
+       root_logger = logging.getLogger()
+       if root_logger.level > logging.INFO:
+               root_logger.setLevel(logging.INFO)
+       root_logger.addHandler(file_handler)
+       
+       return log_path, fence_log
+
+def record_fence_event(action, target_node, status, details=""):
+       """Record fencing event to log"""
+       logging.info(f"Fence event: action={action}, target={target_node}, 
status={status}, details={details}")
+
+# Recorder mode functions
+def write_fence_request_recorder(action, target_node, request_dir):
+       """Write fence request file (atomic rename pattern)"""
+       os.makedirs(request_dir, exist_ok=True)
+       
+       request_id = str(uuid.uuid4())
+       filename = f"{target_node}-{request_id}.json"
+       temp_file = os.path.join(request_dir, f".{filename}.tmp")
+       final_file = os.path.join(request_dir, filename)
+       
+       request_data = {
+               "request_id": request_id,
+               "timestamp": datetime.now().astimezone().isoformat(),
+               "action": action,
+               "target_node": target_node,
+               "recorder_node": socket.gethostname()
+       }
+       
+       try:
+               with open(temp_file, 'w') as f:
+                       json.dump(request_data, f, indent=2)
+               os.rename(temp_file, final_file)
+               logging.info(f"Wrote fence request: {final_file}")
+               return request_id
+       except Exception as e:
+               logging.error(f"Failed to write fence request: {e}")
+               try:
+                       os.remove(temp_file)
+               except OSError:
+                       pass
+               return None
+
+def wait_for_fence_response_recorder(request_id, target_node, response_dir, 
timeout, poll_interval):
+       """Wait for external component to write response file"""
+       os.makedirs(response_dir, exist_ok=True)
+       
+       response_file = os.path.join(response_dir, 
f"{target_node}-{request_id}.json")
+       start_time = time.time()
+       
+       logging.info(f"Waiting for fence response: {response_file} 
(timeout={timeout}s)")
+       
+       while time.time() - start_time < timeout:
+               try:
+                       if os.path.exists(response_file):
+                               file_size = os.path.getsize(response_file)
+                               if file_size > 1024 * 1024:  # 1MB limit
+                                       logging.error(f"Response file too 
large: {file_size} bytes")
+                                       return False, "Response file exceeds 
size limit"
+                               
+                               with open(response_file, 'r') as f:
+                                       response_data = json.load(f)
+                               
+                               success = response_data.get("success", False)
+                               message = response_data.get("message", "Fence 
operation completed")
+                               timestamp = response_data.get("timestamp", 
"unknown")
+                               response_target = 
response_data.get("target_node", "unknown")
+                               response_recorder = 
response_data.get("recorder_node", "unknown")
+                               
+                               logging.info(f"Fence response received: 
success={success}, message={message}, timestamp={timestamp}")
+                               logging.info(f"Response metadata: 
target={response_target}, recorder={response_recorder}")
+                               return success, message
+               except (FileNotFoundError, json.JSONDecodeError, Exception) as 
e:
+                       logging.debug(f"Waiting for response: {e}")
+               
+               time.sleep(poll_interval)
+       
+       logging.error(f"Fence response timeout after {timeout}s")
+       return False, f"Fence operation timed out after {timeout}s"
+
+def get_power_status_recorder(conn, options):
+       """Recorder mode get_power_status - not used with sync pattern"""
+       del conn
+       # This shouldn't be called when using sync_set_power_fn pattern
+       # Return 'on' as fallback
+       return "on"
+
+def sync_set_power_status_recorder(conn, options):
+       """Recorder mode sync_set_power_status - write request and wait for 
response.
+       
+       Returns True on success, False on failure. Using sync pattern avoids
+       the post-action power state verification that would fail since we can't
+       query the actual power state of fenced nodes.
+       """
+       del conn
+       
+       action = options["--action"]
+       target_node = options["--plug"]
+       request_path = options["--request-path"]
+       response_path = options["--response-path"]
+       timeout = int(options["--recorder-timeout"])
+       poll_interval = float(options["--recorder-poll-interval"])
+       
+       # Only handle off/reboot actions (not on/status/monitor)
+       if action not in ["off", "reboot"]:
+               return True
+       
+       # Record fence event initiation
+       record_fence_event(
+               action,
+               target_node,
+               "requested",
+               f"Fence action {action} requested"
+       )
+       
+       # Write request
+       request_id = write_fence_request_recorder(action, target_node, 
request_path)
+       if not request_id:
+               record_fence_event(
+                       action,
+                       target_node,
+                       "failed",
+                       "Failed to create fence request file"
+               )
+               return False
+       
+       # Wait for response
+       success, message = wait_for_fence_response_recorder(
+               request_id, target_node, response_path, timeout, poll_interval
+       )
+       
+       if not success:
+               logging.error(f"Fence operation failed: {message}")
+               record_fence_event(
+                       action,
+                       target_node,
+                       "failed",
+                       f"Fence action {action} failed: {message}"
+               )
+               return False
+       
+       # Record successful completion
+       record_fence_event(
+               action,
+               target_node,
+               "completed",
+               f"Fence action {action} completed successfully: {message}"
+       )
+       
+       return True
+
 def main():
-       device_opt = ["no_password", "status_file", "random_sleep_range", 
"type", "no_port"]
+       device_opt = ["no_password", "status_file", "random_sleep_range", 
"type", "port", "no_port",
+                     "request_path", "response_path", "recorder_timeout", 
"recorder_poll_interval", "log_path"]
 
        atexit.register(atexit_handler)
 
+       # Port is optional - no_port in device_opt handles runtime validation,
+       # but we also need to set required=0 for correct metadata generation
+       all_opt["port"]["required"] = "0"
+
        all_opt["status_file"] = {
                "getopt" : ":",
                "longopt" : "status-file",
@@ -98,21 +288,77 @@
        all_opt["type"] = {
                "getopt" : ":",
                "longopt" : "type",
-               "help":"--type=[type]                  Possible types are: file 
and fail",
+               "help":"--type=[type]                  Possible types are: 
file, fail, and recorder",
                "required" : "0",
                "shortdesc" : "Type of the dummy fence agent",
                "default" : "file",
                "order": 1
                }
 
+       all_opt["request_path"] = {
+               "getopt" : ":",
+               "longopt" : "request-path",
+               "help":"--request-path=[path]          Directory for fence 
request files (recorder mode)",
+               "required" : "0",
+               "shortdesc" : "Request directory path for recorder mode",
+               "default" : DEFAULT_REQUEST_PATH,
+               "order": 1
+               }
+
+       all_opt["response_path"] = {
+               "getopt" : ":",
+               "longopt" : "response-path",
+               "help":"--response-path=[path]         Directory for fence 
response files (recorder mode)",
+               "required" : "0",
+               "shortdesc" : "Response directory path for recorder mode",
+               "default" : DEFAULT_RESPONSE_PATH,
+               "order": 1
+               }
+
+       all_opt["recorder_timeout"] = {
+               "getopt" : ":",
+               "longopt" : "recorder-timeout",
+               "help":"--recorder-timeout=[seconds]   Timeout for external 
response (recorder mode)",
+               "required" : "0",
+               "shortdesc" : "Response timeout for recorder mode",
+               "default" : str(DEFAULT_RECORDER_TIMEOUT),
+               "order": 1
+               }
+
+       all_opt["recorder_poll_interval"] = {
+               "getopt" : ":",
+               "longopt" : "recorder-poll-interval",
+               "help":"--recorder-poll-interval=[sec] Poll interval for 
response check (recorder mode)",
+               "required" : "0",
+               "shortdesc" : "Poll interval for recorder mode",
+               "default" : str(DEFAULT_RECORDER_POLL_INTERVAL),
+               "order": 1
+               }
+
+       all_opt["log_path"] = {
+               "getopt" : ":",
+               "longopt" : "log-path",
+               "help":"--log-path=[path]              Directory for fence 
event logs (recorder mode)",
+               "required" : "0",
+               "shortdesc" : "Log directory path for fence events",
+               "default" : DEFAULT_LOG_PATH,
+               "order": 1
+               }
+
        options = check_input(device_opt, process_input(device_opt))
 
        docs = {}
        docs["shortdesc"] = "Dummy fence agent"
-       docs["longdesc"] = "fence_dummy"
+       docs["longdesc"] = "fence_dummy is a fake fence agent for testing. " \
+               "It supports three modes: 'file' (status in file), 'fail' 
(simulated failures), " \
+               "and 'recorder' (request/response coordination with external 
systems)."
        docs["vendorurl"] = "http://www.example.com";
        show_docs(options, docs)
 
+       # Setup persistent logging for recorder mode only
+       if options.get("--type") == "recorder":
+               setup_recorder_logging(options["--log-path"])
+
        run_delay(options)
 
        # random sleep for testing
@@ -124,6 +370,12 @@
 
        if options["--type"] == "fail":
                result = fence_action(None, options, set_power_status_fail, 
get_power_status_fail, get_outlets_fail)
+       elif options["--type"] == "recorder":
+               # Use sync_set_power_fn pattern to avoid post-action power 
state verification
+               # (we can't query actual power state - the response file 
confirms the action)
+               # Note: fence_action signature is (conn, options, set_power_fn, 
get_power_fn, get_outlet_list, reboot_cycle_fn, sync_set_power_fn)
+               # The 7th parameter is defined in lib/fencing.py.py but not in 
agents/autodetect/fencing.py
+               result = fence_action(None, options, None, 
get_power_status_recorder, None, None, sync_set_power_status_recorder)  # type: 
ignore[call-arg]
        else:
                result = fence_action(None, options, set_power_status_file, 
get_power_status_file, None)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/ibm_vpc/fence_ibm_vpc.py 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/ibm_vpc/fence_ibm_vpc.py
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/ibm_vpc/fence_ibm_vpc.py 
    2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/ibm_vpc/fence_ibm_vpc.py  
    2026-01-29 14:29:46.000000000 +0100
@@ -16,8 +16,8 @@
         "stopping": "unknown",
         "restarting": "unknown",
         "pending": "unknown",
-     "deleting": "unknown",
-     "failed": "unknown",
+        "deleting": "unknown",
+        "failed": "unknown",
 }
 
 def get_list(conn, options):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/kdump/fence_kdump.c 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/kdump/fence_kdump.c
--- old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/kdump/fence_kdump.c  
2025-12-09 16:15:31.000000000 +0100
+++ new/fence-agents-4.17.0+git.1769693386.608dd62/agents/kdump/fence_kdump.c   
2026-01-29 14:29:46.000000000 +0100
@@ -229,7 +229,7 @@
 do_action_metadata (const char *self)
 {
     fprintf (stdout, "<?xml version=\"1.0\" ?>\n");
-    fprintf (stdout, "<resource-agent name=\"%s\"", basename (self));
+    fprintf (stdout, "<resource-agent name=\"%s\"", basename ((char *)self));
     fprintf (stdout, " shortdesc=\"fencing agent for use with kdump crash 
recovery service\">\n");
     fprintf (stdout, "<longdesc>");
     fprintf (stdout, "fence_kdump is an I/O fencing agent to be used with the 
kdump\n"
@@ -335,7 +335,7 @@
 static void
 print_usage (const char *self)
 {
-    fprintf (stdout, "Usage: %s [options]\n", basename (self));
+    fprintf (stdout, "Usage: %s [options]\n", basename ((char *)self));
     fprintf (stdout, "\n");
     fprintf (stdout, "Options:\n");
     fprintf (stdout, "\n");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/kdump/fence_kdump_send.c 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/kdump/fence_kdump_send.c
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/kdump/fence_kdump_send.c 
    2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/kdump/fence_kdump_send.c  
    2026-01-29 14:29:46.000000000 +0100
@@ -72,7 +72,7 @@
 static void
 print_usage (const char *self)
 {
-    fprintf (stdout, "Usage: %s [options] [nodes]\n", basename (self));
+    fprintf (stdout, "Usage: %s [options] [nodes]\n", basename ((char *)self));
     fprintf (stdout, "\n");
     fprintf (stdout, "Options:\n");
     fprintf (stdout, "\n");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/kdump/version.h 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/kdump/version.h
--- old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/kdump/version.h      
2025-12-09 16:15:31.000000000 +0100
+++ new/fence-agents-4.17.0+git.1769693386.608dd62/agents/kdump/version.h       
2026-01-29 14:29:46.000000000 +0100
@@ -24,10 +24,12 @@
 
 #define FENCE_KDUMP_VERSION "0.1"
 
+#include <libgen.h>
+
 static inline void
 print_version (const char *self)
 {
-    fprintf (stdout, "%s %s\n", basename (self), FENCE_KDUMP_VERSION);
+    fprintf (stdout, "%s %s\n", basename ((char *)self), FENCE_KDUMP_VERSION);
 }
 
 #endif /* _FENCE_KDUMP_VERSION_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/scsi/fence_scsi.py 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/scsi/fence_scsi.py
--- old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/scsi/fence_scsi.py   
2025-12-09 16:15:31.000000000 +0100
+++ new/fence-agents-4.17.0+git.1769693386.608dd62/agents/scsi/fence_scsi.py    
2026-01-29 14:29:46.000000000 +0100
@@ -133,7 +133,7 @@
 
 def register_dev(options, dev, key, do_preempt=True):
        dev = os.path.realpath(dev)
-       if re.search(r"^dm", dev[5:]):
+       if options.get("--mpath-register-method") == "multi" and 
re.search(r"^dm", dev[5:]):
                devices = get_mpath_slaves(dev)
                register_dev(options, devices[0], key)
                for device in devices[1:]:
@@ -384,6 +384,15 @@
                "shortdesc" : "Use the APTPL flag for registrations. This 
option is only used for the 'on' action.",
                "order": 1
        }
+       all_opt["mpath_register_method"] = {
+               "getopt" : ":",
+               "longopt" : "mpath-register-method",
+               "help" : "--mpath-register-method=[multi|single]  Register key 
to all multipath sub devices (multi), or directly to the main multipath device 
(single).",
+               "required" : "0",
+               "shortdesc" : "Multipath register method (multi/single).",
+               "default": "multi",
+               "order": 3
+       }
        all_opt["readonly"] = {
                "getopt" : "",
                "longopt" : "readonly",
@@ -523,8 +532,8 @@
 
        device_opt = ["no_login", "no_password", "devices", "nodename", "port",\
        "no_port", "key", "aptpl", "fabric_fencing", "on_target", 
"corosync_cmap_path",\
-       "sg_persist_path", "sg_turs_path", "readonly", "suppress-errors", 
"logfile", "vgs_path",\
-       "force_on", "key_value"]
+       "sg_persist_path", "sg_turs_path", "mpath_register_method", "readonly", 
\
+       "suppress-errors", "logfile", "vgs_path","force_on", "key_value"]
 
        define_new_opts()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/virt/server/daemon_init.c
 new/fence-agents-4.17.0+git.1769693386.608dd62/agents/virt/server/daemon_init.c
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/virt/server/daemon_init.c
    2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/virt/server/daemon_init.c 
    2026-01-29 14:29:46.000000000 +0100
@@ -23,7 +23,7 @@
 #include <fcntl.h>
 #include <dirent.h>
 #include <sys/mman.h>
-#include <sys/errno.h>
+#include <errno.h>
 #include <libgen.h>
 #include <signal.h>
 #include <syslog.h>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/virt/server/virt-serial.c
 new/fence-agents-4.17.0+git.1769693386.608dd62/agents/virt/server/virt-serial.c
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/virt/server/virt-serial.c
    2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/virt/server/virt-serial.c 
    2026-01-29 14:29:46.000000000 +0100
@@ -12,7 +12,7 @@
 #include <fcntl.h>
 
 #include <sys/types.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <libvirt/libvirt.h>
 
 #include <libxml/xmlreader.h>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/virt/server/virt-sockets.c
 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/virt/server/virt-sockets.c
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/agents/virt/server/virt-sockets.c
   2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/agents/virt/server/virt-sockets.c
    2026-01-29 14:29:46.000000000 +0100
@@ -8,6 +8,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <stdlib.h>
+#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/tests/data/metadata/fence_dummy.xml
 
new/fence-agents-4.17.0+git.1769693386.608dd62/tests/data/metadata/fence_dummy.xml
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/tests/data/metadata/fence_dummy.xml
 2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/tests/data/metadata/fence_dummy.xml
  2026-01-29 14:29:46.000000000 +0100
@@ -1,6 +1,6 @@
 <?xml version="1.0" ?>
 <resource-agent name="fence_dummy" shortdesc="Dummy fence agent" >
-<longdesc>fence_dummy</longdesc>
+<longdesc>fence_dummy is a fake fence agent for testing. It supports three 
modes: 'file' (status in file), 'fail' (simulated failures), and 'recorder' 
(request/response coordination with external systems).</longdesc>
 <vendor-url>http://www.example.com</vendor-url>
 <parameters>
        <parameter name="action" unique="0" required="1">
@@ -8,11 +8,43 @@
                <content type="string" default="reboot"  />
                <shortdesc lang="en">Fencing action</shortdesc>
        </parameter>
+       <parameter name="log_path" unique="0" required="0">
+               <getopt mixed="--log-path=[path]" />
+               <shortdesc lang="en">Log directory path for fence 
events</shortdesc>
+       </parameter>
+       <parameter name="plug" unique="0" required="0" 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="0" 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="random_sleep_range" unique="0" required="0">
                <getopt mixed="--random_sleep_range=[seconds]" />
                <content type="string"  />
                <shortdesc lang="en">Issue a sleep between 1 and X seconds. 
Used for testing.</shortdesc>
        </parameter>
+       <parameter name="recorder_poll_interval" unique="0" required="0">
+               <getopt mixed="--recorder-poll-interval=[sec]" />
+               <content type="string" default="0.5"  />
+               <shortdesc lang="en">Poll interval for recorder mode</shortdesc>
+       </parameter>
+       <parameter name="recorder_timeout" unique="0" required="0">
+               <getopt mixed="--recorder-timeout=[seconds]" />
+               <content type="string" default="60"  />
+               <shortdesc lang="en">Response timeout for recorder 
mode</shortdesc>
+       </parameter>
+       <parameter name="request_path" unique="0" required="0">
+               <getopt mixed="--request-path=[path]" />
+               <shortdesc lang="en">Request directory path for recorder 
mode</shortdesc>
+       </parameter>
+       <parameter name="response_path" unique="0" required="0">
+               <getopt mixed="--response-path=[path]" />
+               <shortdesc lang="en">Response directory path for recorder 
mode</shortdesc>
+       </parameter>
        <parameter name="status_file" unique="0" required="0">
                <getopt mixed="--status-file=[file]" />
                <shortdesc lang="en">File with status</shortdesc>
@@ -61,6 +93,11 @@
                <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"  />
@@ -107,6 +144,8 @@
        <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" />
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/tests/data/metadata/fence_scsi.xml
 
new/fence-agents-4.17.0+git.1769693386.608dd62/tests/data/metadata/fence_scsi.xml
--- 
old/fence-agents-4.16.0+git.1765293331.d30fb54b/tests/data/metadata/fence_scsi.xml
  2025-12-09 16:15:31.000000000 +0100
+++ 
new/fence-agents-4.17.0+git.1769693386.608dd62/tests/data/metadata/fence_scsi.xml
   2026-01-29 14:29:46.000000000 +0100
@@ -36,6 +36,11 @@
                <content type="string"  />
                <shortdesc lang="en">Name of the node to be fenced. The node 
name is used to generate the key value used for the current operation. This 
option will be ignored when used with the -k option.</shortdesc>
        </parameter>
+       <parameter name="mpath_register_method" unique="0" required="0">
+               <getopt mixed="--mpath-register-method=[multi|single]" />
+               <content type="string" default="multi"  />
+               <shortdesc lang="en">Multipath register method 
(multi/single).</shortdesc>
+       </parameter>
        <parameter name="readonly" unique="0" required="0">
                <getopt mixed="--readonly" />
                <content type="boolean"  />

Reply via email to