tripleo-container-manage - first support for idempotency
- Implements a new helper to figure out if the existing containers on the hosts need to be removed (and re-created later). The helper will remove the container if: - the container is managed by tripleo_ansible (+ other conditions later) - a running container isn't in the config - the container has no config_data Label - the config_data changed for the container - Restart the systemd service for the container if the podman_container module reported as changed (note the podman_container isn't yet idempotent but we're working on it in a separated patch) - Fix the healthcheck & timer systemd files to be attached to the right service (with tripleo_ prefix) Story: #2006732 Task: #37163 Change-Id: I5081c918b47dcb9f3629a3649fdf33d17668c1ff
This commit is contained in:
parent
2d42082737
commit
7e41e0642d
|
@ -14,6 +14,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
from collections import OrderedDict
|
||||
from operator import itemgetter
|
||||
|
@ -23,7 +24,8 @@ class FilterModule(object):
|
|||
def filters(self):
|
||||
return {
|
||||
'singledict': self.singledict,
|
||||
'subsort': self.subsort
|
||||
'subsort': self.subsort,
|
||||
'needs_delete': self.needs_delete
|
||||
}
|
||||
|
||||
def subsort(self, dict_to_sort, attribute, null_value=None):
|
||||
|
@ -53,3 +55,78 @@ class FilterModule(object):
|
|||
for i in list_to_convert:
|
||||
return_dict.update(i)
|
||||
return return_dict
|
||||
|
||||
def needs_delete(self, container_infos, config, config_id):
|
||||
"""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.
|
||||
"""
|
||||
to_delete = []
|
||||
to_skip = []
|
||||
installed_containers = []
|
||||
for c in container_infos:
|
||||
c_name = c['Name']
|
||||
installed_containers.append(c_name)
|
||||
|
||||
# Don't delete containers not managed by tripleo-ansible
|
||||
if c['Config']['Labels'].get('managed_by') != 'tripleo_ansible':
|
||||
to_skip += [c_name]
|
||||
continue
|
||||
|
||||
# Only remove containers managed in this config_id
|
||||
if c['Config']['Labels'].get('config_id') != config_id:
|
||||
to_skip += [c_name]
|
||||
continue
|
||||
|
||||
# Remove containers with no config_data
|
||||
# e.g. broken config containers
|
||||
if 'config_data' not in c['Config']['Labels']:
|
||||
to_delete += [c_name]
|
||||
continue
|
||||
|
||||
# Remove containers managed by tripleo-ansible that aren't in
|
||||
# config e.g. containers not needed anymore and removed by an
|
||||
# upgrade. Note: we don't cleanup paunch-managed containers.
|
||||
if c_name not in config:
|
||||
to_delete += [c_name]
|
||||
continue
|
||||
|
||||
for c_name, config_data in config.items():
|
||||
# don't try to remove a container which doesn't exist
|
||||
if c_name not in installed_containers:
|
||||
continue
|
||||
|
||||
# already tagged to be removed
|
||||
if c_name in to_delete:
|
||||
continue
|
||||
|
||||
if c_name in to_skip:
|
||||
continue
|
||||
|
||||
# Remove containers managed by tripleo-ansible when config_data
|
||||
# changed. Since we already cleaned the containers not in config,
|
||||
# this check needs to be in that loop.
|
||||
# e.g. new TRIPLEO_CONFIG_HASH during a minor update
|
||||
try:
|
||||
c_facts = [c['Config']['Labels']['config_data']
|
||||
for c in container_infos if c_name == c['Name']]
|
||||
except KeyError:
|
||||
continue
|
||||
c_facts = c_facts[0] if len(c_facts) == 1 else {}
|
||||
|
||||
# 0 was picked since it's the null_value for the subsort filter.
|
||||
# When a container config doesn't provide the start_order, it'll be
|
||||
# 0 by default, therefore it needs to be added in the config_data
|
||||
# when comparing with the actual container_infos results.
|
||||
if 'start_order' not in config_data:
|
||||
config_data['start_order'] = 0
|
||||
|
||||
# TODO(emilien) double check the comparing here and see if
|
||||
# types are accurate (string vs dict, etc)
|
||||
if c_facts != json.dumps(config_data):
|
||||
to_delete += [c_name]
|
||||
continue
|
||||
|
||||
return to_delete
|
||||
|
|
|
@ -24,15 +24,11 @@
|
|||
command: "{{ tripleo_container_manage_cli }} container exists {{ item.1.command.0 }}"
|
||||
- name: "Check if {{ item.1.command.0 }} container is running"
|
||||
block:
|
||||
- name: "Gather podman infos for {{ item.1.command.0 }}"
|
||||
podman_container_info:
|
||||
name: "{{ item.1.command.0 }}"
|
||||
register: podman_containers
|
||||
- name: "Fail if {{ item.1.command.0 }} is not running"
|
||||
fail:
|
||||
msg: "Can't run container exec for {{ item.0 }}, {{ item.1.command.0 }} is not running"
|
||||
when:
|
||||
- not podman_containers.0.State.Running
|
||||
- not podman_containers.containers.0.State.Running
|
||||
- name: "Prepare the exec command for {{ item.0 }}"
|
||||
set_fact:
|
||||
cmd_template:
|
||||
|
@ -45,6 +41,7 @@
|
|||
argv: "{{ cmd_template + item.1.command }}"
|
||||
|
||||
- name: "Manage container for {{ item.0 }}"
|
||||
when: item.1.action is not defined
|
||||
podman_container:
|
||||
cap_add: "{{ item.1.cap_add | default(omit) }}"
|
||||
cap_drop: "{{ item.1.cap_drop | default(omit) }}"
|
||||
|
@ -89,8 +86,7 @@
|
|||
uts: "{{ item.1.uts | default(omit) }}"
|
||||
volume: "{{ item.1.volumes | default(omit) }}"
|
||||
volumes_from: "{{ item.1.volumes_from | default([]) }}"
|
||||
when:
|
||||
- item.1.action is not defined
|
||||
register: podman_container
|
||||
|
||||
- name: Manage systemd service for {{ item.0 }}
|
||||
when:
|
||||
|
@ -132,7 +128,7 @@
|
|||
enabled: true
|
||||
daemon_reload: true
|
||||
when:
|
||||
- systemd_file.changed
|
||||
- systemd_file.changed or podman_container.changed
|
||||
- name: "Manage systemd healthcheck for {{ item.0 }}"
|
||||
when:
|
||||
- not tripleo_container_manage_healthcheck_disabled
|
|
@ -0,0 +1,77 @@
|
|||
---
|
||||
# Copyright 2019 Red Hat, Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This playbook is a "best effort" way to remove a container from a host.
|
||||
# It'll try to remove the healthcheck, service and then container without
|
||||
# much validation in case things failed in the middle.
|
||||
|
||||
- name: "Remove systemd healthcheck for {{ item }}"
|
||||
block:
|
||||
- name: "Stop and disable systemd timer for {{ item }}"
|
||||
systemd:
|
||||
state: stopped
|
||||
name: "tripleo_{{ item }}_healthcheck.timer"
|
||||
enabled: false
|
||||
ignore_errors: true
|
||||
- name: "Delete systemd timer file for {{ item }}"
|
||||
file:
|
||||
path: "/etc/systemd/system/tripleo_{{ item }}_healthcheck.timer"
|
||||
state: absent
|
||||
register: systemd_timer_deleted
|
||||
- name: "Stop and disable systemd healthcheck for {{ item }}"
|
||||
systemd:
|
||||
state: stopped
|
||||
name: "tripleo_{{ item }}_healthcheck.service"
|
||||
enabled: false
|
||||
ignore_errors: true
|
||||
- name: "Delete systemd healthcheck file for {{ item }}"
|
||||
file:
|
||||
path: "/etc/systemd/system/tripleo_{{ item }}_healthcheck.service"
|
||||
state: absent
|
||||
register: systemd_healthcheck_deleted
|
||||
- name: Force systemd to reread configs
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
when: systemd_timer_deleted.changed or systemd_healthcheck_deleted.changed
|
||||
|
||||
- name: "Stop and disable systemd service for {{ item }}"
|
||||
systemd:
|
||||
state: stopped
|
||||
name: "tripleo_{{ item }}.service"
|
||||
enabled: false
|
||||
ignore_errors: true
|
||||
|
||||
- name: "Delete systemd unit file for {{ item }}"
|
||||
file:
|
||||
path: "/etc/systemd/system/tripleo_{{ item }}.service"
|
||||
state: absent
|
||||
register: systemd_file_deleted
|
||||
|
||||
- name: "Remove trailing .requires for {{ item }}"
|
||||
file:
|
||||
path: "/etc/systemd/system/tripleo_{{ item }}.requires"
|
||||
state: absent
|
||||
register: systemd_requires_deleted
|
||||
|
||||
- name: Force systemd to reread configs
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
when: systemd_file_deleted.changed or systemd_requires_deleted.changed
|
||||
|
||||
- name: "Remove container {{ item }}"
|
||||
podman_container:
|
||||
name: "{{ item }}"
|
||||
state: absent
|
|
@ -32,6 +32,10 @@
|
|||
tags:
|
||||
- always
|
||||
|
||||
- name: Gather podman infos
|
||||
podman_container_info: {}
|
||||
register: podman_containers
|
||||
|
||||
- name: Create container logs path
|
||||
file:
|
||||
path: "{{ tripleo_container_manage_log_path }}"
|
||||
|
@ -72,6 +76,9 @@
|
|||
- tripleo_container_manage_cli == 'podman'
|
||||
become: true
|
||||
block:
|
||||
- name: "Manage Podman containers in {{ tripleo_container_manage_config }}"
|
||||
include_tasks: podman.yaml
|
||||
- name: "Cleanup Podman containers from {{ tripleo_container_manage_config }}"
|
||||
include_tasks: delete_podman.yaml
|
||||
loop: "{{ podman_containers.containers | needs_delete(config=all_containers_hash, config_id=tripleo_container_manage_config_id) }}"
|
||||
- name: "Create Podman containers from {{ tripleo_container_manage_config }}"
|
||||
include_tasks: create_podman.yaml
|
||||
loop: "{{ all_containers_hash | subsort(attribute='start_order', null_value=0) }}"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
[Unit]
|
||||
Description={{ item.0 }} healthcheck
|
||||
Description=tripleo_{{ item.0 }} healthcheck
|
||||
After=paunch-container-shutdown.service tripleo_{{ item.0 }}.service
|
||||
Requisite={{ item.0 }}.service
|
||||
Requisite=tripleo_{{ item.0 }}.service
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/bin/podman exec {{ item.0 }} {{ item.1.healthcheck.test }}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[Unit]
|
||||
Description={{ item.0 }} container healthcheck
|
||||
PartOf={{ item.0 }}.service
|
||||
Description=tripleo_{{ item.0 }} container healthcheck
|
||||
PartOf=tripleo_{{ item.0 }}.service
|
||||
[Timer]
|
||||
OnActiveSec=120
|
||||
OnUnitActiveSec={{ item.1.check_interval | default(60) }}
|
||||
|
|
Loading…
Reference in New Issue