Implement podman rename via re-apply of containers
To w/a the missing a container rename feature of podman, implement renaming via removing of the original container and re-applying it from the same configs but using the new name. This fixes idempotency issues when service containers are executed under ephemeral names created via the paunch's unique containers names generator, while it is expected to have them executed under its wanted config names. Change-Id: If851604d25b6c7982d950bb9e13dceada3bfc161 Closes-Bug: #1805410 Signed-off-by: Bogdan Dobrelya <bdobreli@redhat.com>
This commit is contained in:
parent
934b7e0fde
commit
510f091353
@ -12,11 +12,13 @@
|
||||
#
|
||||
|
||||
import collections
|
||||
import jmespath
|
||||
import json
|
||||
import random
|
||||
import string
|
||||
import subprocess
|
||||
|
||||
from paunch.builder import podman
|
||||
from paunch.utils import common
|
||||
from paunch.utils import systemd
|
||||
|
||||
@ -157,6 +159,28 @@ class BaseRunner(object):
|
||||
conf_id)
|
||||
self.remove_containers(conf_id)
|
||||
|
||||
def discover_container_config(self, configs, container, name):
|
||||
'''Find the paunch and runtime configs of a container by name.'''
|
||||
for conf_id in self.current_config_ids():
|
||||
jquerry = ("[] | [?(Name=='%s' && "
|
||||
"Config.Labels.container_name=='%s' && "
|
||||
"Config.Labels.config_id=='%s')]" %
|
||||
(container, name, conf_id))
|
||||
runtime_conf = None
|
||||
try:
|
||||
runtime_conf = jmespath.search(jquerry,
|
||||
configs[conf_id])[0]
|
||||
result = (conf_id, runtime_conf)
|
||||
except Exception:
|
||||
self.log.error("Failed searching container %s "
|
||||
"for config %s" % (container, conf_id))
|
||||
result = (None, None)
|
||||
if runtime_conf:
|
||||
self.log.debug("Found container %s "
|
||||
"for config %s" % (container, conf_id))
|
||||
break
|
||||
return result
|
||||
|
||||
def list_configs(self):
|
||||
configs = collections.defaultdict(list)
|
||||
for conf_id in self.current_config_ids():
|
||||
@ -259,6 +283,54 @@ class PodmanRunner(BaseRunner):
|
||||
|
||||
def rename_container(self, container, name):
|
||||
# TODO(emilien) podman doesn't support rename, we'll handle it
|
||||
# in paunch itself, probably.
|
||||
self.log.warning("container renaming isn't supported by podman")
|
||||
pass
|
||||
# in paunch itself for now
|
||||
configs = self.list_configs()
|
||||
config_id, config = self.discover_container_config(
|
||||
configs, container, name)
|
||||
# Get config_data dict by the discovered conf ID,
|
||||
# paunch needs it for maintaining idempotency within a conf ID
|
||||
filter_names = ("[] | [?(Name!='%s' && "
|
||||
"Config.Labels.config_id=='%s')]"
|
||||
".Name" % (container, config_id))
|
||||
filter_cdata = ("[] | [?(Name!='%s' && "
|
||||
"Config.Labels.config_id=='%s')]"
|
||||
".Config.Labels.config_data" % (container, config_id))
|
||||
names = None
|
||||
cdata = None
|
||||
try:
|
||||
names = jmespath.search(filter_names, configs[config_id])
|
||||
cdata = jmespath.search(filter_cdata, configs[config_id])
|
||||
except jmespath.exceptions.LexerError:
|
||||
self.log.error("Failed to rename a container %s into %s: "
|
||||
"used a bad search pattern" % (container, name))
|
||||
return
|
||||
|
||||
if not names or not cdata:
|
||||
self.log.error("Failed to rename a container %s into %s: "
|
||||
"no config_data was found" % (container, name))
|
||||
return
|
||||
|
||||
# Rename the wanted container in the config_data fetched from the
|
||||
# discovered config
|
||||
config_data = dict(zip(names, map(json.loads, cdata)))
|
||||
config_data[name] = json.loads(
|
||||
config.get('Config').get('Labels').get('config_data'))
|
||||
|
||||
# Re-apply a container under its amended name using the fetched configs
|
||||
self.log.debug("Renaming a container known as %s into %s, "
|
||||
"via re-applying its original config" %
|
||||
(container, name))
|
||||
self.log.debug("Removing the destination container %s" % name)
|
||||
self.stop_container(name)
|
||||
self.remove_container(name)
|
||||
self.log.debug("Removing a container known as %s" % container)
|
||||
self.stop_container(container)
|
||||
self.remove_container(container)
|
||||
builder = podman.PodmanBuilder(
|
||||
config_id=config_id,
|
||||
config=config_data,
|
||||
runner=self,
|
||||
labels=None,
|
||||
log=self.log
|
||||
)
|
||||
builder.apply()
|
||||
|
@ -6,3 +6,4 @@ pbr>=2.0.0,!=2.1.0 # Apache-2.0
|
||||
|
||||
cliff>=2.6.0 # Apache-2.0
|
||||
tenacity>=3.2.1 # Apache-2.0
|
||||
jmespath>=0.9.0 # MIT
|
||||
|
Loading…
Reference in New Issue
Block a user