--- # # Copyright (c) 2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # # ROLE DESCRIPTION: # This role is to check the target host environment before proceeding to # the next step. # # Check host connectivity, change password if provided - block: - name: Set SSH port set_fact: ansible_port: "{{ ansible_port | default(22) }}" - name: Update SSH known hosts lineinfile: path: ~/.ssh/known_hosts state: absent regexp: '^{{ ansible_host }}|^\[{{ ansible_host }}\]:{{ ansible_port }}' delegate_to: localhost - name: Check connectivity local_action: command ping -c 1 {{ ansible_host }} failed_when: false register: ping_result - name: Fail if host is unreachable fail: msg='Host {{ ansible_host }} is unreachable!' with_items: - "{{ ping_result.stdout_lines|list }}" when: ping_result.rc != 0 and item is search('100% packet loss') - block: - debug: msg: "Changing the initial password.." - name: Change initial password expect: echo: yes command: "ssh -p {{ ansible_port }} {{ ansible_ssh_user }}@{{ ansible_host }}" responses: "{{ password_change_responses }}" failed_when: false delegate_to: localhost rescue: # Initial password has been changed and the user forgot to exclude # password_change option in the command line for the replay. - debug: msg: "Password has already been changed" when: change_password when: inventory_hostname != 'localhost' # Check for one of unmistakenly StarlingX packages - name: "Look for unmistakenly {{ image_brand }} package" command: rpm -q controllerconfig args: warn: false failed_when: false register: controllerconfig_installed - name: Fail if the become password is incorrect fail: msg: >- The provided sudo password does not match with {{ ansible_ssh_user }} password!. If {{ ansible_ssh_user }} password differs from StarlingX default ansible_become_pass (St8rlingX*), please overwrite the default ansible_become_pass either in host/site secret/override file or at the command line using playbook --extra-vars option. when: controllerconfig_installed.module_stderr is defined and controllerconfig_installed.module_stderr is search(' incorrect password attempts') - name: Fail if host is not running the right image fail: msg='Host {{ ansible_host }} does not have the right image!.' when: controllerconfig_installed.rc > 0 # Bail if the host has been unlocked - name: Check initial config flag stat: path: /etc/platform/.initial_config_complete register: initial_config_complete - block: - name: Set skip_play flag for host set_fact: skip_play: true - name: Skip remaining tasks if host is already unlocked debug: msg="Host {{ ansible_host }} has been unlocked. There's nothing to play!" - name: Stop playing if this is the only target host meta: end_play when: play_hosts | length == 1 when: initial_config_complete.stat.exists # Proceed only if skip_play flag is not turned on - block: # The following parameters should exist in default.yml. If any of them is # not available, the file is invalid. - name: Fail if any of the mandatory configurations are not defined fail: msg: "Mandatory configuration parameter {{ item }} is not defined." when: item is not defined with_items: - system_mode - timezone - pxeboot_subnet - management_subnet - cluster_host_subnet - cluster_pod_subnet - cluster_service_subnet - external_oam_subnet - external_oam_gateway_address - external_oam_floating_address - management_multicast_subnet - dynamic_address_allocation - dns_servers - docker_registries - admin_username - admin_password - override_files_dir - name: Set initial address facts if not defined. They will be updated later set_fact: pxeboot_start_address: "{{ pxeboot_start_address | default('derived') }}" pxeboot_end_address: "{{ pxeboot_end_address | default('derived') }}" management_start_address: "{{ management_start_address | default('derived') }}" management_end_address: "{{ management_end_address | default('derived') }}" cluster_host_start_address: "{{ cluster_host_start_address | default('derived') }}" cluster_host_end_address: "{{ cluster_host_end_address | default('derived') }}" cluster_pod_start_address: "{{ cluster_pod_start_address | default('derived') }}" cluster_pod_end_address: "{{ cluster_pod_end_address | default('derived') }}" cluster_service_start_address: "{{ cluster_service_start_address | default('derived') }}" cluster_service_end_address: "{{ cluster_service_end_address | default('derived') }}" external_oam_start_address: "{{ external_oam_start_address | default('derived') }}" external_oam_end_address: "{{ external_oam_end_address | default('derived') }}" management_multicast_start_address: "{{ management_multicast_start_address | default('derived') }}" management_multicast_end_address: "{{ management_multicast_end_address | default('derived') }}" external_oam_node_0_address: "{{ external_oam_node_0_address | default('derived') }}" external_oam_node_1_address: "{{ external_oam_node_1_address | default('derived') }}" - name: Set default registries dictionary set_fact: default_docker_registries: k8s.gcr.io: k8s.gcr.io gcr.io: gcr.io quay.io: quay.io docker.io: docker.io - name: Merge user and default registries dictionaries set_fact: docker_registries: "{{ default_docker_registries | combine(docker_registries) }}" - name: Initialize some flags to be used in subsequent roles/tasks set_fact: reconfigured: false system_config_update: false network_config_update: false docker_config_update: false save_password: true save_config: true use_docker_proxy: false use_unified_registry: false restart_services: false reconfigure_endpoints: false - name: Set initial facts set_fact: system_params: 'system_mode': "{{ system_mode }}" 'timezone': "{{ timezone }}" root_disk_size: "{{ standard_root_disk_size }}" root_disk_idx: 0 localhost_name_ip_mapping: "127.0.0.1\tlocalhost\tlocalhost.localdomain localhost4 localhost4.localdomain4" network_params: 'pxeboot_subnet': "{{ pxeboot_subnet }}" 'management_subnet': "{{ management_subnet }}" 'cluster_host_subnet': "{{ cluster_host_subnet }}" 'cluster_pod_subnet': "{{ cluster_pod_subnet }}" 'cluster_service_subnet': "{{ cluster_service_subnet }}" 'external_oam_subnet': "{{ external_oam_subnet }}" 'external_oam_gateway_address': "{{ external_oam_gateway_address }}" 'external_oam_floating_address': "{{ external_oam_floating_address }}" 'management_multicast_subnet': "{{ management_multicast_subnet }}" # Set this placeholder here to workaround an Ansible quirk derived_network_params: place_holder: place_holder ansible_remote_tmp: "{{ ansible_remote_tmp | default(lookup('ini', 'remote_tmp section=defaults file={{ playbook_dir }}/ansible.cfg')) }}" pods_wait_time: "{{ pods_wait_time | default(30) }}" - name: Turn on use_docker_proxy flag set_fact: use_docker_proxy: true when: (docker_http_proxy is defined and docker_http_proxy is not none) or (docker_https_proxy is defined and docker_https_proxy is not none) - name: Set default values for platform registries set_fact: default_k8s_registry: k8s.gcr.io default_gcr_registry: gcr.io default_quay_registry: quay.io default_docker_registry: docker.io - name: Set default values for docker proxies if not defined set_fact: docker_http_proxy: "{{ docker_http_proxy | default('undef') }}" docker_https_proxy: "{{ docker_https_proxy | default('undef') }}" docker_no_proxy: "{{ docker_no_proxy | default([]) }}" - name: Retrieve software version number # lookup module does not work with /etc/build.info as it does not have ini # format. Resort to shell source. shell: source /etc/build.info; echo $SW_VERSION register: sw_version_result - name: Fail if software version is not defined fail: msg: "SW_VERSION is missing in /etc/build.info" when: sw_version_result.stdout_lines|length == 0 - name: Retrieve system type shell: source /etc/platform/platform.conf; echo $system_type register: system_type_result - name: Fail if system type is not defined fail: msg: "system_type is missing in /etc/platform/platform.conf" when: system_type_result.stdout_lines|length == 0 - name: Set software version, system type config path facts set_fact: software_version: "{{ sw_version_result.stdout_lines[0] }}" system_type: "{{ system_type_result.stdout_lines[0] }}" - name: Set config path facts set_fact: keyring_permdir: "{{ platform_path + '/.keyring/' + software_version }}" config_permdir: "{{ platform_path + '/config/' + software_version }}" puppet_permdir: "{{ platform_path + '/puppet/' + software_version }}" # Give the bootstrap config output file on the host a generic name so the # same file is referenced if the host is bootstrapped locally and remotely # in whatever order. - name: Set bootstrap output file set_fact: last_bootstrap_config_file: "{{ config_permdir }}/last_bootstrap_config.yml" - name: Check Docker status command: systemctl status docker failed_when: false register: docker - name: Look for openrc file stat: path: /etc/platform/openrc register: openrc_file - name: Turn on replayed flag set_fact: replayed: true when: openrc_file.stat.exists and docker.rc == 0 - block: - name: Check if the controller-0 host has been successfully provisioned shell: source /etc/platform/openrc; system host-list|grep controller-0 failed_when: false register: host_check - block: # system has been configured - name: Set flag to indicate that this host has been previously configured set_fact: reconfigured: true - name: Find previous config file for this host stat: path: "{{ last_bootstrap_config_file }}" register: last_config_file - block: - name: Set last config file to import (local) set_fact: last_config: "{{ last_bootstrap_config_file }}" when: inventory_hostname == 'localhost' # Currently Ansible include_vars only works with local file - block: # Give a host specific name in case the playbook is used to bootstrap # multiple remote hosts simultaneously - name: Set last config file to import (remote) set_fact: last_config: "/tmp/{{ (last_bootstrap_config_file | basename | splitext)[0] }}_{{ inventory_hostname }}.yml" - name: Fetch previous config file from this host fetch: src: "{{ last_bootstrap_config_file }}" dest: "{{ last_config }}" flat: yes when: inventory_hostname != 'localhost' - name: Read in last config values include_vars: file: "{{ last_config }}" - name: Turn on system attributes reconfiguration flag set_fact: system_config_update: true when: (prev_system_mode != system_mode) or (prev_timezone != timezone) or (prev_dns_servers.split(',') | sort != dns_servers | sort) - name: Turn on docker reconfiguration flag if docker config is changed set_fact: docker_config_update: true when: (prev_docker_registries != docker_registries) or ((use_docker_proxy) and (prev_docker_http_proxy != docker_http_proxy or prev_docker_https_proxy != docker_https_proxy or prev_docker_no_proxy != docker_no_proxy)) - name: Turn on service endpoints reconfiguration flag if management and/or oam network config is changed set_fact: reconfigure_endpoints: true when: (prev_management_subnet != management_subnet) or (prev_management_start_address != management_start_address) or (prev_external_oam_subnet != external_oam_subnet) or (prev_external_oam_gateway_address != external_oam_gateway_address) or (prev_external_oam_floating_address != external_oam_floating_address) or (prev_external_oam_start_address != external_oam_start_address) or (prev_external_oam_end_address != external_oam_end_address) or (prev_external_oam_node_0_address != external_oam_node_0_address) or (prev_external_oam_node_1_address != external_oam_node_1_address) - name: Turn on network reconfiguration flag if any of the network related config is changed set_fact: network_config_update: true when: reconfigure_endpoints or (prev_dynamic_address_allocation != dynamic_address_allocation) or (prev_management_end_address != management_end_address) or (prev_pxeboot_subnet != pxeboot_subnet) or (prev_pxeboot_start_address != pxeboot_start_address) or (prev_pxeboot_end_address != pxeboot_end_address) or (prev_management_multicast_subnet != management_multicast_subnet) or (prev_management_multicast_start_address != management_multicast_start_address) or (prev_management_multicast_end_address != management_multicast_end_address) or (prev_cluster_host_subnet != cluster_host_subnet) or (prev_cluster_host_start_address != cluster_host_start_address) or (prev_cluster_host_end_address != cluster_host_end_address) or (prev_cluster_pod_subnet != cluster_pod_subnet) or (prev_cluster_pod_start_address != cluster_pod_start_address) or (prev_cluster_pod_end_address != cluster_pod_end_address) or (prev_cluster_service_subnet != cluster_service_subnet) or (prev_cluster_service_start_address != cluster_service_start_address) or (prev_cluster_service_end_address != cluster_service_end_address) - name: Turn on restart services flag if management/oam/cluster network or docker config is changed set_fact: restart_services: true pods_wait_time: "{{ pods_wait_time|int + 30 }}" when: reconfigure_endpoints or docker_config_update or (prev_cluster_host_subnet != cluster_host_subnet) or (prev_cluster_pod_subnet != cluster_pod_subnet) or (prev_cluster_service_subnet != cluster_service_subnet) # Re-evaluate the condition to generate the python keyring - name: Turn off save_password flag if admin password has not changed set_fact: save_password: false username: "{{ prev_admin_username }}" password: "{{ prev_admin_password }}" # TODO(tngo): there seems to be a puppet/sysinv limitation that prevents password # reconfiguration to work without an extra boot. Temporarily disable # it for replay for now. when: prev_admin_password == admin_password|hash('sha1') or replayed # Re-evaluate condition to persist config data to sysinv database - name: Turn off save_config flag if system, network, and docker configurations have not changed set_fact: save_config: false when: not system_config_update and not network_config_update and not docker_config_update - block: - debug: msg: "Configurations are unchanged. There's nothing to play!" - name: Stop playing if this is the only target host meta: end_play when: play_hosts|length == 1 - name: Turn on skip_play flag set_fact: skip_play: true when: not save_password and not save_config when: last_config_file.stat.exists when: host_check.rc == 0 when: replayed # bootstrap manifest has been applied - name: Check volume groups command: vgdisplay cgts-vg register: vg_result failed_when: false - name: Fail if volume groups are not configured fail: msg='Volume groups not configured.' when: vg_result.rc != 0 - name: Check size of root disk script: check_root_disk_size.py {{ standard_root_disk_size }} register: disk_size_check_result failed_when: false # Workaround an Ansible quirk - name: Update root disk index for remote play set_fact: root_disk_idx: "{{ root_disk_idx + 1 }}" when: ansible_connection != "local" - name: Set root disk and root disk size facts set_fact: root_disk: "{{ disk_size_check_result.stdout_lines[root_disk_idx|int] }}" root_disk_size: "{{ disk_size_check_result.stdout_lines[root_disk_idx|int + 1] }}" - debug: msg: >- [WARNING]: Root disk {{ root_disk }} size is {{ root_disk_size }}GB which is less than the standard size of {{ standard_root_disk_size }}GB. Please consult the Software Installation Guide for details. when: disk_size_check_result.rc != 0 - name: Look for branding tar file find: paths: /opt/branding patterns: '*.tgz' register: find_tar_result - name: Fail if there are more than one branding tar files fail: msg: >- Only one branding tarball is permitted in /opt/branding. Refer to the branding section of the documentation. when: find_tar_result.matched > 1 - name: Look for other branding files find: paths: /opt/branding excludes: '*.tgz,applied' register: find_result - name: Fail if the branding filename is not valid fail: msg: > {{ find_result.files[0].path }} is not a valid branding filename. Refer to the branding section of the documentation. when: find_result.matched > 0 - name: Mark environment as Ansible bootstrap file: path: /var/run/.ansible_bootstrap state: touch # Set up the remote tmp dir beforehand to get rid of the annoying warning # when pipelining is turned on for better performance. - name: Set up Ansible remote tmp dir file: path: "{{ ansible_remote_tmp }}" state: directory owner: root group: root mode: 0755 - debug: msg: >- system_config_update flag: {{ system_config_update }}, network_config_update flag: {{ network_config_update }}, docker_config_update flag: {{ docker_config_update }}, restart_services flag: {{ restart_services }}, endpoints_reconfiguration_flag: {{ reconfigure_endpoints }}, save_password flag: {{ save_password }}, save_config flag: {{ save_config }}, skip_play flag: {{ skip_play }} when: not skip_play