0

I have a simple python script which I am using to automate updates to a dhcp config file.

The Idea is that it puts the new config file in the dhcpd directory runs a check and if that returns ok it can restart the service. My code looks like this:


syslog.syslog(syslog.LOG_INFO, 'INFO: file copied to /etc/dhcp/conf.d')
return_code = subprocess.call(['dhcpd -t -cf /etc/dhcp/dhcpd.conf'], shell=True)
if return_code != 0:
    print('dhcp config test failed, exiting script')
    syslog.syslog(syslog.LOG_ERR, 'ERROR: dhcp config test failed, exiting script')
    sys.exit()
else:
    print('dhcp config test passed restarting service')
    syslog.syslog(syslog.LOG_INFO, 'INFO: config check passed, restarting service')
    return_code = subprocess.call(['service', conf['service_name'], 'restart'])
    if return_code != 0:
        print('dhcpd service failed to restart')
        syslog.syslog(syslog.LOG_ERR, 'ERROR: dhcpd service failed to restart')
    else:
        print('dhcpd service restarted')
        syslog.syslog(syslog.LOG_INFO, 'INFO: service restarted')
        email_results()

This script is kicked off by a cron job, when it runs it always fails at this bit:

print('dhcp config test failed, exiting script')

If I run the script manually it always works fine and continues to the end as expected.

If I open the python shell and run the important commands by hand it seems to work fine:

python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> return_code = subprocess.call(['dhcpd -t -cf /etc/dhcp/dhcpd.conf'], shell=True)
Internet Systems Consortium DHCP Server 4.3.3
Copyright 2004-2015 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/
Config file: /etc/dhcp/dhcpd.conf
Database file: /var/lib/dhcp/dhcpd.leases
PID file: /var/run/dhcpd.pid
>>> print(return_code)
0

I have tried using "shell=True" and also tried without. I have also tried subprocess.check_call with the same results.

Where am I going wrong here?

Martin W
  • 372
  • 1
  • 2
  • 14
  • 2
    Maybe it can't find the `dhcp`? What's your PATH in cron? Also check this regarding subprocesses.call problems in cron - https://stackoverflow.com/questions/30766067/using-python-subprocess-call-with-crontab – h4z3 Jun 14 '19 at 11:20
  • May be better if you use `subprocess.Popen` instead and leave out the shell parameter, let its use its default which is`False`. The commands go as a list rather than a string. [docs](https://docs.python.org/3.6/library/subprocess.html#subprocess.Popen) – cardamom Jun 14 '19 at 11:31
  • 2
    It it must be started from cron, the most robust way is to set the path inside the script of to use full paths for all files including commands like here `dhcpd`. – Serge Ballesta Jun 14 '19 at 11:32

2 Answers2

1

Use absolute paths instead of just command names like dhcpd in your script.

Try if your script still works when you call it after setting an empty PATH.

Roland Weber
  • 1,865
  • 2
  • 17
  • 27
  • I've made this a community wiki because the answers have actually been provided by other folks in comments. But I don't want this question to remain "unanswered". – Roland Weber Jun 14 '19 at 12:06
1

The arguments to subprocess should be either an array of strings or a single string. Passing in an array of a single string is an error, though it might happen to work on some platforms which are fundamentally broken anyway.

You want

return_code = subprocess.call(['dhcpd', '-t', '-cf', '/etc/dhcp/dhcpd.conf'])   # shell=False implicitly

or

return_code = subprocess.call('dhcpd -t -cf /etc/dhcp/dhcpd.conf', shell=True)

but really, you should avoid shell=True whenever possible; see also Actual meaning of 'shell=True' in subprocess

And of course, if dhcpd is not in the PATH that you get from cron, you want to update the PATH correspondingly, or use an explicit hard-coded path like /usr/sbin/dhcpd (I generally recommend the former).

tripleee
  • 175,061
  • 34
  • 275
  • 318