[aio] Refactor loopback preparation

Current implementation of loopback preparation has quite significant
overhead, as we are calling exact same roles multiple times in order
to provision all required loopback devices. Moreover, we duplicate
code and logic needed for their provisionment, despite we have
pretty much 2 usecase - either add sparse file as LVM or format
and directly mount with systemd.

Proposed patch unifies approach by generating a variable with
required keys/parameters to create all required devices at once.

This should reduce overhead caused by multiple role imports/includes.
as each time role tries to install packages and verifies dependencies.

Change-Id: I419fdcfa2cfac5b636f817b1d6bdd82b7198e6be
Signed-off-by: Dmitriy Rabotyagov <dmitriy.rabotyagov@cleura.com>
This commit is contained in:
Dmitriy Rabotyagov
2025-06-30 19:31:59 +02:00
parent 0003b91035
commit 466df7ade3
13 changed files with 207 additions and 520 deletions

View File

@@ -95,23 +95,14 @@
when:
- "lookup('env', 'ZUUL_SRC_PATH') | length > 0"
# Prepare the swap space loopback disk
# This is only necessary if there isn't swap already
- name: Include prepare_loopback_swap
ansible.builtin.include_tasks: prepare_loopback_swap.yml
when:
- bootstrap_host_loopback_swap | bool
- ansible_facts['swaptotal_mb'] < 1
args:
apply:
tags:
- prepare-loopback
- name: Import prepare_loopback tasks
ansible.builtin.import_tasks: prepare_loopback.yml
tags:
- always
- prepare-loopback
# Prepare the zfs storage loopback disk
- name: Include prepare_loopback_zfs tasks
ansible.builtin.include_tasks: prepare_loopback_zfs.yml
- name: Include prepare_zfs tasks
ansible.builtin.include_tasks: prepare_zfs.yml
when:
- bootstrap_host_loopback_zfs | bool
- bootstrap_host_data_disk_device == None
@@ -123,81 +114,6 @@
tags:
- always
# Prepare the btrfs storage loopback disk
- name: Include prepare_loopback_btrfs tasks
ansible.builtin.include_tasks: prepare_loopback_btrfs.yml
when:
- bootstrap_host_loopback_btrfs | bool
- bootstrap_host_data_disk_device == None
- _lxc_container_backing_store == 'btrfs'
args:
apply:
tags:
- prepare-loopback
tags:
- always
# Prepare the Cinder LVM VG loopback disk
# This is only necessary if bootstrap_host_loopback_cinder is set to yes
- name: Include prepare_loopback_cinder tasks
ansible.builtin.include_tasks: prepare_loopback_cinder.yml
when:
- bootstrap_host_loopback_cinder | bool
args:
apply:
tags:
- prepare-loopback
tags:
- always
# Prepare the Nova instance storage loopback disk
- name: Include prepare_loopback_nova tasks
ansible.builtin.include_tasks: prepare_loopback_nova.yml
when:
- bootstrap_host_loopback_nova | bool
args:
apply:
tags:
- prepare-loopback
tags:
- always
# Prepare the Swift data storage loopback disks
- name: Include prepare_loopback_swift tasks
ansible.builtin.include_tasks: prepare_loopback_swift.yml
when:
- bootstrap_host_loopback_swift | bool
args:
apply:
tags:
- prepare-loopback
tags:
- always
# Prepare the Manila data storage loopback disks
- name: Include prepare_loopback_manila tasks
ansible.builtin.include_tasks: prepare_loopback_manila.yml
when:
- bootstrap_host_loopback_manila | bool
args:
apply:
tags:
- prepare-loopback
tags:
- always
# Prepare the Ceph cluster UUID and loopback disks
- name: Include prepare_ceph tasks
ansible.builtin.include_tasks: prepare_ceph.yml
when:
- bootstrap_host_ceph | bool
args:
apply:
tags:
- prepare-ceph
tags:
- always
# Prepare the NFS server and loopback disks
- name: Include prepare_nfs tasks
ansible.builtin.include_tasks: prepare_nfs.yml

View File

