Rolle aktualisiert: bootstrap (#457)

Co-authored-by: Michael Grote <michael.grote@posteo.de>
Reviewed-on: #457
This commit is contained in:
Michael Grote 2023-02-17 12:06:35 +01:00
parent 3cc377c1a7
commit 686a0b281f
25 changed files with 201 additions and 210 deletions

View file

@ -1,8 +1,14 @@
---
#
# Ansible managed
#
exclude_paths:
- ./meta/exception.yml
- ./meta/preferences.yml
- ./molecule/default/prepare.yml
- ./molecule/default/converge.yml
- ./molecule/default/verify.yml
- ./molecule/default/collections.yml
- ./.tox
- ./.cache
- ./.github
- ./requirements.yml

View file

@ -5,6 +5,7 @@ about: Create a report to help me improve
---
## Describe the bug
A clear and concise description of what the bug is.
## Playbook

View file

@ -13,6 +13,6 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: galaxy
uses: robertdebock/galaxy-action@1.1.0
uses: robertdebock/galaxy-action@1.2.0
with:
galaxy_api_key: ${{ secrets.galaxy_api_key }}

View file

@ -11,20 +11,16 @@ on:
- '*'
pull_request:
schedule:
- cron: '2 2 2 * *'
- cron: '3 2 2 * *'
jobs:
lint:
runs-on: ubuntu-20.04
steps:
- name: checkout
uses: actions/checkout@v2
with:
path: "${{ github.repository }}"
- name: molecule
uses: robertdebock/molecule-action@2.6.8
with:
command: lint
uses: actions/checkout@v3
- name: ansible-lint
uses: ansible-community/ansible-lint-action@main
test:
needs:
- lint
@ -33,18 +29,22 @@ jobs:
fail-fast: false
matrix:
config:
- image: "alpine"
tag: "latest"
- image: "amazonlinux"
tag: "latest"
- image: "centos"
- image: "enterpriselinux"
tag: "7"
- image: "centos"
- image: "enterpriselinux"
tag: "8"
- image: "enterpriselinux"
tag: "latest"
- image: "debian"
tag: "latest"
- image: "debian"
tag: "bullseye"
tag: "bookworm"
- image: "fedora"
tag: "32"
tag: "36"
- image: "fedora"
tag: "latest"
- image: "fedora"
@ -53,11 +53,13 @@ jobs:
tag: "latest"
- image: "ubuntu"
tag: "latest"
- image: "ubuntu"
tag: "focal"
- image: "ubuntu"
tag: "bionic"
steps:
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
path: "${{ github.repository }}"
- name: disable apparmor for mysql
@ -65,7 +67,7 @@ jobs:
- name: parse apparmor for mysql
run: sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
- name: molecule
uses: robertdebock/molecule-action@2.6.8
uses: robertdebock/molecule-action@5.0.0
with:
image: ${{ matrix.config.image }}
tag: ${{ matrix.config.tag }}

View file

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
path: ${{ github.repository }}
- name: create png

View file

@ -2,3 +2,5 @@
*.log
*.swp
.tox
.cache
.DS_Store

View file

@ -1,33 +1,33 @@
---
image: robertdebock/github-action-molecule:2.6.6
services:
- docker:dind
image: "robertdebock/github-action-molecule:5.0.0"
variables:
DOCKER_HOST: "tcp://docker:2375"
PY_COLORS: 1
molecule:
script:
- image=${image} tag=${tag} molecule test
- if [ -f tox.ini ] ; then tox ; fi
- if [ ! -f tox.ini ] ; then molecule test ; fi
rules:
- if: $CI_COMMIT_REF_NAME == "master"
retry: 2
parallel:
matrix:
- image: "alpine"
tag: "latest"
- image: "amazonlinux"
tag: "latest"
- image: "centos"
- image: "enterpriselinux"
tag: "7"
- image: "centos"
- image: "enterpriselinux"
tag: "8"
- image: "enterpriselinux"
tag: "latest"
- image: "debian"
tag: "latest"
- image: "debian"
tag: "bullseye"
tag: "bookworm"
- image: "fedora"
tag: "32"
tag: "36"
- image: "fedora"
tag: "latest"
- image: "fedora"
@ -36,11 +36,13 @@ molecule:
tag: "latest"
- image: "ubuntu"
tag: "latest"
- image: "ubuntu"
tag: "focal"
- image: "ubuntu"
tag: "bionic"
galaxy:
script:
- ansible-galaxy role import --api-key ${GALAXY_API_KEY} ${CI_PROJECT_NAMESPACE} ${CI_PROJECT_NAME}
- ansible-galaxy role import --api-key ${GALAXY_API_KEY} robertdebock ${CI_PROJECT_NAME}
rules:
- if: $CI_COMMIT_TAG != null

View file

@ -1,26 +1,24 @@
---
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
- repo: https://github.com/adrienverge/yamllint
rev: v1.25.0
rev: v1.26.3
hooks:
- id: yamllint
args: [-c=.yamllint]
- repo: https://github.com/ansible/ansible-lint
rev: v4.3.7
hooks:
- id: ansible-lint
pass_filenames: false
- repo: https://github.com/robertdebock/pre-commit
rev: v1.1.2
rev: v1.5.2
hooks:
- id: ansible_role_find_unused_variable
- id: ansible_role_find_empty_files
- id: ansible_role_find_empty_directories
- id: ansible_role_find_undefined_handlers
- id: ansible_role_find_unquoted_values
- id: ansible_role_find_horizontal_when

View file

@ -1,30 +0,0 @@
---
#
# Ansible managed
#
language: python
os: linux
dist: xenial
python:
- "3.9"
services:
- docker
cache:
- pip
install:
- pip install --upgrade pip
- pip install yamllint
- pip install ansible-lint
script:
- yamllint .
- ansible-lint
notifications:
webhooks: https://galaxy.ansible.com/api/v1/notifications/
email: false

View file

@ -13,3 +13,4 @@ rules:
ignore: |
.tox/
.cache/

View file

@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2021 Robert de Bock (robert@meinit.nl)
Copyright 2023 Robert de Bock (robert@meinit.nl)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View file

@ -4,16 +4,24 @@ Prepare your system to be managed by Ansible.
|GitHub|GitLab|Quality|Downloads|Version|
|------|------|-------|---------|-------|
|[![github](https://github.com/robertdebock/ansible-role-bootstrap/workflows/Ansible%20Molecule/badge.svg)](https://github.com/robertdebock/ansible-role-bootstrap/actions)|[![gitlab](https://gitlab.com/robertdebock/ansible-role-bootstrap/badges/master/pipeline.svg)](https://gitlab.com/robertdebock/ansible-role-bootstrap)|[![quality](https://img.shields.io/ansible/quality/21642)](https://galaxy.ansible.com/robertdebock/bootstrap)|[![downloads](https://img.shields.io/ansible/role/d/21642)](https://galaxy.ansible.com/robertdebock/bootstrap)|[![Version](https://img.shields.io/github/release/robertdebock/ansible-role-bootstrap.svg)](https://github.com/robertdebock/ansible-role-bootstrap/releases/)|
|[![github](https://github.com/robertdebock/ansible-role-bootstrap/workflows/Ansible%20Molecule/badge.svg)](https://github.com/robertdebock/ansible-role-bootstrap/actions)|[![gitlab](https://gitlab.com/robertdebock-iac/ansible-role-bootstrap/badges/master/pipeline.svg)](https://gitlab.com/robertdebock-iac/ansible-role-bootstrap)|[![quality](https://img.shields.io/ansible/quality/21642)](https://galaxy.ansible.com/robertdebock/bootstrap)|[![downloads](https://img.shields.io/ansible/role/d/21642)](https://galaxy.ansible.com/robertdebock/bootstrap)|[![Version](https://img.shields.io/github/release/robertdebock/ansible-role-bootstrap.svg)](https://github.com/robertdebock/ansible-role-bootstrap/releases/)|
## [Example Playbook](#example-playbook)
This example is taken from `molecule/resources/converge.yml` and is tested on each push, pull request and release.
This example is taken from [`molecule/default/converge.yml`](https://github.com/robertdebock/ansible-role-bootstrap/blob/master/molecule/default/converge.yml) and is tested on each push, pull request and release.
```yaml
---
- name: Converge
hosts: all
become: yes
# This role installs packages using the `raw` module and needs to connect as
# `root`. (`sudo` is not available before bootstrapping.) All tasks in the
# role have `become` set to `no`, so you can use either `no` or `yes` for
# `become`, the role will not use become (so `sudo`) for any task.
become: yes # `no` will also work.
# This role installs python, gathering facts can't be done before `python` is
# installed. This role runs the `setup` module, so facts will be available
# after running the role.
gather_facts: no
roles:
@ -24,19 +32,20 @@ Also see a [full explanation and example](https://robertdebock.nl/how-to-use-the
## [Role Variables](#role-variables)
These variables are set in `defaults/main.yml`:
The default values for the variables are set in [`defaults/main.yml`](https://github.com/robertdebock/ansible-role-bootstrap/blob/master/defaults/main.yml):
```yaml
---
# defaults file for bootstrap
# The user to use to connect to machines.
bootstrap_user: root
# Do you want to wait for the host to be available?
bootstrap_wait_for_host: no
# The number of seconds you want to wait during connection test before failing.
bootstrap_timeout: 3
# Tell the role to "become" or not.
bootstrap_become: yes
```
## [Requirements](#requirements)
@ -57,12 +66,13 @@ This role has been tested on these [container images](https://hub.docker.com/u/r
|container|tags|
|---------|----|
|amazon|Candidate|
|el|7, 8|
|debian|all|
|fedora|all|
|opensuse|all|
|ubuntu|focal, bionic|
|[Alpine](https://hub.docker.com/repository/docker/robertdebock/alpine/general)|all|
|[Amazon](https://hub.docker.com/repository/docker/robertdebock/amazonlinux/general)|Candidate|
|[EL](https://hub.docker.com/repository/docker/robertdebock/enterpriselinux/general)|all|
|[Debian](https://hub.docker.com/repository/docker/robertdebock/debian/general)|all|
|[Fedora](https://hub.docker.com/repository/docker/robertdebock/fedora/general)|all|
|[opensuse](https://hub.docker.com/repository/docker/robertdebock/opensuse/general)|all|
|[Ubuntu](https://hub.docker.com/repository/docker/robertdebock/ubuntu/general)|all|
The minimum version of Ansible required is 2.10, tests have been done to:
@ -70,34 +80,14 @@ The minimum version of Ansible required is 2.10, tests have been done to:
- The current version.
- The development version.
## [Exceptions](#exceptions)
Some variarations of the build matrix do not work. These are the variations and reasons why the build won't work:
| variation | reason |
|---------------------------|------------------------|
| alpine:edge | Failed to create temporary directory. |
If you find issues, please register them in [GitHub](https://github.com/robertdebock/ansible-role-bootstrap/issues)
## [License](#license)
Apache-2.0
## [Contributors](#contributors)
I'd like to thank everybody that made contributions to this repository. It motivates me, improves the code and is just fun to collaborate.
- [rembik](https://github.com/rembik)
- [jellevandehaterd](https://github.com/jellevandehaterd)
- [fzarifian](https://github.com/fzarifian)
- [kmonticolo](https://github.com/kmonticolo)
- [CrystalStiletto](https://github.com/CrystalStiletto)
- [infothrill](https://github.com/infothrill)
[Apache-2.0](https://github.com/robertdebock/ansible-role-bootstrap/blob/master/LICENSE).
## [Author Information](#author-information)
[Robert de Bock](https://robertdebock.nl/)
[robertdebock](https://robertdebock.nl/)
Please consider [sponsoring me](https://github.com/sponsors/robertdebock).

View file

@ -1,11 +1,11 @@
---
# defaults file for bootstrap
# The user to use to connect to machines.
bootstrap_user: root
# Do you want to wait for the host to be available?
bootstrap_wait_for_host: no
# The number of seconds you want to wait during connection test before failing.
bootstrap_timeout: 3
# Tell the role to "become" or not.
bootstrap_become: yes

View file

@ -0,0 +1,18 @@
---
argument_specs:
main:
short_description: "Prepare a system to be managed by Ansible."
description: >
Install the minimum required set of packages (python and sudo) to allow Ansible to manage a system.
This role tries to figure out what to install and uses the raw module to install the packages.
author: Robert de Bock
options:
bootstrap_wait_for_host:
type: "bool"
default: no
description: "Wait for the machine to be available."
bootstrap_timeout:
type: "int"
default: 3
description: "Time (in seconds) to wait for connection."

View file

@ -1,4 +0,0 @@
---
exceptions:
- variation: alpine:edge
reason: "Failed to create temporary directory."

View file

@ -1,6 +1,6 @@
---
galaxy_info:
author: Robert de Bock
author: robertdebock
role_name: bootstrap
description: Prepare your system to be managed by Ansible.
license: Apache-2.0
@ -8,30 +8,27 @@ galaxy_info:
min_ansible_version: "2.10"
platforms:
# Broken: idempotence, gather_facts: Failed to create temporary directory.
# - name: Alpine
# versions:
# - all
- name: Alpine
versions:
- all
- name: Amazon
versions:
- Candidate
- name: EL
versions:
- 7
- 8
- all
- name: Debian
versions:
- all
- name: Fedora
versions:
- all
- name: OpenSUSE
- name: opensuse
versions:
- all
- name: Ubuntu
versions:
- focal
- bionic
- all
galaxy_tags:
- bootstrap

View file

@ -1,7 +1,14 @@
---
- name: Converge
hosts: all
become: yes
# This role installs packages using the `raw` module and needs to connect as
# `root`. (`sudo` is not available before bootstrapping.) All tasks in the
# role have `become` set to `no`, so you can use either `no` or `yes` for
# `become`, the role will not use become (so `sudo`) for any task.
become: yes # `no` will also work.
# This role installs python, gathering facts can't be done before `python` is
# installed. This role runs the `setup` module, so facts will be available
# after running the role.
gather_facts: no
roles:

View file

@ -6,6 +6,7 @@ dependency:
name: galaxy
options:
role-file: requirements.yml
requirements-file: requirements.yml
lint: |
set -e
yamllint .
@ -22,9 +23,5 @@ platforms:
pre_build_image: yes
provisioner:
name: ansible
config_options:
defaults:
stdout_callback: yaml
bin_ansible_callbacks: yes
verifier:
name: ansible

View file

@ -6,9 +6,9 @@
tasks:
- name: test connection
ping:
ansible.builtin.ping:
- name: try the package module
package:
ansible.builtin.package:
name: gzip
state: present

View file

@ -0,0 +1,2 @@
---
collections:

View file

@ -1,23 +1,23 @@
---
- name: test if bootstrap_user is set correctly
assert:
that:
- bootstrap_user is defined
- bootstrap_user is string
quiet: yes
- name: test if bootstrap_wait_for_host is set correctly
assert:
- name: Test if bootstrap_wait_for_host is set correctly
ansible.builtin.assert:
that:
- bootstrap_wait_for_host is defined
- bootstrap_wait_for_host is boolean
quiet: yes
- name: test if bootstrap_timeout is set correctly
assert:
- name: Test if bootstrap_timeout is set correctly
ansible.builtin.assert:
that:
- bootstrap_timeout is defined
- bootstrap_timeout is number
- bootstrap_timeout >= 0
quiet: yes
- name: Test if bootstrap_become is set correctly
ansible.builtin.assert:
that:
- bootstrap_become is defined
- bootstrap_become is boolean
quiet: yes

View file

@ -1,29 +1,29 @@
---
- name: lookup bootstrap facts
- name: Lookup bootstrap facts
ansible.builtin.raw: "cat /etc/os-release"
become: no
raw: "cat /etc/os-release"
check_mode: no
register: bootstrap_facts
changed_when: no
vars:
ansible_user: "{{ bootstrap_user }}"
- name: set bootstrap facts (I)
set_fact:
- name: Set bootstrap facts (I)
ansible.builtin.set_fact:
bootstrap_distribution: "{{ item }}"
bootstrap_distribution_major_version: "{{ bootstrap_facts.stdout_lines | join(',') | regex_replace(
'^.*VERSION_ID=\"(\\d{1,2})(\\.\\d{1,4})*?\".*$','\\1') | default('NA') }}"
bootstrap_distribution_major_version: "{{ bootstrap_facts.stdout_lines | join(',') | regex_replace('^.*VERSION_ID=\"(\\d{1,2})(\\.\\d{1,4})*?\".*$', '\\1') | default('NA') }}"
loop: "{{ bootstrap_os_family_map | dict2items | map(attribute='value') | flatten }}"
when:
- bootstrap_facts.rc == 0
- bootstrap_distribution is not defined
- bootstrap_facts.stdout is regex('PRETTY_NAME=.'~ bootstrap_search[item] | default(item) ~'.*')
become: no
- name: set bootstrap facts (II)
set_fact:
- name: Set bootstrap facts (II)
ansible.builtin.set_fact:
bootstrap_os_family: "{{ item.key }}"
loop: "{{ bootstrap_os_family_map | dict2items }}"
loop_control:
label: "{{ item.key }}"
when:
- bootstrap_distribution in item.value
become: no

View file

@ -1,58 +1,55 @@
---
# tasks file for bootstrap
- name: include assert.yml
import_tasks: assert.yml
- name: Import assert.yml
ansible.builtin.import_tasks: assert.yml
run_once: yes
delegate_to: localhost
- name: wait for host
wait_for:
- name: Wait for port to be available
ansible.builtin.wait_for:
port: "{{ ansible_port | default('22') }}"
host: "{{ (ansible_ssh_host | default(ansible_host) | default(inventory_hostname)) }}"
connection: local
timeout: "{{ bootstrap_timeout }}"
become: no
when:
- ansible_connection is defined
- ansible_connection not in [ "docker", "container" ]
- ansible_connection not in [ "container", "docker", "community.docker.docker" ]
- bootstrap_wait_for_host | bool
- name: prepare system
- name: Prepare system
# At this stage, python and/or sudo are not installed, `become` can't be used.
become: no
block:
- name: test connection
wait_for_connection:
- name: Test connection
ansible.builtin.wait_for_connection:
timeout: "{{ bootstrap_timeout }}"
register: bootstrap_connect
changed_when: no
- name: Test sudo
ansible.builtin.command:
cmd: sudo --version
changed_when: no
rescue:
- name: gather bootstrap facts
include_tasks: "gather_facts.yml"
- name: Gather bootstrap facts
ansible.builtin.include_tasks:
file: gather_facts.yml
- name: install bootstrap packages
raw: "{{ bootstrap_install.raw }}"
- name: Install bootstrap packages (raw)
ansible.builtin.raw: "{{ bootstrap_install.raw }}"
register: bootstrap_install_packages
changed_when:
- (bootstrap_install.stdout_regex in bootstrap_install_packages.stdout and
bootstrap_os_family in [ "Alpine", "Archlinux", "Gentoo" ]) or
(bootstrap_install.stdout_regex not in bootstrap_install_packages.stdout and
bootstrap_os_family in [ "Debian", "RedHat", "Suse" ])
vars:
ansible_user: "{{ bootstrap_user }}"
always:
- name: set bootstrap_ansible_user
set_fact:
bootstrap_ansible_user: "{{ ansible_user | default(omit) if bootstrap_connect is succeeded else bootstrap_user }}"
changed_when: no
bootstrap_os_family in [ "Debian", "RedHat", "Rocky", "Suse" ])
- name: ensure system is prepared
block:
- name: gather ansible facts
setup:
- name: Gather ansible facts
ansible.builtin.setup:
become: no
- name: install bootstrap packages
package:
- name: Install bootstrap packages (package)
ansible.builtin.package:
name: "{{ item }}"
state: present
loop: "{{ bootstrap_facts_packages.split() }}"
vars:
ansible_user: "{{ bootstrap_ansible_user | default(omit) }}"
become: "{{ bootstrap_become }}"

View file

@ -2,25 +2,28 @@
# Ansible managed
#
[tox]
minversion = 3.20
# These environments are disabled:
# previous: Because collections don't work. ETA Fix: ansible-2.11 released.
envlist = py{39}-ansible-{current,next}
minversion = 4.2.4
envlist = py{310}-ansible{5,6,7}
skipsdist = true
[testenv]
deps =
previous: ansible>=2.9, <2.10
current: ansible
next: git+https://github.com/ansible/ansible.git@devel
molecule[docker]>=3, <4
docker>=4.2, <4.3
ansible-lint
ansible5: ansible == 5.*
ansible6: ansible == 6.*
ansible7: ansible == 7.*
molecule[docker]
docker == 6.*
ansible-lint == 6.*
commands = molecule test
setenv =
TOX_ENVNAME={envname}
PY_COLORS=1
ANSIBLE_FORCE_COLOR=1
ANSIBLE_ROLES_PATH=../
passenv = namespace image tag
passenv =
namespace
image
tag
DOCKER_HOST

View file

@ -6,7 +6,7 @@ _bootstrap_packages:
Archlinux: python sudo
Debian: python3 sudo gnupg python3-apt
Gentoo: python sudo gentoolkit
RedHat: python3 sudo
RedHat: &redhat_packages python3 sudo
Suse: python3 python3-xml sudo
Amazon: python sudo
CentOS_7: python sudo
@ -14,6 +14,11 @@ _bootstrap_packages:
Debian_9: python sudo gnupg
RedHat_7: python sudo
# Map the right set of packages, based on gathered bootstrap facts.
bootstrap_packages: "{{ _bootstrap_packages[bootstrap_distribution ~'_'~ bootstrap_distribution_major_version]|default(
_bootstrap_packages[bootstrap_distribution] )|default(
_bootstrap_packages[bootstrap_os_family] ) }}"
_bootstrap_install:
Alpine:
raw: "LANG=C apk update ; apk add {{ bootstrap_packages }}"
@ -35,18 +40,25 @@ _bootstrap_install:
raw: "LANG=C zypper -n install {{ bootstrap_packages }}"
stdout_regex: 'Nothing'
# Map the right install command, based on gathered bootstrap facts.
bootstrap_install: "{{ _bootstrap_install[bootstrap_distribution ~'_'~ bootstrap_distribution_major_version]|default(
_bootstrap_install[bootstrap_distribution] )|default(
_bootstrap_install[bootstrap_os_family] ) }}"
# See URL for available OS families and search queries
# https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts/system/distribution.py
bootstrap_os_family_map:
Alpine: [Alpine]
Archlinux: [Archlinux, Antergos, Manjaro]
Debian: [Debian, Ubuntu, Raspbian, Neon, KDE neon,
Linux Mint, SteamOS, Devuan, Kali, 'Cumulus Linux']
Linux Mint, SteamOS, Devuan, Kali, Cumulus Linux,
'Pop!_OS', Parrot, Pardus GNU/Linux]
Gentoo: [Gentoo, Funtoo]
RedHat: [RedHat, Fedora, CentOS, Scientific, SLC,
Ascendos, CloudLinux, PSBM, OracleLinux, OVS,
OEL, Amazon, Virtuozzo, XenServer, Alibaba]
Suse: [SLED, 'openSUSE Tumbleweed', 'openSUSE Leap',
Ascendos, CloudLinux, PSBM, Rocky, OracleLinux,
OVS, OEL, Amazon, Virtuozzo, XenServer, Alibaba,
EulerOS, openEuler, AlmaLinux]
Suse: [SLED, openSUSE Tumbleweed, openSUSE Leap,
SLES_SAP, SUSE_LINUX, SLES, openSUSE, SuSE]
bootstrap_search:
@ -54,16 +66,6 @@ bootstrap_search:
OracleLinux: 'Oracle Linux'
RedHat: 'Red Hat'
# Map the right set of packages, based on gathered bootstrap facts.
bootstrap_packages: "{{ _bootstrap_packages[bootstrap_distribution ~'_'~ bootstrap_distribution_major_version]|default(
_bootstrap_packages[bootstrap_distribution])|default(
_bootstrap_packages[bootstrap_os_family]) }}"
# Map the right install command, based on gathered bootstrap facts.
bootstrap_install: "{{ _bootstrap_install[bootstrap_distribution ~'_'~ bootstrap_distribution_major_version]|default(
_bootstrap_install[bootstrap_distribution])|default(
_bootstrap_install[bootstrap_os_family]) }}"
# Map the right set of packages, based on gathered ansible_facts.
bootstrap_facts_packages: "{{ _bootstrap_packages[ansible_distribution ~'_'~ ansible_distribution_major_version]|default(
_bootstrap_packages[ansible_distribution] )|default(