Always attempt a graceful container stop/remove

When paunch removes a container, like applying a container's config
changes, it does that not gracefully. That poses an issue for some
cases, like stateful services. To mitigate that, attempt stopping the
container prior to removing it. And use the defined stop signal and
timeout settings for such a container, when stopping it. If there is no
signal/timeout in the config, fallback to deaults of SIGTERM and a 10s.

Related-bug: #1810690
Change-Id: I7c72ea055984bb5ff3ea7cea019693d61245212f
Signed-off-by: Bogdan Dobrelya <bdobreli@redhat.com>
This commit is contained in:
Bogdan Dobrelya
2019-01-09 12:51:45 +02:00
parent 510f091353
commit b5a14c6cd0
4 changed files with 108 additions and 16 deletions

View File

@@ -18,6 +18,7 @@ import random
import string
import subprocess
from paunch.builder.base import BaseBuilder
from paunch.builder import podman
from paunch.utils import common
from paunch.utils import systemd
@@ -215,25 +216,66 @@ class BaseRunner(object):
yield line.split()
def remove_containers(self, conf_id):
configs = self.list_configs()
for container in self.containers_in_config(conf_id):
self.remove_container(container)
# Find the container's configh in the known configs
# (the name should be matching its config name)
cid, cconfig = self.discover_container_config(
configs, container, container)
if cid != conf_id:
self.log.debug('Ignoring container %s from config'
'ID %s' % (container, cid))
continue
self.remove_container(container, conf_id, cconfig)
def remove_container(self, container):
def remove_container(self, container, conf_id=None, cconfig=None):
if self.cont_cmd == 'podman':
systemd.service_delete(container=container, log=self.log)
# NOTE(bogdando): that's also used when applying changes on
# containers and must be a graceful operation
self.stop_container(container=container, cont_cmd=self.cont_cmd,
quiet=True, conf_id=conf_id, cconfig=cconfig)
cmd = [self.cont_cmd, 'rm', '-f', container]
cmd_stdout, cmd_stderr, returncode = self.execute(cmd, self.log)
if returncode != 0:
self.log.error('Error removing container: %s' % container)
self.log.error(cmd_stderr)
def stop_container(self, container, cont_cmd=None, quiet=False):
def stop_container(self, container, cont_cmd=None, quiet=False,
conf_id=None, cconfig=None):
cont_cmd = cont_cmd or self.cont_cmd
cmd = [cont_cmd, 'stop', container]
cmd = [cont_cmd, 'stop']
# Pick pre-configured timeout and signal or use defaults for graceful
# stopping of the container, which is important to have for applying
# the container config updates
config = {}
if cconfig and 'stop_signal' in cconfig.keys():
config[container] = cconfig
else:
config[container] = {'stop_signal': 'SIGTERM'}
if cconfig and 'stop_grace_period' in cconfig.keys():
config[container].update(cconfig)
else:
config[container].update({'stop_grace_period': '10s'})
builder = BaseBuilder(config_id=conf_id,
config=config,
runner=self,
labels=None,
log=self.log)
builder.string_arg(config[container], cmd, 'stop_signal',
'--stop-signal')
builder.string_arg(config[container], cmd,
'stop_grace_period', '--stop-timeout',
builder.duration)
cmd.append(container)
# Log the stop command events disregard of the quiet setting
self.log.debug('Stopping container %s: %s' % (container, cmd))
cmd_stdout, cmd_stderr, returncode = self.execute(cmd, quiet=quiet)
if returncode != 0 and not quiet:
if returncode != 0:
self.log.error('Error stopping container: %s' % container)
self.log.error(cmd_stderr)
if not quiet:
self.log.error(cmd_stderr)
def rename_containers(self):
current_containers = []