@@ -1,77 +0,0 @@
---
# Copyright 2016, Logan Vig <logan2211@gmail.com>
#
# 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: Create sparse ceph OSD files
ansible.builtin.command: truncate -s {{ bootstrap_host_loopback_ceph_size }}G /openstack/{{ item }}.img
args:
creates: "/openstack/{{ item }}.img"
with_items: "{{ ceph_osd_images }}"
register: ceph_create
tags:
- ceph-file-create
- name: Run the systemd service role
ansible.builtin.include_role:
name: systemd_service
vars:
systemd_services:
- service_name: "loop-{{ loopback_var }}"
config_overrides:
Unit:
Description: false
After: systemd-udev-settle.service
Service:
RemainAfterExit: true
service_type: oneshot
execstarts:
- /bin/bash -c "/sbin/losetup /dev/loop{{ 10 + loopback_index }} /openstack/{{ loopback_var }}.img"
execstops:
- /bin/bash -c "losetup -d /dev/loop{{ 10 + loopback_index }}"
enabled: true
state: started
systemd_tempd_prefix: openstack
with_items: "{{ ceph_osd_images }}"
loop_control:
loop_var: loopback_var
index_var: loopback_index
tags:
- ceph-config
- name: Set permissions on loopback devices
ansible.builtin.file:
path: "/dev/loop{{ 10 + loopback_index }}"
mode: "0777"
with_items: "{{ ceph_osd_images }}"
loop_control:
index_var: loopback_index
# NOTE(jrosser) ceph-volume is unwilling to automatically create OSD
# directly on loop devices - see http://tracker.ceph.com/issues/36603
# Work around this with manual LVM creation and the advanced lvm OSD
# scenario
- name: Create LVM VG
community.general.lvg:
vg: "vg-{{ item }}"
pvs: "/dev/loop{{ 10 + loopback_index }}"
loop: "{{ ceph_osd_images }}"
loop_control:
index_var: loopback_index
- name: Create LVM LV
community.general.lvol:
lv: "lv-{{ item }}"
vg: "vg-{{ item }}"
size: 100%FREE
loop: "{{ ceph_osd_images }}"

View File

@@ -108,23 +108,12 @@
options: "{{ bootstrap_host_data_mount_options[bootstrap_host_data_disk_fs_type] }}"
state: 'started'
enabled: true
tags:
- data-config
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts:
- what: "/dev/{{ _bootstrap_host_data_partition_devices[1] }}"
where: "{{ bootstrap_host_data_disk2_path }}"
type: "{{ bootstrap_host_data_disk2_fs }}"
options: "{{ bootstrap_host_data_disk2_fs_mount_options }}"
state: 'started'
enabled: true
when:
- _lxc_container_backing_store != 'lvm'
- _lxc_container_backing_store != 'zfs'
state: "{{ (_lxc_container_backing_store != 'lvm' and _lxc_container_backing_store != 'zfs') | ternary('started', 'stopped') }}"
enabled: "{{ (_lxc_container_backing_store != 'lvm' and _lxc_container_backing_store != 'zfs') | bool }}"
tags:
- data-config

View File

@@ -0,0 +1,82 @@
---
# Copyright 2025, Cleura AB.
#
# 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: Create sparse files
ansible.builtin.command: "truncate -s {{ item.size }}G {{ item.path }}"
loop: "{{ _loopback_device_data['sparse'] }}"
args:
creates: "{{ item.path }}"
tags:
- spare-file-create
- name: Format the file if needed
community.general.filesystem:
fstype: "{{ item['fstype'] | default(omit) }}"
opts: "{{ item['opts'] | default(omit) }}"
dev: "{{ item['path'] }}"
loop: "{{ _loopback_device_data['fs'] }}"
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts: "{{ _loopback_device_data['mounts'] }}"
- name: Run the systemd service role
ansible.builtin.include_role:
name: systemd_service
vars:
systemd_services: |-
{% set services = [] %}
{% for service in _loopback_device_data['services'] %}
{% set _ = services.append({
'service_name': service['name'],
'config_overrides': {
'Unit': {
'Description': false,
'After': 'systemd-udev-settle.service',
'Before': 'lvm2-activation-early.service',
'Wants': 'systemd-udev-settle.service',
},
'Service': {'RemainAfterExit': true},
},
'service_type': 'oneshot',
'execstarts': service['execstarts'],
'execstops': service['execstops'],
'enabled': true,
'state': 'started',
}) %}
{% endfor %}
{{ services }}
systemd_tempd_prefix: openstack
- name: Add LVM Volume Groups
community.general.lvg:
vg: "{{ item.vg }}"
pvs: "{{ item.pvs }}"
loop: "{{ _loopback_device_data['lvm'] }}"
tags:
- create-lvm-vg
- name: Create LVM Logical Volumes
community.general.lvol:
lv: "{{ item.lv }}"
vg: "{{ item.vg }}"
size: 100%VG
loop: "{{ _loopback_device_data['lvm'] }}"
when:
- "'lv' in item"
tags:
- create-lvm-lv

