A few pointers about launchd and daemondo
Scott Haneda
talklists at newgeo.com
Wed Nov 4 15:54:32 PST 2009
On Oct 30, 2009, at 2:55 PM, Panagiotis Atmatzidis wrote:
> Greetings,
>
> I've created my first launchd script. It's for OpenVPN2. Here are
> the files I've created so far:
Just out of general curiosity, why use openVPN2? I have been meaning
to create a set of launchd items that start the built in VPN server on
OS X. It is really quite trivial with the inbuilt one. Just start it
up, give it a range, plop in some user:pass stuff, and you have a
pretty nice VPN ready to go.
Apparently OS X Sever has a GUI for this, but OS X Client does not
even claim to support it, though it does, and has been every day I am
at the coffee shop :)
What advantages, and what am I missing out on by using this method
over openVPN?
> devo:/opt/local/etc/LaunchDaemons root# ls -l org.macports.OpenVPN2/
> total 16
> -rwxr-xr-x 1 root admin 957 Oct 30 23:06 OpenVPN2.wrapper
> -rw-r--r-- 1 root admin 1026 Oct 30 23:39
> org.macports.OpenVPN2.plist
I do not like the way in which launchd scrips are put into play in
MacPorts. I never could understand the magic it was doing under the
hood. Since I consider them almost always starting servers of some
form, I have moved to making my own normal .plist files and putting
them in files/tld.app.binary.plist, so org.pure-ftpd.ftpd.plist or
similar.
it would seem every time I needed to add something a little out of the
ordinary I was getting stuck, whereas a plist is rather simple for me
to understand, and just as easy to copy into place.
> The Wrapper
>
> [snip... removed wrapper code]
>
>
> the .plist which is an: ln -sf /opt/local/etc/LaunchDaemons/
> org.macports.OpenVPN2/org.macports.OpenVPN2.plist /Library/
> LaunchDaemons/....
> ------------------------
> <?xml version='1.0' encoding='UTF-8'?>
> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
> "http://www.apple.com/DTDs/PropertyList-1.0.dtd" >
> <plist version='1.0'>
> <dict>
> <key>Label</key><string>org.macports.OpenVPN2</string>
> <key>ProgramArguments</key>
> <array>
> <string>/opt/local/bin/daemondo</string>
> <string>--label=OpenVPN2</string>
> <string>--start-cmd</string>
> <string>/opt/local/etc/LaunchDaemons/org.macports.OpenVPN2/
> OpenVPN2.wrapper</string>
> <string>start</string>
> <string>;</string>
> <string>--stop-cmd</string>
> <string>/opt/local/etc/LaunchDaemons/org.macports.OpenVPN2/
> OpenVPN2.wrapper</string>
> <string>stop</string>
> <string>;</string>
> <string>--restart-cmd</string>
> <string>/opt/local/etc/LaunchDaemons/org.macports.OpenVPN2/
> OpenVPN2.wrapper</string>
> <string>restart</string>
> <string>;</string>
> <string>--pid=none</string>
> </array>
> <key>Debug</key><false/>
> <key>Disabled</key><false/>
> <key>OnDemand</key><false/>
> <key>RunAtLoad</key><true/>
> <key>NetworkState</key><true/>
> </dict>
> </plist>
>
>
> However, there are two issues that I can't seem to be able to manage
> right now.
>
> The first is that OpenVPN does not start at boot while the module is
> loaded succesfully. When I login to the system and kill daemondo, it
> relaunches itself and ovpn works fine. I suspect that the problem is
> en0. Launchd tries to launchd openvpn before en0 comes up. That's
> why I put the NetworkState keyword, but it does not seem to effect
> *any* startup script. I had issues with dnsmasq also in the recent
> past.
Are you sure that "NetworkState" is what you are looking for?
From the man page $man 5 launchd.plist
NetworkState <boolean>
If true, the job will be kept alive as long as the network is up,
where up is defined as at least one non-loopback interface being
up
and having IPv4 or IPv6 addresses assigned to them. If false, the
job will be kept alive in the inverse condition.
NetworkState seems to be for keeping a job alive if the network is up,
or keeping it dead if the network is down. In your case, the app is
not up yet. My interpretation is that since the app never launched
via launchd, the NetworkState test never comes into play.
I could be wrong, that is just how I am reading that man page.
I have a machine that loads a good chunk of IP's into an interface,
and I need to make sure they are all up before moving on, or the final
app will not work correctly. I used `ipconfig` to make sure this
happened in a "wrapper" script.
$man ipconfig
There is a lot of good stuff in there that could help you, even just
the logging verbosity you can kick up and see what is going on.
The argument I used was
waitall Blocks until all network services have completed
configuring,
or have timed out in the process of configuring.
This is only useful for initial system start-up time
synchronization for legacy network services that are inca-
pable of dealing with dynamic network configuration
changes.
If you were to add to your wrapper/start script:
/usr/sbin/ipconfig waitall
Then a basic test of the result of that command:
$? tests the last command ran, as far as I now, or set the result to a
variable...
if [[ $? -eq 0 ]]
then
echo "Interfaces are NOT up"
else
echo "Interfaces are up"
fi
You probably have to put that in a while loop, and keep on trying
until the interfaces are all up. I would be inclined to put a little
`sleep 1` in there to reduce the number of checks. And a counter to
make sure it does not accidentally run wild and keep running forever,
sort of a safety net to exit. If loopcount > 100 then exit type of
thing.
> The second problem with this script is that when I unload it via
> launchd it does not kill the process. Launchd unloads the script and
> (probably) will not be launchd (if -w is added) in the next boot but
> daemondo keeps running the process nevertheless. Is this a normal
> behaviour?
I can not help on this one, unload should not only remove the job, but
also stop it if it is running. Though I find this very dependent on
how the app itself works. For example, I never seem to get a
unloading of Apache2 to stop apache, which I assume is why there are
tools like `apachectl stop`.
Apache spawns a number of processes of itself as needed, so to me, it
make sense that launchd would only be able to track the initial app it
started. If I had a launchd item that started 10 copies of `find`,
and then unloaded that launchd, I would imagine I would only stop 9 of
those copies, the rest would keep running. Or maybe I only stop the
script itself, and all the copies of `find` keep running.
Maybe keep that in mind when working on this.
> I'm not *that* worried about the second. I'd prefer to have a
> solution about the first one, which is the most important for me.
I would get a standalone launchd plist calling a script that does the
work of starting the job as you want it. While you can jam all sorts
of commands and scripting into a launchd file, I find them to be messy
and hard to debug. You have to take special care with spaces, quotes,
and paths and some other little "gotcha" areas.
I find if I can get a local script to start my app as I want it, then
I just have one command in my plist to call that script, things are a
lot cleaner.
Once you have that working, it is up to you to use `daemondo` or not.
Hopefully some of this is of help. I am not very versed in much of
this, so it is mostly just to point you in a direction that hopefully
gets you where you need to go.
--
Scott * If you contact me off list replace talklists@ with scott@ *
More information about the macports-users
mailing list