tripleo_container_manage: reduce cleanup when single config is given

If a single JSON file is given to tripleo_container_manage_config, we
don't want to remove containers from the same config in that directory,
we just want to manage that container. Which is often used to either
debug or just controlling one container at a time (FFU).

This patch will change the needs_delete() filter, and if only one config
is given, we won't cleanup other containers.

We also add the clean_orphans config param to the method, so we can
override it later.

Also if no config is given (could be due to a wrong given
tripleo_container_manage_config_patterns which would not match
anything), we don't want to remove anything for safety purpose.

Change-Id: Ic06ac0f41767ca513c612b1ebb38d2ff92500ea5
(cherry picked from commit 99b8a1c4b8)
This commit is contained in:
Emilien Macchi 2020-02-11 15:21:46 -05:00
parent 834bbc344b
commit 327e8fa386
2 changed files with 134 additions and 3 deletions

View File

@ -86,16 +86,33 @@ class FilterModule(object):
break
return return_dict
def needs_delete(self, container_infos, config, config_id):
def needs_delete(self, container_infos, config, config_id,
clean_orphans=True):
"""Returns a list of containers which need to be removed.
This filter will check which containers need to be removed for these
reasons: no config_data, updated config_data or container not
part of the global config.
:param container_infos: list
:param config: dict
:param config_id: string
:param clean_orphans: bool
:returns: list
"""
to_delete = []
to_skip = []
installed_containers = []
# If config has no item, it's probably due to a user error where
# the given pattern match no container.
# If config has one item, it's because we want to manage only one
# container.
# In both cases, we don't want to remove the others in the same
# config_id.
if len(config) <= 1:
clean_orphans = False
for c in container_infos:
c_name = c['Name']
installed_containers.append(c_name)
@ -107,19 +124,22 @@ class FilterModule(object):
# Check containers have a label
if not labels:
to_skip += [c_name]
continue
# Don't delete containers NOT managed by tripleo* or paunch*
elif not re.findall(r"(?=("+'|'.join(['tripleo', 'paunch'])+r"))",
managed_by):
to_skip += [c_name]
continue
# Only remove containers managed in this config_id
elif labels.get('config_id') != config_id:
to_skip += [c_name]
continue
# Remove containers with no config_data
# e.g. broken config containers
elif 'config_data' not in labels:
elif 'config_data' not in labels and clean_orphans:
to_delete += [c_name]
for c_name, config_data in config.items():
@ -159,6 +179,11 @@ class FilterModule(object):
if cmp(c_data, config_data) != 0:
to_delete += [c_name]
# Cleanup installed containers that aren't in config anymore.
for c in installed_containers:
if c not in config.keys() and c not in to_skip and clean_orphans:
to_delete += [c]
return to_delete
def haskey(self, data, attribute, value=None, reverse=False, any=False):

View File

@ -371,6 +371,16 @@ class TestHelperFilters(tests_base.TestCase):
'Labels': None
}
},
{
'Name': 'old_tripleo',
'Config': {
'Labels': {
'managed_by': 'tripleo_ansible',
'config_id': 'tripleo_step1',
'config_data': ""
}
}
},
]
config = {
# we don't want that container to be touched: no restart
@ -391,7 +401,103 @@ class TestHelperFilters(tests_base.TestCase):
# config_data changed: restart needed
'test1': {'start_order': 2},
}
expected_list = ['rabbitmq', 'haproxy', 'heat', 'test1']
expected_list = ['rabbitmq', 'haproxy', 'heat', 'test1', 'old_tripleo']
result = self.filters.needs_delete(container_infos=data,
config=config,
config_id='tripleo_step1')
self.assertEqual(result, expected_list)
def test_needs_delete_single_config(self):
data = [
{
'Name': 'rabbitmq',
'Config': {
'Labels': {
'managed_by': 'tripleo_ansible',
'config_id': 'tripleo_step1',
'container_name': 'rabbitmq',
'name': 'rabbitmq'
}
}
},
{
'Name': 'swift',
'Config': {
'Labels': {
'managed_by': 'tripleo',
'config_id': 'tripleo_step1',
'container_name': 'swift',
'name': 'swift',
'config_data': {'foo': 'bar'}
}
}
},
{
'Name': 'heat',
'Config': {
'Labels': {
'managed_by': 'tripleo-Undercloud',
'config_id': 'tripleo_step1',
'container_name': 'heat',
'name': 'heat',
'config_data': "{'start_order': 0}"
}
}
},
{
'Name': 'haproxy',
'Config': {
'Labels': {
'managed_by': 'paunch',
'config_id': 'tripleo_step1',
'config_data': ""
}
}
},
{
'Name': 'none_tripleo',
'Config': {
'Labels': None
}
},
{
'Name': 'old_tripleo',
'Config': {
'Labels': {
'managed_by': 'tripleo_ansible',
'config_id': 'tripleo_step1',
'config_data': ""
}
}
},
]
config = {
# config_data changed: restart needed
'heat': {'start_order': 1},
}
expected_list = ['heat']
result = self.filters.needs_delete(container_infos=data,
config=config,
config_id='tripleo_step1')
self.assertEqual(result, expected_list)
def test_needs_delete_no_config(self):
data = [
{
'Name': 'heat',
'Config': {
'Labels': {
'managed_by': 'tripleo-Undercloud',
'config_id': 'tripleo_step1',
'container_name': 'heat',
'name': 'heat',
'config_data': "{'start_order': 0}"
}
}
},
]
config = {}
expected_list = []
result = self.filters.needs_delete(container_infos=data,
config=config,
config_id='tripleo_step1')