7

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/systemfoo@.service 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
PartOf=systemfoo@.service

[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
1
  • 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
7

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 (systemfoo@.service), 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.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.