View File

@@ -1,39 +0,0 @@
---
# Copyright 2018, Rackspace US, Inc.
#
# 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: Create sparse lxc-btrfs file
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_btrfs_size }}G /openstack/lxc-btrfs.img"
args:
creates: /openstack/lxc-btrfs.img
- name: Format the lxc-btrfs file
community.general.filesystem:
fstype: btrfs
opts: "{{ bootstrap_host_format_options['btrfs'] | default(omit) }}"
dev: /openstack/lxc-btrfs.img
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts:
- what: "/openstack/lxc-btrfs.img"
where: "/var/lib/lxc"
options: "loop,{{ bootstrap_host_data_mount_options['btrfs'] }}"
type: "btrfs"
state: 'started'
enabled: true
tags:
- lxc-config

View File

@@ -1,55 +0,0 @@
---
# Copyright 2015, Rackspace US, Inc.
#
# 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: Create sparse Cinder file
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_cinder_size }}G /openstack/cinder.img"
args:
creates: /openstack/cinder.img
register: cinder_create
tags:
- cinder-file-create
- name: Run the systemd service role
ansible.builtin.include_role:
name: systemd_service
vars:
systemd_services:
- service_name: "loop-cinder"
config_overrides:
Unit:
Description: false
After: systemd-udev-settle.service
Before: lvm2-activation-early.service
Wants: systemd-udev-settle.service
Service:
RemainAfterExit: true
service_type: oneshot
execstarts:
- /bin/bash -c "/sbin/losetup /dev/loop6 /openstack/cinder.img"
- /sbin/pvscan
execstops:
- /bin/bash -c "losetup -d /dev/loop6"
enabled: true
state: started
systemd_tempd_prefix: openstack
tags:
- cinder-config
- name: Add cinder-volumes volume group
community.general.lvg:
vg: cinder-volumes
pvs: /dev/loop6
tags:
- cinder-lvm-vg

View File

@@ -1,55 +0,0 @@
---
# Copyright 2015, Rackspace US, Inc.
#
# 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: Create sparse manila file
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_manila_size }}G /openstack/manila.img"
args:
creates: /openstack/manila.img
register: manila_create
tags:
- manila-file-create
- name: Run the systemd service role
ansible.builtin.include_role:
name: systemd_service
vars:
systemd_services:
- service_name: "loop-manila"
config_overrides:
Unit:
Description: false
After: systemd-udev-settle.service
Before: lvm2-activation-early.service
Wants: systemd-udev-settle.service
Service:
RemainAfterExit: true
service_type: oneshot
execstarts:
- /bin/bash -c "/sbin/losetup /dev/loop7 /openstack/manila.img"
- /sbin/pvscan
execstops:
- /bin/bash -c "losetup -d /dev/loop7"
enabled: true
state: started
systemd_tempd_prefix: openstack
tags:
- manila-config
- name: Add manila-shares volume group
community.general.lvg:
vg: manila-shares
pvs: /dev/loop7
tags:
- manila-lvm-vg

View File

@@ -1,43 +0,0 @@
---
# Copyright 2015, Rackspace US, Inc.
#
# 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: Create sparse Nova file
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_nova_size }}G /openstack/nova.img"
args:
creates: /openstack/nova.img
tags:
- nova-file-create
- name: Format the Nova file
community.general.filesystem:
fstype: xfs
dev: /openstack/nova.img
opts: "{{ bootstrap_host_format_options['xfs'] | default(omit) }}"
tags:
- nova-format-file
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts:
- what: "/openstack/nova.img"
where: "/var/lib/nova/instances"
options: "loop,{{ bootstrap_host_data_mount_options['xfs'] }}"
type: "xfs"
state: 'started'
enabled: true
tags:
- nova-config

View File

@@ -1,52 +0,0 @@
---
# Copyright 2015, Rackspace US, Inc.
#
# 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: Create swap file
ansible.builtin.command: "dd if=/dev/zero of=/openstack/swap.img bs=1M count={{ bootstrap_host_loopback_swap_size }}"
args:
creates: /openstack/swap.img
register: swap_create
tags:
- swap-file-create
- name: Format the swap file
ansible.builtin.command: mkswap /openstack/swap.img
when:
- swap_create is changed
tags:
- swap-format
- skip_ansible_lint
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts:
- what: "/openstack/swap.img"
priority: "0"
options: "{{ bootstrap_host_data_mount_options['swap'] }}"
type: "swap"
state: 'started'
enabled: true
tags:
- swap-config
- name: Set system swappiness
ansible.posix.sysctl:
name: vm.swappiness
value: 10
state: present
tags:
- swap-sysctl

