Add systemd healthchecks to podman
Add systemd managed healthchecks and timers to podman containers. Change-Id: I1949b7ba9e06110a2e91c9cb3359605cae3638e5
This commit is contained in:
parent
aa42360b85
commit
c23384a6d4
|
@ -104,6 +104,13 @@ class BaseBuilder(object):
|
||||||
systemd.service_create(container=container_name,
|
systemd.service_create(container=container_name,
|
||||||
cconfig=cconfig,
|
cconfig=cconfig,
|
||||||
log=self.log)
|
log=self.log)
|
||||||
|
if 'healthcheck' in cconfig:
|
||||||
|
systemd.healthcheck_create(container=container_name,
|
||||||
|
log=self.log)
|
||||||
|
systemd.healthcheck_timer_create(
|
||||||
|
container=container_name,
|
||||||
|
cconfig=cconfig,
|
||||||
|
log=self.log)
|
||||||
return stdout, stderr, deploy_status_code
|
return stdout, stderr, deploy_status_code
|
||||||
|
|
||||||
def delete_missing_and_updated(self):
|
def delete_missing_and_updated(self):
|
||||||
|
|
|
@ -63,6 +63,7 @@ class PodmanBuilder(base.BaseBuilder):
|
||||||
|
|
||||||
self.list_arg(cconfig, cmd, 'cap_add', '--cap-add')
|
self.list_arg(cconfig, cmd, 'cap_add', '--cap-add')
|
||||||
self.list_arg(cconfig, cmd, 'cap_drop', '--cap-drop')
|
self.list_arg(cconfig, cmd, 'cap_drop', '--cap-drop')
|
||||||
|
self.string_arg(cconfig, cmd, 'check_interval', '--check-interval')
|
||||||
|
|
||||||
cmd.append(cconfig.get('image', ''))
|
cmd.append(cconfig.get('image', ''))
|
||||||
cmd.extend(self.command_argument(cconfig.get('command')))
|
cmd.extend(self.command_argument(cconfig.get('command')))
|
||||||
|
|
|
@ -60,3 +60,45 @@ class TestUtilsSystemd(base.TestCase):
|
||||||
mock.call(['systemctl', 'disable', service]),
|
mock.call(['systemctl', 'disable', service]),
|
||||||
mock.call(['systemctl', 'daemon-reload']),
|
mock.call(['systemctl', 'daemon-reload']),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@mock.patch('subprocess.call', autospec=True)
|
||||||
|
@mock.patch('os.chmod')
|
||||||
|
def test_healthcheck_create(self, mock_chmod, mock_subprocess_call):
|
||||||
|
container = 'my_app'
|
||||||
|
service = 'tripleo_' + container
|
||||||
|
tempdir = tempfile.mkdtemp()
|
||||||
|
healthcheck = service + '_healthcheck.service'
|
||||||
|
sysd_unit_f = tempdir + healthcheck
|
||||||
|
|
||||||
|
systemd.healthcheck_create(container, tempdir)
|
||||||
|
unit = open(sysd_unit_f, 'rt').read()
|
||||||
|
|
||||||
|
self.assertIn('ExecStart=/usr/bin/podman exec my_app '
|
||||||
|
'/openstack/healthcheck', unit)
|
||||||
|
mock_chmod.assert_has_calls([mock.call(sysd_unit_f, 420)])
|
||||||
|
mock_subprocess_call.assert_has_calls([
|
||||||
|
mock.call(['systemctl', 'enable', '--now',
|
||||||
|
healthcheck]),
|
||||||
|
mock.call(['systemctl', 'daemon-reload']),
|
||||||
|
])
|
||||||
|
|
||||||
|
@mock.patch('subprocess.call', autospec=True)
|
||||||
|
@mock.patch('os.chmod')
|
||||||
|
def test_healthcheck_timer_create(self, mock_chmod, mock_subprocess_call):
|
||||||
|
container = 'my_app'
|
||||||
|
service = 'tripleo_' + container
|
||||||
|
cconfig = {'check_interval': '15'}
|
||||||
|
tempdir = tempfile.mkdtemp()
|
||||||
|
healthcheck_timer = service + '_healthcheck.timer'
|
||||||
|
sysd_unit_f = tempdir + healthcheck_timer
|
||||||
|
|
||||||
|
systemd.healthcheck_timer_create(container, cconfig, tempdir)
|
||||||
|
unit = open(sysd_unit_f, 'rt').read()
|
||||||
|
|
||||||
|
self.assertIn('Requires=my_app_healthcheck.service', unit)
|
||||||
|
self.assertIn('OnCalendar=*-*-* *:*:00/15', unit)
|
||||||
|
mock_chmod.assert_has_calls([mock.call(sysd_unit_f, 420)])
|
||||||
|
mock_subprocess_call.assert_has_calls([
|
||||||
|
mock.call(['systemctl', 'enable', '--now', healthcheck_timer]),
|
||||||
|
mock.call(['systemctl', 'daemon-reload']),
|
||||||
|
])
|
||||||
|
|
|
@ -30,7 +30,7 @@ def service_create(container, cconfig, sysdir='/etc/systemd/system/',
|
||||||
:type cconfig: Dictionary
|
:type cconfig: Dictionary
|
||||||
|
|
||||||
:param sysdir: systemd unit files directory
|
:param sysdir: systemd unit files directory
|
||||||
:type sysdir: string
|
:type sysdir: String
|
||||||
|
|
||||||
:param log: optional pre-defined logger for messages
|
:param log: optional pre-defined logger for messages
|
||||||
:type log: logging.RootLogger
|
:type log: logging.RootLogger
|
||||||
|
@ -105,3 +105,84 @@ def service_delete(container, log=None):
|
||||||
subprocess.call(['systemctl', 'daemon-reload'])
|
subprocess.call(['systemctl', 'daemon-reload'])
|
||||||
else:
|
else:
|
||||||
log.warning('No systemd unit file was found for %s' % service)
|
log.warning('No systemd unit file was found for %s' % service)
|
||||||
|
|
||||||
|
|
||||||
|
def healthcheck_create(container, sysdir='/etc/systemd/system/', log=None):
|
||||||
|
"""Create a healthcheck for a service in systemd
|
||||||
|
|
||||||
|
:param container: container name
|
||||||
|
:type container: String
|
||||||
|
|
||||||
|
:param sysdir: systemd unit files directory
|
||||||
|
:type sysdir: String
|
||||||
|
|
||||||
|
:param log: optional pre-defined logger for messages
|
||||||
|
:type log: logging.RootLogger
|
||||||
|
"""
|
||||||
|
|
||||||
|
log = log or common.configure_logging(__name__)
|
||||||
|
|
||||||
|
service = 'tripleo_' + container
|
||||||
|
healthcheck = service + '_healthcheck.service'
|
||||||
|
sysd_unit_f = sysdir + healthcheck
|
||||||
|
log.debug('Creating systemd unit file: %s' % sysd_unit_f)
|
||||||
|
s_config = {
|
||||||
|
'name': container,
|
||||||
|
'restart': 'restart',
|
||||||
|
}
|
||||||
|
with open(sysd_unit_f, 'w') as unit_file:
|
||||||
|
os.chmod(unit_file.name, 0o644)
|
||||||
|
unit_file.write("""[Unit]
|
||||||
|
Description=%(name)s healthcheck
|
||||||
|
After=paunch-container-shutdown.service
|
||||||
|
Requisite=%(name)s.service
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/bin/podman exec %(name)s /openstack/healthcheck
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
""" % s_config)
|
||||||
|
subprocess.call(['systemctl', 'enable', '--now', healthcheck])
|
||||||
|
subprocess.call(['systemctl', 'daemon-reload'])
|
||||||
|
|
||||||
|
|
||||||
|
def healthcheck_timer_create(container, cconfig, sysdir='/etc/systemd/system/',
|
||||||
|
log=None):
|
||||||
|
"""Create a systemd timer for a healthcheck
|
||||||
|
|
||||||
|
:param container: container name
|
||||||
|
:type container: String
|
||||||
|
|
||||||
|
:param cconfig: container configuration
|
||||||
|
:type cconfig: Dictionary
|
||||||
|
|
||||||
|
:param sysdir: systemd unit files directory
|
||||||
|
:type sysdir: string
|
||||||
|
|
||||||
|
:param log: optional pre-defined logger for messages
|
||||||
|
:type log: logging.RootLogger
|
||||||
|
"""
|
||||||
|
|
||||||
|
log = log or common.configure_logging(__name__)
|
||||||
|
|
||||||
|
service = 'tripleo_' + container
|
||||||
|
healthcheck_timer = service + '_healthcheck.timer'
|
||||||
|
sysd_timer_f = sysdir + healthcheck_timer
|
||||||
|
log.debug('Creating systemd timer file: %s' % sysd_timer_f)
|
||||||
|
interval = cconfig.get('check_interval', 30)
|
||||||
|
s_config = {
|
||||||
|
'name': container,
|
||||||
|
'interval': interval
|
||||||
|
}
|
||||||
|
with open(sysd_timer_f, 'w') as timer_file:
|
||||||
|
os.chmod(timer_file.name, 0o644)
|
||||||
|
timer_file.write("""[Unit]
|
||||||
|
Description=%(name)s container healthcheck
|
||||||
|
Requires=%(name)s_healthcheck.service
|
||||||
|
[Timer]
|
||||||
|
OnUnitActiveSec=90
|
||||||
|
OnCalendar=*-*-* *:*:00/%(interval)s
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target""" % s_config)
|
||||||
|
subprocess.call(['systemctl', 'enable', '--now', healthcheck_timer])
|
||||||
|
subprocess.call(['systemctl', 'daemon-reload'])
|
||||||
|
|
Loading…
Reference in New Issue