9

I would like to periodically trigger a remote bash script. How this needs to work is that a 3rd party application will connect to a CentOS 7 system on a specific TCP port and send a short text message. SSH is not an option because of the 3rd party application.

When the message is received it needs to pass the IP address to the bash script. I would like the bash script to run and then go dormant until the next message. I would prefer not to write a daemon. I just want to keep this simple.

These messages may come a few times per week or less. We had this running on using xinetd but not sure exactly how to make this work with systemd.

Here is what I have so far:

/etc/systemd/systemfoo.service

[Unit]
Description=Foo Service
After=network.target foo.socket
Requires=foo.socket

[Service]
Type=oneshot
ExecStart=/bin/bash /opt/foo/foo.sh
TimeoutStopSec=5

[Install]
WantedBy=multi-user.target

/etc/systemd/systemfoo.socket

[Unit]
Description=Foo Socket
PartOf=foo.service

[Socket]
ListenStream=127.0.0.1:7780

[Install]
WantedBy=sockets.target

/opt/foo/foo.sh

#!/bin/bash

# Not sure how to get IP
logger -t FOO "Connection received:"
# Do some action

This is what I see in the log:

Jul 10 17:29:32 localhost systemd: Listening on Foo Socket.
Jul 10 17:29:32 localhost systemd: Starting Foo Socket.
Jul 10 17:29:32 localhost systemd: Started Foo Service.
Jul 10 17:29:32 localhost systemd: Starting Foo Service...
Jul 10 17:29:32 localhost FOO: Connection received
Jul 10 17:29:53 localhost systemd: Started Session 4 of user vagrant.
Jul 10 17:29:53 localhost systemd-logind: New session 4 of user vagrant.
Jul 10 17:29:53 localhost systemd: Starting Session 4 of user vagrant.
Jul 10 17:29:56 localhost su: (to root) vagrant on pts/1
Jul 10 17:30:11 localhost systemd: Started Foo Service.
Jul 10 17:30:11 localhost systemd: Starting Foo Service...
Jul 10 17:30:11 localhost FOO: Connection received
Jul 10 17:30:11 localhost systemd: Started Foo Service.
Jul 10 17:30:11 localhost systemd: Starting Foo Service...
Jul 10 17:30:11 localhost FOO: Connection received
Jul 10 17:30:11 localhost systemd: Started Foo Service.
Jul 10 17:30:11 localhost systemd: Starting Foo Service...
Jul 10 17:30:11 localhost FOO: Connection received
Jul 10 17:30:11 localhost systemd: Started Foo Service.
Jul 10 17:30:11 localhost systemd: Starting Foo Service...
Jul 10 17:30:11 localhost FOO: Connection received
Jul 10 17:30:11 localhost systemd: Started Foo Service.
Jul 10 17:30:11 localhost systemd: Starting Foo Service...
Jul 10 17:30:11 localhost FOO: Connection received
Jul 10 17:30:11 localhost systemd: start request repeated too quickly for foo.service
Jul 10 17:30:11 localhost systemd: Failed to start Foo Service.
Jul 10 17:30:11 localhost systemd: Unit foo.socket entered failed state.
Jul 10 17:30:11 localhost systemd: Unit foo.service entered failed state.
Jul 10 17:30:11 localhost systemd: foo.service failed.

Any suggestions on how to make systemd run the script once and then wait for the next message before running it again?

For testing I'm just running:

echo "Hello" | nc 127.0.0.1 7780

Updated Working Configuration

/etc/systemd/[email protected] Note the @.

[Unit]
Description=Foo Service
After=network.target systemfoo.socket
Requires=systemfoo.socket

[Service]
Type=oneshot
ExecStart=/bin/bash /opt/foo/foo.sh
TimeoutStopSec=5

[Install]
WantedBy=multi-user.target

/etc/systemd/systemfoo.socket

[Unit]
Description=Foo Socket
[email protected]

[Socket]
ListenStream=127.0.0.1:7780
Accept=Yes

[Install]
WantedBy=sockets.target

/opt/foo/foo.sh

#!/bin/bash

# Not sure how to get IP
logger -t FOO "Connection received: $REMOTE_ADDR $REMOTE_PORT"
# Do some action

Required to load the configuration into systemd:

systemctl enable systemfoo.socket
systemctl start systemfoo.socket
Hugh
  • 93
  • 1
  • 4
  • 1
    Just for completeness to enable the socket you would need to `systemctl enable foo.socket` and `systemctl start foo.socket` – Hugh Jul 11 '18 at 16:47

1 Answers1

8

You should add Accept=yes to the socket unit, indicating that systemd should start separate service instances for each connection, and then turn the service unit into a template ([email protected]), to be instantiated separately for each connection. Then the remote address and port should be available in the REMOTE_ADDR and REMOTE_PORT environment variables, according to the systemd.socket(5) manpage.