Files
ansible-playbooks/playbookconfig/playbookconfig/playbooks/bootstrap/roles/validate-config/tasks/main.yml
Tee Ngo 2b7bcd79c9 Ansible Bootstrap Deployment
This commit is initial submission of bootstrap playbook which
enables the bootstrap of initial controller. The playbook
defaults are meant for configuring the localhost in vbox
development environment. Custom hosts file and user overrides
are required for configuring multiple hosts and lab specific setup.
Secret file and SSH keys are required for production test enviroment.

Tests performed:
 - installation
 - config_controller complete to ensure the current method of
   configuring the first controller is intact
 - localhost bootstrap with default hosts file
 - multiple remote hosts bootstrap with custom hosts file
 - reconfigurations with user overrides
 - stx-application applied in AIOSX and AIODX
 - Failure & skip play cases (invalid config inputs, incorrect load,
   connection failure, no changes replay, etc...)

TODO:
 - Support for standard & storage configurations
 - Docker proxy/custom registry related tests
 - Package bootstrap playbook in SDK
 - Config_controller cleanup

Change-Id: If553f1eeed32606bacc690ef277e60606e9d93ea
Story: 200476
Task: 29686
Task: 29687
Co-Authored-By: Ovidiu Poncea <ovidiu.poncea@windriver.com>
Signed-off-by: Tee Ngo <tee.ngo@windriver.com>
2019-04-11 08:40:34 -04:00

427 lines
20 KiB
YAML