View File

@@ -1,63 +0,0 @@
---
# Copyright 2015, Rackspace US, Inc.
#
# 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: Create sparse Swift files
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_swift_size }}G /openstack/{{ item }}.img"
args:
creates: "/openstack/{{ item }}.img"
with_items:
- 'swift1'
- 'swift2'
- 'swift3'
tags:
- swift-file-create
- name: Format the Swift files
community.general.filesystem:
fstype: xfs
opts: "{{ bootstrap_host_format_options['xfs'] | default(omit) }}"
dev: "/openstack/{{ item }}.img"
with_items:
- 'swift1'
- 'swift2'
- 'swift3'
tags:
- swift-format-file
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts:
- what: "/openstack/swift1.img"
where: "/srv/swift1.img"
options: "loop,{{ bootstrap_host_data_mount_options['xfs'] }}"
type: "xfs"
state: 'started'
enabled: true
- what: "/openstack/swift2.img"
where: "/srv/swift2.img"
options: "loop,{{ bootstrap_host_data_mount_options['xfs'] }}"
type: "xfs"
state: 'started'
enabled: true
- what: "/openstack/swift3.img"
where: "/srv/swift3.img"
options: "loop,{{ bootstrap_host_data_mount_options['xfs'] }}"
type: "xfs"
state: 'started'
enabled: true
tags:
- swift-config

View File

@@ -13,35 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
- name: Create sparse NFS volume
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_nfs_size }}G /openstack/nfs.img"
args:
creates: /openstack/nfs.img
tags:
- nfs-file-create
- name: Format the NFS file
community.general.filesystem:
fstype: xfs
dev: /openstack/nfs.img
opts: "{{ bootstrap_host_format_options['xfs'] | default(omit) }}"
tags:
- nfs-format-file
- name: Run the systemd mount role
ansible.builtin.include_role:
name: systemd_mount
vars:
systemd_mounts:
- what: "/openstack/nfs.img"
where: "/srv/nfs"
options: "loop,{{ bootstrap_host_data_mount_options['xfs'] }}"
type: "xfs"
state: 'started'
enabled: true
tags:
- nfs-config
- name: Install NFS packages
ansible.builtin.package:
name: "{{ nfs_package }}"

View File

@@ -21,11 +21,6 @@
tags:
- install-packages
- name: Create sparse ZFS backing file
ansible.builtin.command: "truncate -s {{ bootstrap_host_loopback_zfs_size }}G /openstack/lxc-zfs.img"
args:
creates: /openstack/lxc-zfs.img
- name: Create the ZFS pool
ansible.builtin.command: zpool create osa-test-pool /openstack/lxc-zfs.img
args:

View File

@@ -72,3 +72,121 @@ _neutron_plugin_driver: |-
{% set plugin = 'ml2.ovn' %}
{% endif %}
{{ plugin }}
_loopback_device_data: |-
{% set data = {'sparse': [], 'fs': [], 'mounts': [], 'services': [], 'lvm': []} %}
{% if bootstrap_host_loopback_nova | bool %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_nova_size, 'path': '/openstack/nova.img'}) %}
{% set _ = data['fs'].append({'fstype': 'xfs', 'opts': bootstrap_host_format_options['xfs'], 'path': '/openstack/nova.img'}) %}
{% set _ = data['mounts'].append({
'what': '/openstack/nova.img',
'where': '/var/lib/nova/instances',
'type': 'xfs',
'options': 'loop,' ~ bootstrap_host_data_mount_options['xfs'],
'enabled': true,
'state': 'started',
}) %}
{% endif %}
{% if bootstrap_host_loopback_cinder | bool %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_cinder_size, 'path': '/openstack/cinder.img'}) %}
{% set _ = data['services'].append({
'name': 'loop-cinder',
'execstarts': [
'/bin/bash -c "/sbin/losetup /dev/loop6 /openstack/cinder.img"',
'/sbin/pvscan'
],
'execstops': ['/bin/bash -c "losetup -d /dev/loop6"'],
}) %}
{% set _ = data['lvm'].append({
'vg': 'cinder-volumes',
'pvs': '/dev/loop6',
}) %}
{% endif %}
{% if bootstrap_host_loopback_manila | bool %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_manila_size, 'path': '/openstack/manila.img'}) %}
{% set _ = data['services'].append({
'name': 'loop-manila',
'execstarts': [
'/bin/bash -c "/sbin/losetup /dev/loop7 /openstack/manila.img"',
'/sbin/pvscan'
],
'execstops': ['/bin/bash -c "losetup -d /dev/loop7"'],
}) %}
{% set _ = data['lvm'].append({
'vg': 'manila-shares',
'pvs': '/dev/loop7',
}) %}
{% endif %}
{% if bootstrap_host_ceph | bool %}
{% for image in ceph_osd_images %}
{% set device = '/dev/loop' ~ (10 + loop.index) %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_ceph_size, 'path': '/openstack/' ~ image ~ '.img'}) %}
{% set _ = data['services'].append({
'name': 'loop-' ~ image,
'execstarts': [
'/bin/bash -c "/sbin/losetup '~ device ~' /openstack/' ~ image ~ '.img"',
'/sbin/pvscan'
],
'execstops': ['/bin/bash -c "losetup -d ' ~ device ~ '"']
}) %}
{% set _ = data['lvm'].append({
'lv': 'lv-' ~ image,
'vg': 'vg-' ~ image,
'pvs': device,
}) %}
{% endfor %}
{% endif %}
{% if bootstrap_host_loopback_swift | bool %}
{% for image in ['swift1', 'swift2', 'swift3'] %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_swift_size, 'path': '/openstack/' ~ image ~ '.img'}) %}
{% set _ = data['fs'].append({'fstype': 'xfs', 'opts': bootstrap_host_format_options['xfs'], 'path': '/openstack/' ~ image ~ '.img'}) %}
{% set _ = data['mounts'].append({
'what': '/openstack/' ~ image ~ '.img',
'where': '/srv/' ~ image ~ '.img',
'type': 'xfs',
'options': 'loop,' ~ bootstrap_host_data_mount_options['xfs'],
'enabled': true,
'state': 'started',
}) %}
{% endfor %}
{% endif %}
{% if bootstrap_host_loopback_btrfs | bool and bootstrap_host_data_disk_device == None and _lxc_container_backing_store == 'btrfs'%}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_btrfs_size, 'path': '/openstack/lxc-btrfs.img'}) %}
{% set _ = data['fs'].append({'fstype': 'btrfs', 'opts': bootstrap_host_format_options['btrfs'], 'path': '/openstack/lxc-btrfs.img'}) %}
{% set _ = data['mounts'].append({
'what': '/openstack/lxc-btrfs.img',
'where': '/var/lib/lxc',
'type': 'btrfs',
'options': 'loop,' ~ bootstrap_host_data_mount_options['btrfs'],
'enabled': true,
'state': 'started',
}) %}
{% endif %}
{% if bootstrap_host_loopback_btrfs | bool and bootstrap_host_data_disk_device == None and _lxc_container_backing_store == 'zfs'%}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_zfs_size, 'path': '/openstack/lxc-zfs.img'}) %}
{% endif %}
{% if bootstrap_host_nfs | bool %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_nfs_size, 'path': '/openstack/nfs.img'}) %}
{% set _ = data['fs'].append({'fstype': 'xfs', 'opts': bootstrap_host_format_options['xfs'], 'path': '/openstack/nfs.img'}) %}
{% set _ = data['mounts'].append({
'what': '/openstack/nfs.img',
'where': '/srv/nfs',
'type': 'xfs',
'options': 'loop,' ~ bootstrap_host_data_mount_options['xfs'],
'enabled': true,
'state': 'started',
}) %}
{% endif %}
{% if bootstrap_host_loopback_swap | bool and ansible_facts['swaptotal_mb'] < 1 %}
{% set _ = data['sparse'].append({'size': bootstrap_host_loopback_swap_size, 'path': '/openstack/swap.img'}) %}
{% set _ = data['fs'].append({'fstype': 'swap', 'path': '/openstack/swap.img'}) %}
{% set _ = data['mounts'].append({
'what': '/openstack/swap.img',
'priority': 0,
'type': 'swap',
'options': bootstrap_host_data_mount_options['swap'],
'enabled': true,
'state': 'started',
}) %}
{% endif %}
{{ data }}