Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/user/debugging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,32 @@ You can inspect the version of openwisp-config currently installed with:
.. code-block:: shell

openwisp-config --version

Forcing Configuration Update
----------------------------

You can force openwisp-config to immediately download and apply the latest
configuration from the controller using the ``--force-update`` option:

.. code-block:: shell

openwisp-config --force-update

This command checks if the openwisp-config agent is running and sends a
SIGUSR2 signal to trigger an immediate configuration update. If the agent
is not running, the command will exit with an error.

Alternatively, you can manually send the SIGUSR2 signal to the agent
process:

.. code-block:: shell

kill -USR2 "$(pgrep -P 1 -f openwisp-config)"

This is useful when you need to:

- Force the device to fetch the latest configuration without waiting for
the next polling interval
- Apply configuration changes immediately after making updates in OpenWISP
Controller
- Troubleshoot configuration synchronization issues
25 changes: 23 additions & 2 deletions openwisp-config/files/openwisp.agent
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ while [ -n "$1" ]; do
export VERSION=1
break
;;
--force-update)
# Check if agent is running and send SIGUSR2 to force configuration reload
AGENT_PID=$(pgrep -P 1 -f openwisp-config)
if [ -z "$AGENT_PID" ]; then
echo "Error: openwisp-config agent is not running" >&2
exit 1
fi
kill -USR2 "$AGENT_PID"
echo "Sent SIGUSR2 to openwisp-config agent (PID: $AGENT_PID) to force configuration update"
exit 0
;;
Comment on lines +12 to +22
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's read the actual file to confirm the code snippet
cat -n openwisp-config/files/openwisp.agent | sed -n '10,25p'

Repository: openwisp/openwisp-config

Length of output: 624


🏁 Script executed:

# Test pgrep behavior - can it return multiple PIDs?
echo "=== Testing pgrep with multiple potential matches ==="
# Create a test to see pgrep output format
pgrep -f "bash" 2>/dev/null | head -3 | while IFS= read -r line; do echo "Line: [$line]"; done
echo ""

# Count how many PIDs pgrep returns
PIDS=$(pgrep -f "bash" 2>/dev/null)
PID_COUNT=$(echo "$PIDS" | wc -w)
echo "Number of PIDs returned: $PID_COUNT"
echo "PIDS content: [$PIDS]"

Repository: openwisp/openwisp-config

Length of output: 166


🏁 Script executed:

# Test kill behavior with quoted multi-PID string
echo "=== Testing kill with quoted multi-PID string ==="
PIDS="1 2 3"
echo "Variable PIDS contains: $PIDS"
echo "Running: kill -0 \"\$PIDS\""
kill -0 "$PIDS" 2>&1 || echo "Command failed (as expected if multiple PIDs)"

Repository: openwisp/openwisp-config

Length of output: 287


🏁 Script executed:

# Check if there's any documentation about single vs. multiple agent instances
rg -i "agent" openwisp-config/files/openwisp.agent | head -10

Repository: openwisp/openwisp-config

Length of output: 659


🏁 Script executed:

# Look for comments about process management and PID handling
rg -B2 -A2 "pgrep|pidof" openwisp-config/files/openwisp.agent

Repository: openwisp/openwisp-config

Length of output: 300


Fix pgrep output handling: iterate over PIDs instead of passing quoted string to kill.

When pgrep -P 1 -f openwisp-config returns multiple PIDs (space-separated), passing the quoted variable to kill fails because kill interprets the entire string as a single invalid PID argument. The correct approach is to iterate over the individual PIDs.

Suggested fix
 		--force-update)
 			# Check if agent is running and send SIGUSR2 to force configuration reload
-			AGENT_PID=$(pgrep -P 1 -f openwisp-config)
-			if [ -z "$AGENT_PID" ]; then
+			AGENT_PIDS=$(pgrep -P 1 -f openwisp-config)
+			if [ -z "$AGENT_PIDS" ]; then
 				echo "Error: openwisp-config agent is not running" >&2
 				exit 1
 			fi
-			kill -USR2 "$AGENT_PID"
-			echo "Sent SIGUSR2 to openwisp-config agent (PID: $AGENT_PID) to force configuration update"
+			for pid in $AGENT_PIDS; do
+				kill -USR2 "$pid" 2>/dev/null
+			done
+			echo "Sent SIGUSR2 to openwisp-config agent (PID(s): $AGENT_PIDS) to force configuration update"
 			exit 0
 			;;
🤖 Prompt for AI Agents
In `@openwisp-config/files/openwisp.agent` around lines 12 - 22, The current
AGENT_PID variable from pgrep may contain multiple space-separated PIDs; instead
of passing the quoted string to kill, split and iterate over each PID and call
kill -USR2 on each one. Modify the block that sets AGENT_PID=$(pgrep -P 1 -f
openwisp-config) to check for empty result, then loop over the tokens in
AGENT_PID (for pid in $AGENT_PID; do ... done), verify each pid is non-empty and
numeric before running kill -USR2 "$pid", and update the echo to report which
PIDs were signalled (or a summary) from the existing --force-update case.

--url)
export URL="${2%/}"
shift
Expand Down Expand Up @@ -914,7 +925,14 @@ handle_sigusr1() {
-t openwisp \
-p daemon.info
}

handle_sigusr2() {
logger -s "Received SIGUSR2: forcing configuration update..." \
-t openwisp \
-p daemon.info
# Remove checksum files to ensure configuration_changed returns 1
# which will trigger update_configuration on the next loop iteration
rm -f "$CONFIGURATION_CHECKSUM" "$PERSISTENT_CHECKSUM"
}
# ensure both UUID and KEY are defined
# otherwise perform registration
if [ -z "$UUID" ] || [ -z "$KEY" ]; then
Expand Down Expand Up @@ -972,8 +990,11 @@ while true; do

# handle SIGUSR1 to interrupt sleep
trap handle_sigusr1 USR1
# handle SIGUSR2 to force downloading and applying config again
trap handle_sigusr2 USR2
sleep "$INTERVAL" &
wait $!
# ignore SIGUSR1 signals again
# ignore SIGUSR1 and SIGUSR2 signals again
trap "" USR1
trap "" USR2
done