---
#
# Copyright (c) 2019 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
# ROLE DESCRIPTION:
# This role is to validate amd save host (non secure) config.
#
- debug:
msg:
- System mode is {{ system_mode }}
- Timezone is {{ timezone }}
- DNS servers is {{ dns_servers }}
- PXE boot subnet is {{ pxeboot_subnet }}
- Management subnet is {{ management_subnet }}
- Cluster host subnet is {{ cluster_host_subnet }}
- Cluster pod subnet is {{ cluster_pod_subnet }}
- Cluster service subnet is {{ cluster_service_subnet }}
- OAM subnet is {{ external_oam_subnet }}
- OAM gateway is {{ external_oam_gateway_address }}
- OAM floating ip is {{ external_oam_floating_address }}
- Dynamic address allocation is {{ dynamic_address_allocation }}
- Docker registries is {{ docker_registries }}
- Docker HTTP proxy is {{ docker_http_proxy }}
- Docker HTTPS proxy is {{ docker_https_proxy }}
- Docker no proxy list is {{ docker_no_proxy }}
# System parameters config validation
- block:
- name: Set system mode fact
set_fact:
system_mode: "{{ system_mode|lower }}"
- block:
- debug:
msg: "System type is Standard, system mode will be set to duplex."
- name: Set system mode to duplex for Standard system
set_fact:
system_mode: duplex
when: system_type == 'Standard'
- name: Validate system mode if system type is All-in-one
fail:
msg: "Invalid system mode. Valid values are: simplex, duplex or duplex-direct."
when: >
(system_mode != 'simplex' and
system_mode != 'duplex' and
system_mode != 'duplex-direct') and
(system_type == 'All-in-one')
- name: Checking registered timezones
stat:
path: "{{ '/usr/share/zoneinfo/' + timezone }}"
register: timezone_file
- name: Fail if provided timezone is unknown
fail: msg="The provided timezone {{ timezone }} is invalid."
when: not timezone_file.stat.exists
- name: Fail if the number of dns servers provided is not at least 1 and no more than 3
fail:
msg: "The number of DNS servers exceeds maximum allowable number of 3."
when: (dns_servers | length == 0) or (dns_servers | length > 3)
# DNS servers config validation
- block:
# Looping over a block of tasks is not yet supported. For now, move the
# DNS validation to a seprate tasks file.
- include: validate_dns.yml dns_server={{ item }}
with_items: "{{ dns_servers }}"
# Networks config validation
- block:
- name: Validate provided subnets (both IPv4 & IPv6 notations)
debug:
msg: "{{ item.key }}: {{ item.value }}"
failed_when: item.value|ipaddr == False
with_dict: "{{ network_params }}"
- name: Fail if cluster pod/service subnet size is too small (minimum size = 65536)
fail:
msg: "Subnet size is too small, must have minimum {{ min_pod_service_num_addresses }} addresses."
when: item|ipaddr('size') < min_pod_service_num_addresses
with_items:
- "{{ network_params.cluster_pod_subnet }}"
- "{{ network_params.cluster_service_subnet }}"
- name: Fail if pxeboot/management/multicast subnet size is too small (minimum size = 16)
fail:
msg: "Subnet size is too small, must have minimum {{ min_16_addresses }} addresses."
when: item|ipaddr('size') < min_16_addresses
with_items:
- "{{ network_params.pxeboot_subnet }}"
- "{{ network_params.management_subnet }}"
- "{{ network_params.management_multicast_subnet }}"
- name: Fail if the size of the remaining subnets is too small (minimum size = 8)
fail:
msg: "Subnet size is too small, must have minimum {{ min_8_addresses }} addresses."
when: item|ipaddr('size') < min_8_addresses
with_items:
- "{{ network_params.cluster_host_subnet }}"
- "{{ network_params.external_oam_subnet }}"
- name: Generate warning if subnet prefix is not typical for Standard systems
debug:
msg: "WARNING: Subnet prefix of less than /24 is not typical. This will affect scaling of the system!"
when: item|ipaddr('prefix')|int > typical_subnet_prefix and system_type == 'Standard'
with_items:
- "{{ network_params.pxeboot_subnet }}"
- "{{ network_params.management_subnet }}"
- "{{ network_params.cluster_host_subnet }}"
- "{{ network_params.external_oam_subnet }}"
- "{{ network_params.management_multicast_subnet }}"
- set_fact:
ipv6_addressing: "{{ network_params.management_subnet|ipv6 }}"
- block:
- name: Fail if IPv6 management on simplex
fail:
msg: "IPv6 management network not supported on simplex configuration."
when: system_mode == 'simplex'
- name: Fail if IPv6 prefix length is too short
fail:
msg: "IPv6 minimum prefix length is {{ minimum_prefix_length }}"
when: network_params.management_subnet|ipaddr('prefix')|int < minimum_ipv6_prefix_length
- name: Update localhost name ip mapping for IPv6
set_fact:
localhost_name_ip_mapping: "::1\tlocalhost\tlocalhost.localdomain localhost6 localhost6.localdomain6"
when: ipv6_addressing
- name: Fail if address allocation is misconfigured
fail:
msg: "dynamic_address_allocation is misconfigured. Valid value is either 'True' or 'False'."
when: not dynamic_address_allocation | bool
# The provided subnets have passed validation, set the default addresses
# based on the subnet values
- name: Set default start and end addresses based on provided subnets
set_fact:
default_pxeboot_start_address: "{{ (pxeboot_subnet | ipaddr(2)).split('/')[0] }}"
default_pxeboot_end_address: "{{ (pxeboot_subnet | ipaddr(-2)).split('/')[0] }}"
default_management_start_address: "{{ (management_subnet | ipaddr(2)).split('/')[0] }}"
default_management_end_address: "{{ (management_subnet | ipaddr(-2)).split('/')[0] }}"
default_cluster_host_start_address: "{{ (cluster_host_subnet | ipaddr(2)).split('/')[0] }}"
default_cluster_host_end_address: "{{ (cluster_host_subnet | ipaddr(-2)).split('/')[0] }}"
default_cluster_pod_start_address: "{{ (cluster_pod_subnet | ipaddr(1)).split('/')[0] }}"
default_cluster_pod_end_address: "{{ (cluster_pod_subnet | ipaddr(-2)).split('/')[0] }}"
default_cluster_service_start_address: "{{ (cluster_service_subnet | ipaddr(1)).split('/')[0] }}"
default_cluster_service_end_address: "{{ (cluster_service_subnet | ipaddr(-2)).split('/')[0] }}"
default_external_oam_start_address: "{{ (external_oam_subnet | ipaddr(1)).split('/')[0] }}"
default_external_oam_end_address: "{{ (external_oam_subnet | ipaddr(-2)).split('/')[0] }}"
default_management_multicast_start_address: "{{ (management_multicast_subnet | ipaddr(1)).split('/')[0] }}"
default_management_multicast_end_address: "{{ (management_multicast_subnet | ipaddr(-2)).split('/')[0] }}"
default_external_oam_node_0_address: "{{ external_oam_floating_address | ipmath(1) }}"
default_external_oam_node_1_address: "{{ external_oam_floating_address | ipmath(2) }}"
- name: Build address pairs for validation, merging default and user provided values
set_fact:
address_pairs:
pxeboot:
start: "{{ pxeboot_start_address if pxeboot_start_address != 'derived' else default_pxeboot_start_address }}"
end: "{{ pxeboot_end_address if pxeboot_end_address != 'derived' else default_pxeboot_end_address }}"
subnet: "{{ network_params.pxeboot_subnet }}"
use_default: "{{ true if pxeboot_start_address == 'derived' and pxeboot_end_address == 'derived' else false }}"
management:
start: "{{ management_start_address if management_start_address != 'derived' else default_management_start_address }}"
end: "{{ management_end_address if management_end_address != 'derived' else default_management_end_address }}"
subnet: "{{ network_params.management_subnet }}"
use_default: "{{ true if management_start_address == 'derived' and management_end_address == 'derived' else false }}"
cluster_host:
start: "{{ cluster_host_start_address if cluster_host_start_address != 'derived' else default_cluster_host_start_address }}"
end: "{{ cluster_host_end_address if cluster_host_end_address != 'derived' else default_cluster_host_end_address}}"
subnet: "{{ network_params.cluster_host_subnet }}"
use_default: "{{ true if cluster_host_start_address == 'derived' and cluster_host_end_address == 'derived' else false }}"
cluster_pod:
start: "{{ cluster_pod_start_address if cluster_pod_start_address != 'derived' else default_cluster_pod_start_address }}"
end: "{{ cluster_pod_end_address if cluster_pod_end_address != 'derived' else default_cluster_pod_end_address }}"
subnet: "{{ network_params.cluster_pod_subnet }}"
use_default: "{{ true if cluster_pod_start_address == 'derived' and cluster_pod_end_address == 'derived' else false }}"
cluster_service:
start: "{{ cluster_service_start_address if cluster_service_start_address != 'derived' else default_cluster_service_start_address }}"
end: "{{ cluster_service_end_address if cluster_service_end_address != 'derived' else default_cluster_service_end_address }}"
subnet: "{{ network_params.cluster_service_subnet }}"
use_default: "{{ true if cluster_service_start_address == 'derived' and cluster_service_end_address == 'derived' else false }}"
oam:
start: "{{ external_oam_start_address if external_oam_start_address != 'derived' else default_external_oam_start_address }}"
end: "{{ external_oam_end_address if external_oam_end_address != 'derived' else default_external_oam_end_address }}"
subnet: "{{ network_params.external_oam_subnet }}"
use_default: "{{ true if external_oam_start_address == 'derived' and external_oam_end_address == 'derived' else false }}"
multicast:
start: "{{ management_multicast_start_address if management_multicast_start_address != 'derived' else default_management_multicast_start_address }}"
end: "{{ management_multicast_end_address if management_multicast_end_address != 'derived' else default_management_multicast_end_address }}"
subnet: "{{ network_params.management_multicast_subnet }}"
use_default: "{{ true if management_multicast_start_address == 'derived' and management_multicast_end_address == 'derived' else false }}"
oam_node:
start: "{{ external_oam_node_0_address if external_oam_node_0_address != 'derived' else default_external_oam_node_0_address }}"
end: "{{ external_oam_node_1_address if external_oam_node_1_address != 'derived' else default_external_oam_node_1_address }}"
subnet: "{{ network_params.external_oam_subnet }}"
use_default: "{{ true if external_oam_node_0_address == 'derived' and external_oam_node_1_address == 'derived' else false }}"
- include: validate_address_range.yml
with_dict: "{{ address_pairs }}"
- name: Set floating addresses based on subnets or start addresses
set_fact:
# Not sure why ipaddr('address') and ipsubnet filter did not extract the IP from CIDR input. Resort to string split for now.
controller_floating_address: "{{ (management_subnet | ipaddr(2)).split('/')[0] if management_start_address == 'derived' else management_start_address }}"
controller_pxeboot_floating_address: "{{ (pxeboot_subnet | ipaddr(2)).split('/')[0] if pxeboot_start_address == 'derived' else pxeboot_start_address }}"
cluster_floating_address: "{{ (cluster_host_subnet | ipaddr(2)).split('/')[0] if cluster_host_start_address == 'derived' else cluster_host_start_address }}"
- name: Set derived facts for subsequent roles
set_fact:
derived_network_params:
'management_interface': lo
'management_interface_name': lo
'controller_0_address': "{{ controller_floating_address|ipmath(1) }}"
'controller_1_address': "{{ controller_floating_address|ipmath(2) }}"
'nfs_management_address_1': "{{ controller_floating_address|ipmath(3) }}"
'nfs_management_address_2': "{{ controller_floating_address|ipmath(4) }}"
'controller_pxeboot_address_0': "{{ controller_pxeboot_floating_address|ipmath(1) }}"
'controller_pxeboot_address_1': "{{ controller_pxeboot_floating_address|ipmath(2) }}"
# Make common facts available to other roles
config_workdir: "{{ config_workdir }}"
dns_servers: "{{ dns_servers }}"
# Derived network parameters that don't apply to bootstrap_config but are required for
# subsequent roles
management_subnet_prefix: "{{ management_subnet | ipaddr('prefix') }}"
management_broadcast: "{{ management_subnet | ipaddr('broadcast') }}"
pxe_subnet_prefix: "{{ pxeboot_subnet | ipaddr('prefix') }}"
cluster_subnet_prefix: "{{ cluster_host_subnet | ipaddr('prefix') }}"
cluster_broadcast: "{{ cluster_host_subnet | ipaddr('broadcast') }}"
controller_0_cluster_host: "{{ cluster_floating_address|ipmath(1) }}"
controller_1_cluster_host: "{{ cluster_floating_address|ipmath(2) }}"
# Docker config validation
- block:
- set_fact:
use_default_registries: true
# Define these just in case we need them later
default_k8s_registry: k8s.gcr.io
default_gcr_registry: gcr.io
default_quay_registry: quay.io
default_docker_registry: docker.io
default_no_proxy:
- localhost
- 127.0.0.1
- "{{ controller_floating_address }}"
- "{{ derived_network_params.controller_0_address }}"
- "{{ derived_network_params.controller_1_address }}"
sx_proxy_addons:
- "{{ address_pairs['oam']['start'] }}"
non_sx_proxy_addons:
- "{{ external_oam_floating_address }},"
- "{{ address_pairs['oam_node']['start'] }},"
- "{{ address_pairs['oam_node']['end'] }}"
docker_no_proxy_combined: []
- block:
- name: Set default no-proxy address list (simplex)
set_fact:
default_no_proxy: "{{ default_no_proxy + sx_proxy_addons }}"
when: system_mode == 'simplex'
- name: Set default no-proxy address list (non simplex)
set_fact:
default_no_proxy: "{{ default_no_proxy + non_sx_proxy_addons }}"
when: system_mode != 'simplex'
- block:
- name: Validate http proxy urls
include: validate_url.yml input_url={{ item }}
with_items:
- "{{ docker_http_proxy }}"
- "{{ docker_https_proxy }}"
- block:
- name: Validate no proxy addresses
include: validate_address.yml input_address={{ item }}
with_items: "{{ docker_no_proxy }}"
when: docker_no_proxy|length > 0
- name: Add user defined no-proxy address list to default
set_fact:
docker_no_proxy_combined: "{{ default_no_proxy + docker_no_proxy }}"
when: use_docker_proxy
- block:
- name: Fail if secure registry flag is misconfigured
fail:
msg: "is_secure_registry is misconfigured. Valid value is either 'True' or 'False'."
when: (is_secure_registry is defined) and
(not is_secure_registry | bool)
- name: Default the unified registry to secure if not specified
set_fact:
is_secure_registry: True
when: is_secure_registry is not defined
- name: Turn on use_unified_registry flag
set_fact:
use_unified_registry: true
unified_registry: "{{ docker_registries }}"
when: docker_registries|length == 1
- name: Update use_default_registries flag
set_fact:
use_default_registries: false
when: use_unified_registry or
docker_registries|length != 4 or
default_k8s_registry not in docker_registries or
default_gcr_registry not in docker_registries or
default_quay_registry not in docker_registries or
default_docker_registry not in docker_registries
- block:
- include: validate_address.yml input_address={{ item }}
with_items: "{{ docker_registries }}"
when: not use_default_registries
# Docker images archive source validation
- block:
- set_fact:
images_archive_exists: false
- block:
- name: Check if images archive location exists
stat:
path: "{{ docker_images_archive_source }}"
register: archive_source
- block:
- name: Get list of archived files
find:
paths: "{{ docker_images_archive_source }}"
patterns: "*.tar"
register: archive_find_output
- name: Turn on images archive flag
set_fact:
images_archive_exists: true
when: archive_find_output.matched > 0
when: archive_source.stat.exists
delegate_to: localhost
when: (docker_images_archive_source is defined) and
(docker_images_archive_source is not none)
# bootstrap_config ini file generation
- block:
- name: Create config workdir
file:
path: "{{ config_workdir }}"
state: directory
owner: root
group: root
mode: 0755
- name: Generate config ini file for python sysinv db population script
lineinfile:
path: "{{ bootstrap_config_file }}"
line: "{{ item }}"
create: yes
with_items:
- "[BOOTSTRAP_CONFIG]"
- "CONTROLLER_HOSTNAME=controller-0"
- "SYSTEM_TYPE={{ system_type }}"
- "SYSTEM_MODE={{ system_mode }}"
- "TIMEZONE={{ timezone }}"
- "SW_VERSION={{ software_version }}"
- "NAMESERVERS={{ dns_servers| join(',') }}"
- "PXEBOOT_SUBNET={{ pxeboot_subnet }}"
- "PXEBOOT_START_ADDRESS={{ address_pairs['pxeboot']['start'] }}"
- "PXEBOOT_END_ADDRESS={{ address_pairs['pxeboot']['end'] }}"
- "MANAGEMENT_SUBNET={{ management_subnet }}"
- "MANAGEMENT_START_ADDRESS={{ address_pairs['management']['start'] }}"
- "MANAGEMENT_END_ADDRESS={{ address_pairs['management']['end'] }}"
- "DYNAMIC_ADDRESS_ALLOCATION={{ dynamic_address_allocation }}"
- "MANAGEMENT_INTERFACE=lo"
- "CONTROLLER_0_ADDRESS={{ derived_network_params.controller_0_address }}"
- "CLUSTER_HOST_SUBNET={{ cluster_host_subnet }}"
- "CLUSTER_HOST_START_ADDRESS={{ address_pairs['cluster_host']['start'] }}"
- "CLUSTER_HOST_END_ADDRESS={{ address_pairs['cluster_host']['end'] }}"
- "CLUSTER_POD_SUBNET={{ cluster_pod_subnet }}"
- "CLUSTER_POD_START_ADDRESS={{ address_pairs['cluster_pod']['start'] }}"
- "CLUSTER_POD_END_ADDRESS={{ address_pairs['cluster_pod']['end'] }}"
- "CLUSTER_SERVICE_SUBNET={{ cluster_service_subnet }}"
- "CLUSTER_SERVICE_START_ADDRESS={{ address_pairs['cluster_service']['start'] }}"
- "CLUSTER_SERVICE_END_ADDRESS={{ address_pairs['cluster_service']['start'] }}"
- "EXTERNAL_OAM_SUBNET={{ external_oam_subnet }}"
- "EXTERNAL_OAM_START_ADDRESS={{ address_pairs['oam']['start'] }}"
- "EXTERNAL_OAM_END_ADDRESS={{ address_pairs['oam']['end'] }}"
- "EXTERNAL_OAM_GATEWAY_ADDRESS={{ external_oam_gateway_address }}"
- "EXTERNAL_OAM_FLOATING_ADDRESS={{ external_oam_floating_address }}"
- "EXTERNAL_OAM_0_ADDRESS={{ address_pairs['oam_node']['start'] }}"
- "EXTERNAL_OAM_1_ADDRESS={{ address_pairs['oam_node']['end'] }}"
- "MANAGEMENT_MULTICAST_SUBNET={{ management_multicast_subnet }}"
- "MANAGEMENT_MULTICAST_START_ADDRESS={{ address_pairs['multicast']['start'] }}"
- "MANAGEMENT_MULTICAST_END_ADDRESS={{ address_pairs['multicast']['end'] }}"
- "DOCKER_HTTP_PROXY={{ docker_http_proxy }}"
- "DOCKER_HTTPS_PROXY={{ docker_https_proxy }}"
- "DOCKER_NO_PROXY={{ docker_no_proxy_combined | join(',') }}"
- "DOCKER_REGISTRIES={{ docker_registries | join(',') }}"
- "USE_DEFAULT_REGISTRIES={{ use_default_registries }}"
- "IS_SECURE_REGISTRY={{ is_secure_registry | default(True) }}"
- name: Write simplex flag
file:
path: /etc/platform/simplex
state: touch
when: save_config