tripleo-container-manage: introduce concurrency
Co-Authored-By: Alex Schultz <aschultz@redhat.com> Change-Id: I1e5e941558c492b050e4db542703e322707dbbbd
This commit is contained in:
parent
57411934b7
commit
2f8f0fc027
|
@ -31,19 +31,27 @@ class FilterModule(object):
|
||||||
def subsort(self, dict_to_sort, attribute, null_value=None):
|
def subsort(self, dict_to_sort, attribute, null_value=None):
|
||||||
"""Sort a hash from a sub-element.
|
"""Sort a hash from a sub-element.
|
||||||
|
|
||||||
This filter will return a sorted list of tuples from a dictionary
|
This filter will return an dictionary ordered by the attribute
|
||||||
using an attribute from within the hash. If the sort attribute is
|
part of each item.
|
||||||
undefined it will be set in the returned item as the defined
|
|
||||||
`null_value`. This makes it possible to sort all items equally.
|
|
||||||
"""
|
"""
|
||||||
for k, v in dict_to_sort.items():
|
for k, v in dict_to_sort.items():
|
||||||
if attribute not in v:
|
if attribute not in v:
|
||||||
dict_to_sort[k][attribute] = null_value
|
dict_to_sort[k][attribute] = null_value
|
||||||
|
|
||||||
return sorted(
|
data = {}
|
||||||
dict_to_sort.items(),
|
for d in dict_to_sort.items():
|
||||||
key=lambda x: x[1][attribute]
|
if d[1][attribute] not in data:
|
||||||
|
data[d[1][attribute]] = []
|
||||||
|
data[d[1][attribute]].append({d[0]: d[1]})
|
||||||
|
|
||||||
|
sorted_list = sorted(
|
||||||
|
data.items(),
|
||||||
|
key=lambda x: x[0]
|
||||||
)
|
)
|
||||||
|
ordered_dict = {}
|
||||||
|
for o, v in sorted_list:
|
||||||
|
ordered_dict[o] = v
|
||||||
|
return ordered_dict
|
||||||
|
|
||||||
def singledict(self, list_to_convert):
|
def singledict(self, list_to_convert):
|
||||||
"""Generate a single dictionary from a list of dictionaries.
|
"""Generate a single dictionary from a list of dictionaries.
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
# All variables within this role should have a prefix of "tripleo_container_manage"
|
# All variables within this role should have a prefix of "tripleo_container_manage"
|
||||||
tripleo_container_manage_cli: podman
|
tripleo_container_manage_cli: podman
|
||||||
|
tripleo_container_manage_concurrency: 1
|
||||||
tripleo_container_manage_config: "/var/lib/tripleo-config/"
|
tripleo_container_manage_config: "/var/lib/tripleo-config/"
|
||||||
tripleo_container_manage_config_id: tripleo
|
tripleo_container_manage_config_id: tripleo
|
||||||
tripleo_container_manage_config_patterns: 'hashed-*.json'
|
tripleo_container_manage_config_patterns: 'hashed-*.json'
|
||||||
|
|
|
@ -17,5 +17,5 @@
|
||||||
- name: "Create containers managed by Podman for {{ tripleo_container_manage_config }}"
|
- name: "Create containers managed by Podman for {{ tripleo_container_manage_config }}"
|
||||||
when:
|
when:
|
||||||
- tripleo_container_manage_cli == 'podman'
|
- tripleo_container_manage_cli == 'podman'
|
||||||
include_tasks: podman/create.yml
|
include: podman/start_order.yml order="{{ item.key }}" data="{{ item.value }}"
|
||||||
loop: "{{ all_containers_hash | subsort(attribute='start_order', null_value=0) }}"
|
loop: "{{ all_containers_hash | subsort(attribute='start_order', null_value=0) | dict2items | list }}"
|
||||||
|
|
|
@ -14,66 +14,71 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
- name: "Run execute task"
|
- name: Prepare container facts
|
||||||
|
set_fact:
|
||||||
|
container_name: "{{ batched_container_data.0.keys() | first }}"
|
||||||
|
container_data: "{{ batched_container_data.0[batched_container_data.0.keys()|first] }}"
|
||||||
|
|
||||||
|
- name: "{{ container_name }} : Run execute task"
|
||||||
include_tasks: exec.yml
|
include_tasks: exec.yml
|
||||||
when:
|
when:
|
||||||
- item.1.action is defined
|
- container_data.action is defined
|
||||||
- item.1.action == 'exec'
|
- container_data.action == 'exec'
|
||||||
|
|
||||||
- name: "Manage container for {{ item.0 }}"
|
- name: "{{ container_name }} : Manage container"
|
||||||
when: item.1.action is not defined
|
when: container_data.action is not defined
|
||||||
podman_container:
|
podman_container:
|
||||||
cap_add: "{{ item.1.cap_add | default(omit) }}"
|
cap_add: "{{ container_data.cap_add | default(omit) }}"
|
||||||
cap_drop: "{{ item.1.cap_drop | default(omit) }}"
|
cap_drop: "{{ container_data.cap_drop | default(omit) }}"
|
||||||
command: "{{ item.1.command | default(omit) }}"
|
command: "{{ container_data.command | default(omit) }}"
|
||||||
conmon_pidfile: "/var/run/{{ item.0 }}.pid"
|
conmon_pidfile: "/var/run/{{ container_name }}.pid"
|
||||||
cpu_shares: "{{ item.1.cpu_shares | default(omit) | int }}"
|
cpu_shares: "{{ container_data.cpu_shares | default(omit) | int }}"
|
||||||
# cpuset_cpus: "{{ item.1.cpuset_cpus | default(omit) }}"
|
# cpuset_cpus: "{{ container_data.cpuset_cpus | default(omit) }}"
|
||||||
detach: "{{ item.1.detach | default(true) }}"
|
detach: "{{ container_data.detach | default(true) }}"
|
||||||
env: "{{ item.1.environment if item.1.environment is defined and item.1.environment else {} }}"
|
env: "{{ container_data.environment if container_data.environment is defined and container_data.environment else {} }}"
|
||||||
env_file: "{{ item.1.env_file | default(omit) }}"
|
env_file: "{{ container_data.env_file | default(omit) }}"
|
||||||
etc_hosts: "{{ item.1.extra_hosts | default({}) }}"
|
etc_hosts: "{{ container_data.extra_hosts | default({}) }}"
|
||||||
group_add: "{{ item.1.group_add | default(omit) }}"
|
group_add: "{{ container_data.group_add | default(omit) }}"
|
||||||
hostname: "{{ item.1.hostname | default(omit) }}"
|
hostname: "{{ container_data.hostname | default(omit) }}"
|
||||||
image: "{{ item.1.image }}"
|
image: "{{ container_data.image }}"
|
||||||
interactive: "{{ item.1.interactive | default(false) }}"
|
interactive: "{{ container_data.interactive | default(false) }}"
|
||||||
ipc: "{{ item.1.ipc | default(omit) }}"
|
ipc: "{{ container_data.ipc | default(omit) }}"
|
||||||
label:
|
label:
|
||||||
config_id: "{{ tripleo_container_manage_config_id }}"
|
config_id: "{{ tripleo_container_manage_config_id }}"
|
||||||
container_name: "{{ item.0 }}"
|
container_name: "{{ container_name }}"
|
||||||
managed_by: tripleo_ansible
|
managed_by: tripleo_ansible
|
||||||
config_data: "{{ item.1 | to_json }}"
|
config_data: "{{ container_data | to_json }}"
|
||||||
log_driver: 'k8s-file'
|
log_driver: 'k8s-file'
|
||||||
# log_opt: |
|
# log_opt: |
|
||||||
# "{{ 'path=' if tripleo_container_manage_log_path is defined else '' }}
|
# "{{ 'path=' if tripleo_container_manage_log_path is defined else '' }}
|
||||||
# {{ tripleo_container_manage_log_path | default('') }}
|
# {{ tripleo_container_manage_log_path | default('') }}
|
||||||
# {{ '/' if tripleo_container_manage_log_path is defined else '' }}
|
# {{ '/' if tripleo_container_manage_log_path is defined else '' }}
|
||||||
# {{ item.0 if tripleo_container_manage_log_path is defined else '' }}"
|
# {{ container_data if tripleo_container_manage_log_path is defined else '' }}"
|
||||||
memory: "{{ item.1.mem_limit | default(omit) }}"
|
memory: "{{ container_data.mem_limit | default(omit) }}"
|
||||||
memory_swap: "{{ item.1.mem_swappiness | default(omit) }}"
|
memory_swap: "{{ container_data.mem_swappiness | default(omit) }}"
|
||||||
name: "{{ item.0 }}"
|
name: "{{ container_name }}"
|
||||||
net: "{{ item.1.net | default('none') }}"
|
net: "{{ container_data.net | default('none') }}"
|
||||||
pid: "{{ item.1.pid | default(omit) }}"
|
pid: "{{ container_data.pid | default(omit) }}"
|
||||||
privileged: "{{ item.1.privileged | default(false) }}"
|
privileged: "{{ container_data.privileged | default(false) }}"
|
||||||
rm: "{{ item.1.remove | default(false) }}"
|
rm: "{{ container_data.remove | default(false) }}"
|
||||||
security_opt: "{{ item.1.security_opt | default(omit) }}"
|
security_opt: "{{ container_data.security_opt | default(omit) }}"
|
||||||
state: present
|
state: present
|
||||||
stop_signal: "{{ item.1.stop_signal | default(omit) }}"
|
stop_signal: "{{ container_data.stop_signal | default(omit) }}"
|
||||||
stop_timeout: "{{ item.1.stop_grace_period | default(omit) | int }}"
|
stop_timeout: "{{ container_data.stop_grace_period | default(omit) | int }}"
|
||||||
tty: "{{ item.1.tty | default(false) }}"
|
tty: "{{ container_data.tty | default(false) }}"
|
||||||
ulimit: "{{ item.1.ulimit | default(omit) }}"
|
ulimit: "{{ container_data.ulimit | default(omit) }}"
|
||||||
user: "{{ item.1.user | default(omit) }}"
|
user: "{{ container_data.user | default(omit) }}"
|
||||||
uts: "{{ item.1.uts | default(omit) }}"
|
uts: "{{ container_data.uts | default(omit) }}"
|
||||||
volume: "{{ item.1.volumes | default(omit) }}"
|
volume: "{{ container_data.volumes | default(omit) }}"
|
||||||
volumes_from: "{{ item.1.volumes_from | default([]) }}"
|
volumes_from: "{{ container_data.volumes_from | default([]) }}"
|
||||||
register: podman_container
|
register: podman_container
|
||||||
|
|
||||||
- name: Manage systemd service for {{ item.0 }}
|
- name: "{{ container_name }} : Manage systemd service }}"
|
||||||
include_tasks: systemd.yml
|
include_tasks: systemd.yml
|
||||||
when:
|
when:
|
||||||
- item.1.action is not defined
|
- container_data.action is not defined
|
||||||
- item.1.restart is defined
|
- container_data.restart is defined
|
||||||
# systemd doesn't have the equivalent of docker unless-stopped.
|
# systemd doesn't have the equivalent of docker unless-stopped.
|
||||||
# Let's force 'always' so containers aren't restarted when stopped by
|
# Let's force 'always' so containers aren't restarted when stopped by
|
||||||
# systemd, but restarted when in failure.
|
# systemd, but restarted when in failure.
|
||||||
- item.1.restart == 'always' or item.1.restart == 'unless-stopped'
|
- container_data.restart == 'always' or container_data.restart == 'unless-stopped'
|
||||||
|
|
|
@ -14,23 +14,23 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
- name: "Execute a command within a running container for {{ item.0 }}"
|
- name: "Execute a command within a running container for {{ container_name }}"
|
||||||
check_mode: false
|
check_mode: false
|
||||||
block:
|
block:
|
||||||
- name: "Check if {{ item.1.command.0 }} container is running"
|
- name: "Check if {{ container_data.command.0 }} container is running"
|
||||||
block:
|
block:
|
||||||
- name: "Fail if {{ item.1.command.0 }} is not running"
|
- name: "Fail if {{ container_data.command.0 }} is not running"
|
||||||
fail:
|
fail:
|
||||||
msg: "Can't run container exec for {{ item.0 }}, {{ item.1.command.0 }} is not running"
|
msg: "Can't run container exec for {{ container_name }}, {{ container_data.command.0 }} is not running"
|
||||||
when:
|
when:
|
||||||
- not podman_containers.containers.0.State.Running
|
- not podman_containers.containers.0.State.Running
|
||||||
- name: "Prepare the exec command for {{ item.0 }}"
|
- name: "Prepare the exec command for {{ container_name }}"
|
||||||
set_fact:
|
set_fact:
|
||||||
cmd_template:
|
cmd_template:
|
||||||
- "{{ tripleo_container_manage_cli }}"
|
- "{{ tripleo_container_manage_cli }}"
|
||||||
- "exec"
|
- "exec"
|
||||||
- "-u"
|
- "-u"
|
||||||
- "{{ item.1.user if item.1.user is defined else 'root' }}"
|
- "{{ container_data.user if container_data.user is defined else 'root' }}"
|
||||||
- name: "Run the container exec for {{ item.0 }}"
|
- name: "Run the container exec for {{ container_name }}"
|
||||||
command:
|
command:
|
||||||
argv: "{{ cmd_template + item.1.command }}"
|
argv: "{{ cmd_template + container_data.command }}"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
- name: "Batching items for start_order {{ order }}"
|
||||||
|
include_tasks: podman/create.yml
|
||||||
|
loop: "{{ data | batch(tripleo_container_manage_concurrency) | list }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: batched_container_data
|
|
@ -22,55 +22,55 @@
|
||||||
podman_drop_in: true
|
podman_drop_in: true
|
||||||
when:
|
when:
|
||||||
- podman_drop_in.stat.exists
|
- podman_drop_in.stat.exists
|
||||||
- name: "Start systemd service for {{ item.0 }}"
|
- name: "Start systemd service for {{ container_name }}"
|
||||||
block:
|
block:
|
||||||
- name: "Remove trailing .requires for {{ item.0 }}"
|
- name: "Remove trailing .requires for {{ container_name }}"
|
||||||
file:
|
file:
|
||||||
path: "/etc/systemd/system/tripleo_{{ item.0 }}.requires"
|
path: "/etc/systemd/system/tripleo_{{ container_name }}.requires"
|
||||||
state: absent
|
state: absent
|
||||||
- name: "Create systemd unit file for {{ item.0 }} service"
|
- name: "Create systemd unit file for {{ container_name }} service"
|
||||||
template:
|
template:
|
||||||
src: systemd-service.j2
|
src: systemd-service.j2
|
||||||
dest: "/etc/systemd/system/tripleo_{{ item.0 }}.service"
|
dest: "/etc/systemd/system/tripleo_{{ container_name }}.service"
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
register: systemd_file
|
register: systemd_file
|
||||||
- name: "Enable and start systemd service for {{ item.0 }}"
|
- name: "Enable and start systemd service for {{ container_name }}"
|
||||||
systemd:
|
systemd:
|
||||||
# Restart the service if it was already running
|
# Restart the service if it was already running
|
||||||
state: restarted
|
state: restarted
|
||||||
name: "tripleo_{{ item.0 }}.service"
|
name: "tripleo_{{ container_name }}.service"
|
||||||
enabled: true
|
enabled: true
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
when:
|
when:
|
||||||
- systemd_file.changed or podman_container.changed
|
- systemd_file.changed or podman_container.changed
|
||||||
- name: "Manage systemd healthcheck for {{ item.0 }}"
|
- name: "Manage systemd healthcheck for {{ container_name }}"
|
||||||
when:
|
when:
|
||||||
- not tripleo_container_manage_healthcheck_disabled
|
- not tripleo_container_manage_healthcheck_disabled
|
||||||
- item.1.healthcheck is defined
|
- container_data.healthcheck is defined
|
||||||
block:
|
block:
|
||||||
- name: "Create systemd unit file for {{ item.0 }} healthcheck"
|
- name: "Create systemd unit file for {{ container_name }} healthcheck"
|
||||||
template:
|
template:
|
||||||
src: systemd-healthcheck.j2
|
src: systemd-healthcheck.j2
|
||||||
dest: "/etc/systemd/system/tripleo_{{ item.0 }}_healthcheck.service"
|
dest: "/etc/systemd/system/tripleo_{{ container_name }}_healthcheck.service"
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
register: systemd_healthcheck
|
register: systemd_healthcheck
|
||||||
- name: "Create systemd timer for {{ item.0 }} healthcheck"
|
- name: "Create systemd timer for {{ container_name }} healthcheck"
|
||||||
template:
|
template:
|
||||||
src: systemd-timer.j2
|
src: systemd-timer.j2
|
||||||
dest: "/etc/systemd/system/tripleo_{{ item.0 }}_healthcheck.timer"
|
dest: "/etc/systemd/system/tripleo_{{ container_name }}_healthcheck.timer"
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
register: systemd_timer
|
register: systemd_timer
|
||||||
- name: "Enable and start systemd timer for {{ item.0 }}"
|
- name: "Enable and start systemd timer for {{ container_name }}"
|
||||||
systemd:
|
systemd:
|
||||||
# Restart the timer if it was already running
|
# Restart the timer if it was already running
|
||||||
state: restarted
|
state: restarted
|
||||||
name: "tripleo_{{ item.0 }}_healthcheck.timer"
|
name: "tripleo_{{ container_name }}_healthcheck.timer"
|
||||||
enabled: true
|
enabled: true
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=tripleo_{{ item.0 }} healthcheck
|
Description=tripleo_{{ container_name }} healthcheck
|
||||||
After=paunch-container-shutdown.service tripleo_{{ item.0 }}.service
|
After=paunch-container-shutdown.service tripleo_{{ container_name }}.service
|
||||||
Requisite=tripleo_{{ item.0 }}.service
|
Requisite=tripleo_{{ container_name }}.service
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart=/usr/bin/podman exec {{ item.0 }} {{ item.1.healthcheck.test }}
|
ExecStart=/usr/bin/podman exec {{ container_name }} {{ container_data.healthcheck.test }}
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description={{ item.0 }} container
|
Description={{ container_name }} container
|
||||||
After=paunch-container-shutdown.service
|
After=paunch-container-shutdown.service
|
||||||
Wants={{ item.1.depends_on | default([]) | join(',') }}
|
Wants={{ container_data.depends_on | default([]) | join(',') }}
|
||||||
[Service]
|
[Service]
|
||||||
Restart=always
|
Restart=always
|
||||||
{% if item.1.depends_on is defined and (item.1.depends_on | length > 0) and podman_drop_in | default('false') %}
|
{% if container_data.depends_on is defined and (container_data.depends_on | length > 0) and podman_drop_in | default('false') %}
|
||||||
ExecStart=/usr/libexec/paunch-start-podman-container {{ item.0 }}
|
ExecStart=/usr/libexec/paunch-start-podman-container {{ container_name }}
|
||||||
{% else %}
|
{% else %}
|
||||||
ExecStart=/usr/bin/podman start {{ item.0 }}
|
ExecStart=/usr/bin/podman start {{ container_name }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
ExecStop=/usr/bin/podman stop -t {{ item.1.stop_grace_period | default(10) | int }} {{ item.0 }}
|
ExecStop=/usr/bin/podman stop -t {{ container_data.stop_grace_period | default(10) | int }} {{ container_name }}
|
||||||
KillMode=none
|
KillMode=none
|
||||||
Type=forking
|
Type=forking
|
||||||
PIDFile=/var/run/{{ item.0 }}.pid
|
PIDFile=/var/run/{{ container_name }}.pid
|
||||||
{% if item.1.systemd_exec_flags is defined %}
|
{% if container_data.systemd_exec_flags is defined %}
|
||||||
{% for s_flag, s_value in item.1.systemd_exec_flags.items() %}
|
{% for s_flag, s_value in container_data.systemd_exec_flags.items() %}
|
||||||
{{ s_flag }}={{ s_value }}
|
{{ s_flag }}={{ s_value }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=tripleo_{{ item.0 }} container healthcheck
|
Description=tripleo_{{ container_name }} container healthcheck
|
||||||
PartOf=tripleo_{{ item.0 }}.service
|
PartOf=tripleo_{{ container_name }}.service
|
||||||
[Timer]
|
[Timer]
|
||||||
OnActiveSec=120
|
OnActiveSec=120
|
||||||
OnUnitActiveSec={{ item.1.check_interval | default(60) }}
|
OnUnitActiveSec={{ container_data.check_interval | default(60) }}
|
||||||
RandomizedDelaySec={{ 45 if item.1.check_interval is not defined else (item.1.check_interval * 3 / 4) | int | abs }}
|
RandomizedDelaySec={{ 45 if container_data.check_interval is not defined else (container_data.check_interval * 3 / 4) | int | abs }}
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=timers.target
|
WantedBy=timers.target
|
||||||
|
|
Loading…
Reference in New Issue