Skip to content

Instantly share code, notes, and snippets.

@oskapt
Last active July 31, 2024 03:51
Show Gist options
  • Save oskapt/055d474d7bfef32c49469c1b53e8225f to your computer and use it in GitHub Desktop.
Save oskapt/055d474d7bfef32c49469c1b53e8225f to your computer and use it in GitHub Desktop.
Netdata init script for Synology DSM
#!/bin/bash
# 1. Install this as `/usr/local/etc/rc.d/rc.netdata`
# 2. Create the directory `/volume1/netdata`
# 3. Symlink `/opt/netdata` to `/volume1/netdata`
# 4. Create a triggered task with Task Scheduler to call `/usr/local/etc/rc.d/rc.netdata start` at boot.
# - (You may have to turn on Advanced Mode in the Control Panel to see Task Scheduler)
# 5. Either reboot or run `sudo /usr/local/etc/rc.d/rc.netdata start`
# If you get an error about "Connection Failed," then you've already run Netdata and filled `/`.
# Stop netdata and move `/opt/netdata` to `/volume1/netdata` before continuing with step 3 above.
NETDATA_DIR=/opt/netdata
DAEMON=$NETDATA_DIR/bin/srv/netdata
TIMEOUT=30 # seconds to wait for netdata to exit
[ -x $DAEMON ] || exit 0
function get_pid() {
pid=$( ps ax | grep -v grep | grep -m 1 $DAEMON | awk '{ print $1 }' )
}
function check_netdata() {
count=1
while [ $count -lt $TIMEOUT ]; do
get_pid
if [ -z $pid ]; then
break
else
sleep 1
count=$(( $count + 1))
fi
done
if [ $count -eq $TIMEOUT ]; then
echo "Timeout exceeded waiting for netdata to exit."
echo "Use '$0 kill' to force netdata to exit."
exit 1
fi
}
function stop_netdata() {
get_pid
if [ "x$pid" != "x" ]; then
if [ "x$1" = "xforce" ]; then
kill -9 $pid
else
kill $pid
fi
else
echo "No running netdata found."
fi
}
function start_netdata() {
get_pid
if [ "x$pid" = "x" ]; then
echo "Starting Netdata."
$DAEMON
else
echo "Netdata already running with pid $pid"
fi
}
case "$1" in
start)
start_netdata
;;
stop)
echo "Shutting down Netdata."
stop_netdata
;;
restart)
echo "Shutting down Netdata."
stop_netdata
if [ "x$pid" != "x" ]; then
echo "Waiting maximum of $TIMEOUT seconds for netdata to exit."
fi
check_netdata
start_netdata
;;
kill)
echo "Killing netdata."
stop_netdata force
;;
status)
get_pid
if [ "x$pid" != "x" ]; then
echo "Netdata running with PID $pid"
else
echo "No running netdata found."
fi
;;
*)
echo "Usage: $0 {start|stop|kill|restart|status}"
exit 1
esac
exit 0
@ilyam8
Copy link

ilyam8 commented Feb 3, 2022

Hi, @oskapt. We have a link to this file in our documentation. And there is a bug report:

/etc/rc.netdata: line 20: [: 17389: binary operator expected

The problem is get_pid() func returns 2 PIDs:

# ps ax | grep /opt/netdata/bin/srv/netdata | grep -v grep
18652 ?        SNsl 109:21 /opt/netdata/bin/srv/netdata -P /opt/netdata/var/run/netdata/netdata.pid -D
18677 ?        SNl    0:00 /opt/netdata/bin/srv/netdata --special-spawn-server
# ps ax | grep /opt/netdata/bin/srv/netdata | grep -v grep | awk '{ print $1 }'
18652
18677

I think adding -m 1 option to the first grep will fix the issue.

# ps ax | grep -m 1 /opt/netdata/bin/srv/netdata | grep -v grep
18652 ?        SNsl 109:23 /opt/netdata/bin/srv/netdata -P /opt/netdata/var/run/netdata/netdata.pid -D
# ps ax | grep -m 1 /opt/netdata/bin/srv/netdata | grep -v grep | awk '{ print $1 }'
18652

Thanks!

@oskapt
Copy link
Author

oskapt commented Feb 3, 2022

Updated. Thanks for reaching out!

@timrettop
Copy link

I believe that the modification suggested above can result in the issued command ps ax... being the only result passed to grep -v grep. I've swapped this:
ps ax | grep -m 1 $DAEMON | grep -v grep | awk '{ print $1 }'
with
ps ax | grep -v grep | grep -m 1 $DAEMON | awk '{ print $1 }'

Thoughts?

@oskapt
Copy link
Author

oskapt commented Dec 8, 2023

It's possible, but only if grep -v $DAEMON is earlier in the process list than "$DAEMON" itself. The only way that can happen is if this script is run before netdata is started, in which case netdata isn't running and will be started by the script. Your change doesn't hurt anything, and is probably cleaner from a logical flow. I'll make the adjustment. Thanks for posting it.

@ilyam8
Copy link

ilyam8 commented Dec 8, 2023

I am not sure I follow this part

ps ax | grep -v grep

@oskapt
Copy link
Author

oskapt commented Dec 12, 2023

I am not sure I follow this part

ps ax | grep -v grep

This is standard when grepping for something because the grep command also includes the thing you're grepping for. For example (from something unrelated but that I already had open in my terminal):

root@axigen-0:/axigen/var/log# ps ax | grep entrypoint.sh
      1 pts/0    Ss+    0:00 /bin/bash /axigen/bin/entrypoint.sh
    348 pts/1    S+     0:00 grep --color=auto entrypoint.sh

If I was only looking for lines with entrypoint.sh to find the PID, I need to exclude the grep command that also matches.

Using grep -v grep means, "exclude any line that has grep in it," which assures you that you're only processing the lines you're looking for.

@ilyam8
Copy link

ilyam8 commented Dec 12, 2023

Yeah, I mean the order - ps ax | grep -v grep. Why grep after ps? It does nothing.

On a side note: I usually do the following (first letter in square brackets)

ps ax | grep [e]ntrypoint.sh

@oskapt
Copy link
Author

oskapt commented Dec 12, 2023

  • ps ax shows all processes running on the host.
  • grep -v grep excludes the grep command
  • grep -m 1 $DAEMON returns the first match of whatever is in the variable $DAEMON
  • awk '{ print $1 }' returns the first field (which is the pid)

The two grep lines were in the opposite order, which could, in an unusual circumstance, cause the grep line to be matched before $DAEMON and then excluded, resulting in no matches. Flipping it around ensures that only $DAEMON lines are included.

Doing it with square brackets is another way, but it's dependent on the shell. Using grep -v is consistent across any shell I might be working in, or any scripts that I write.

Can you explain why you think that "grep after ps does nothing?"

@ilyam8
Copy link

ilyam8 commented Dec 12, 2023

Ah, you were fixing this

It's possible, but only if grep -v $DAEMON is earlier in the process list than "$DAEMON" itself. The only way that can happen is if this script is run before netdata is started, in which case netdata isn't running and will be started by the script.

I guess I didn't read or understand. So grep -v grep is supposed to filter other grep $DAEMON command that is running at the same time but also started before Netdata. I am not sure this can happen. But thanks for your detailed explanation.

@oskapt
Copy link
Author

oskapt commented Dec 13, 2023

I agree that it's not likely to ever happen, since it would require that the grep command had a pid lower than the running netdata process. However, placing grep -v grep first in the chain changes "unlikely to happen" to "will never happen," and that seemed reasonable.

@oskapt
Copy link
Author

oskapt commented Jul 31, 2024

Synology DSM >= 6.1 no longer calls rc.local, so I've updated the script with new instructions.

First, don't let Netdata write to /opt/netdata because the DSM root partition is only ~2GB in size. Symlink /opt/netdata to /volume1/netdata.

Second, use Task Scheduler to create a Triggered Task that fires at boot and calls /usr/local/etc/rc.d/rc.netdata start. I'm not sure if /etc gets overwritten during DSM updates, but allegedly /usr/local/etc/rc.d is safe. I haven't tried an upgrade yet. Alternatively you can put it in /volume1/netdata and call it from there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment