From e6b6001274cafea8374a06e8b17fb22fa20eb096 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 28 Mar 2018 10:24:47 +0100 Subject: xci: Use proper Ansible modules to manage SSH keys We can use the 'user', 'slurp' and 'authorized_key' modules to manage the various SSH configurations across the hosts instead of using command line tools. Change-Id: I2dde4d584fc336e267868607d5a58f5ee2c1feed Signed-off-by: Markos Chandras --- .../osa/playbooks/configure-opnfvhost.yml | 74 +++++++++++----------- .../osa/playbooks/configure-targethosts.yml | 34 ++++++++-- xci/playbooks/configure-localhost.yml | 14 ++++ 3 files changed, 80 insertions(+), 42 deletions(-) diff --git a/xci/installer/osa/playbooks/configure-opnfvhost.yml b/xci/installer/osa/playbooks/configure-opnfvhost.yml index 001fcee3..25e78b2c 100644 --- a/xci/installer/osa/playbooks/configure-opnfvhost.yml +++ b/xci/installer/osa/playbooks/configure-opnfvhost.yml @@ -43,16 +43,15 @@ proxy_settings_no_proxy: "{{ lookup('env','no_proxy') }}" tasks: - - name: generate SSH keys - command: ssh-keygen -b 2048 -t rsa -f /root/.ssh/id_rsa -q -N "" - args: - creates: "{{ ansible_env.HOME }}/.ssh/id_rsa" - changed_when: True - - name: fetch public key - fetch: - src: "{{ ansible_env.HOME }}/.ssh/id_rsa.pub" - dest: "{{ xci_path }}/xci/files/authorized_keys" - flat: yes + - name: Configure SSH key for root user + user: + name: root + generate_ssh_key: yes + ssh_key_bits: 2048 + ssh_key_comment: xci + ssh_key_type: rsa + state: present + - name: Copy releng-xci to remote host synchronize: src: "{{ xci_path }}/" @@ -204,32 +203,14 @@ src: "{{ xci_path }}/.cache/xci.env" dest: /root/xci.env -- hosts: localhost - remote_user: root - - tasks: - - name: Append public keys to authorized_keys - shell: "/bin/cat {{ ansible_env.HOME }}/.ssh/id_rsa.pub >> {{ xci_path }}/xci/files/authorized_keys" - changed_when: True - -- hosts: opnfv - remote_user: root - vars_files: - - "{{ xci_path }}/xci/var/opnfv.yml" - - pre_tasks: - - name: Load distribution variables + - name: Reload OpenStack-Ansible variables include_vars: - file: "{{ item }}" - failed_when: false - with_items: - - "{{ xci_path }}/xci/var/{{ ansible_os_family }}.yml" - - "{{ xci_flavor_ansible_file_path }}/flavor-vars.yml" - - "{{ xci_flavor_ansible_file_path }}/user_variables.yml" - roles: - - role: "openstack-ansible-openstack_openrc" + file: "{{ xci_flavor_ansible_file_path }}/user_variables.yml" + + - name: Generate openrc + include_role: + name: "openstack-ansible-openstack_openrc" - tasks: - name: add extra insecure flag to generated openrc blockinfile: dest: "{{ ansible_env.HOME }}/openrc" @@ -242,7 +223,24 @@ dest: "{{ xci_path }}/.cache/openrc" flat: true - - name: add public key to host - copy: - src: "{{ xci_path }}/xci/files/authorized_keys" - dest: /root/.ssh/authorized_keys + - name: Determine local user + become: no + local_action: command whoami + changed_when: False + register: _ansible_user + + - name: Fetch local SSH key + delegate_to: localhost + become: no + slurp: + src: "/home/{{ _ansible_user.stdout }}/.ssh/id_rsa.pub" + register: _local_ssh_key + + - name: Configure OPNFV authorized_keys file + authorized_key: + exclusive: yes + user: root + state: present + manage_dir: yes + comment: "{{ _ansible_user.stdout }} key" + key: "{{ _local_ssh_key['content'] | b64decode }}" diff --git a/xci/installer/osa/playbooks/configure-targethosts.yml b/xci/installer/osa/playbooks/configure-targethosts.yml index 09258e7c..b76a5950 100644 --- a/xci/installer/osa/playbooks/configure-targethosts.yml +++ b/xci/installer/osa/playbooks/configure-targethosts.yml @@ -33,7 +33,33 @@ - xci_ceph_enabled == "true" - "'compute' in group_names" tasks: - - name: add public key to host - copy: - src: "{{ xci_path }}/xci/files/authorized_keys" - dest: /root/.ssh/authorized_keys + - name: Determine local user + become: no + local_action: command whoami + changed_when: False + register: _ansible_user + + - name: Fetch local SSH key + delegate_to: localhost + become: no + slurp: + src: "/home/{{ _ansible_user.stdout }}/.ssh/id_rsa.pub" + register: _local_ssh_key + + - name: Fetch OPNFV SSH key + delegate_to: opnfv + slurp: + src: "{{ ansible_env.HOME }}/.ssh/id_rsa.pub" + register: _opnfv_ssh_key + + - name: "Configure {{ inventory_hostname }} authorized_keys file" + authorized_key: + exclusive: "{{ item.exclusive }}" + user: root + state: present + manage_dir: yes + key: "{{ item.key }}" + comment: "{{ item.comment }}" + with_items: + - { key: "{{ _local_ssh_key['content'] | b64decode }}", comment: "{{ _ansible_user.stdout }} key", exclusive: yes } + - { key: "{{ _opnfv_ssh_key['content'] | b64decode }}", comment: "opnfv host key", exclusive: no } diff --git a/xci/playbooks/configure-localhost.yml b/xci/playbooks/configure-localhost.yml index f64400e3..1f010528 100644 --- a/xci/playbooks/configure-localhost.yml +++ b/xci/playbooks/configure-localhost.yml @@ -99,6 +99,20 @@ when: - installer_type == "osa" + - name: Configure SSH key for local user + user: + name: "{{ ansible_env.USER }}" + createhome: yes + home: "/home/{{ ansible_env.USER }}" + move_home: yes + shell: /bin/bash + generate_ssh_key: yes + ssh_key_bits: 2048 + ssh_key_comment: xci + ssh_key_type: rsa + ssh_key_file: .ssh/id_rsa + state: present + - name: Dump XCI execution environment to a file shell: env > "{{ xci_path }}/.cache/xci.env" args: -- cgit From 25ec0a542c5948b4ec515138ddb339fa12234a4b Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 28 Mar 2018 10:44:12 +0100 Subject: xci: osa: Simplify tasks for copying OSA configuration files We can use a loop to copy all these files instead of multiple tasks. This simplifies the playbook quite a bit. Change-Id: I5f0d387ac090d81fc577b5ebeaeb6131e75cffa1 Signed-off-by: Markos Chandras --- .../osa/playbooks/configure-opnfvhost.yml | 113 +++++++++------------ 1 file changed, 48 insertions(+), 65 deletions(-) diff --git a/xci/installer/osa/playbooks/configure-opnfvhost.yml b/xci/installer/osa/playbooks/configure-opnfvhost.yml index 25e78b2c..11957cdc 100644 --- a/xci/installer/osa/playbooks/configure-opnfvhost.yml +++ b/xci/installer/osa/playbooks/configure-opnfvhost.yml @@ -58,28 +58,47 @@ dest: "{{ remote_xci_path }}" recursive: yes delete: yes - - name: copy flavor inventory - command: "/bin/cp -rf {{ remote_xci_flavor_files }}/inventory {{ remote_xci_playbooks }}" - args: - creates: "{{ remote_xci_playbooks }}/inventory" - - name: copy openstack_deploy - command: "/bin/cp -rf {{openstack_osa_path}}/etc/openstack_deploy {{openstack_osa_etc_path}}" - args: - creates: "{{ openstack_osa_etc_path }}" - - name: copy openstack_user_config.yml - command: "/bin/cp -rf {{ remote_xci_flavor_files }}/openstack_user_config.yml {{openstack_osa_etc_path}}" - args: - creates: "{{ openstack_osa_etc_path }}/openstack_user_config.yml" - failed_when: false - - name: copy all user override files - command: "/bin/cp -rf {{ remote_xci_flavor_files }}/user_variables.yml {{openstack_osa_etc_path}}" - args: - creates: "{{ openstack_osa_etc_path }}/user_variables.yml }}" - failed_when: false - - name: copy cinder.yml - command: "/bin/cp -rf {{ remote_xci_path }}/xci/installer/osa/files/cinder.yml {{openstack_osa_etc_path}}/env.d" + + - name: Re-create OpenStack-Ansible /etc directory + file: + path: "{{ openstack_osa_etc_path }}" + state: "{{ item }}" + with_items: + - absent + - directory + + - name: Remove upstream OpenStack-Ansible files + file: + path: "{{ openstack_osa_path }}/playbooks/{{ item }}" + state: absent + with_items: + - inventory + - setup-openstack.yml + + - name: Copy OpenStack-Ansible configuration files + command: "/bin/cp -rf {{ item.src }} {{ item.dest }}" args: - creates: "{{ openstack_osa_etc_path }}/env.d/cinder.yml" + creates: "{{ item.dest }}/{{ item.src | basename }}" + with_items: + - { src: "{{ openstack_osa_path }}/etc/openstack_deploy/env.d", dest: "{{ openstack_osa_etc_path }}" } + - { src: "{{ openstack_osa_path }}/etc/openstack_deploy/conf.d", dest: "{{ openstack_osa_etc_path }}" } + - { src: "{{ openstack_osa_path }}/etc/openstack_deploy/user_secrets.yml", dest: "{{ openstack_osa_etc_path }}" } + - { src: "{{ remote_xci_flavor_files }}/inventory", dest: "{{ remote_xci_playbooks }}" } + - { src: "{{ remote_xci_flavor_files }}/openstack_user_config.yml", dest: "{{ openstack_osa_etc_path }}" } + - { src: "{{ remote_xci_flavor_files }}/user_variables.yml", dest: "{{ openstack_osa_etc_path }}" } + - { src: "{{ remote_xci_flavor_files }}/ceph.yml", dest: "{{ openstack_osa_etc_path }}/conf.d/", cond: xci_ceph_enabled } + - { src: "{{ remote_xci_flavor_files }}/user_ceph.yml", dest: "{{ openstack_osa_etc_path }}/user_ceph.yml", cond: xci_ceph_enabled } + - { src: "{{ remote_xci_flavor_files }}/user_variables_ceph.yml", dest: "{{ openstack_osa_etc_path }}/user_variables_ceph.yml", cond: xci_ceph_enabled } + - { src: "{{ remote_xci_path }}/xci/installer/osa/files/cinder.yml", dest: "{{ openstack_osa_etc_path }}/env.d" } + - { src: "{{ remote_xci_path }}/xci/installer/osa/files/user_variables_proxy.yml", dest: "{{ openstack_osa_etc_path }}/user_variables_proxy.yml", cond: "{{ lookup('env', 'http_proxy') != '' }}" } + - { src: "{{ remote_xci_path }}/xci/installer/osa/files/setup-openstack.yml", dest: "{{ openstack_osa_path }}/playbooks" } + - { src: "{{ remote_xci_path }}/xci/installer/osa/files/ansible-role-requirements.yml", dest: "{{openstack_osa_path}}/ansible-role-requirements.yml", cond: openstack_osa_version != "master" } + - { src: "{{ remote_xci_path }}/xci/installer/osa/files/global-requirement-pins.txt", dest: "{{openstack_osa_path}}/global-requirement-pins.txt", cond: openstack_osa_version != "master" } + - { src: "{{ remote_xci_path }}/xci/installer/osa/files/openstack_services.yml", dest: "{{ openstack_osa_path }}/playbooks/defaults/repo_packages/openstack_services.yml", cond: openstack_osa_version != "master" } + when: item.cond is not defined or (item.cond is defined and item.cond | bool) + loop_control: + label: "{{ item.src }}" + - name: Configure OpenStack-Ansible components lineinfile: path: "{{ openstack_osa_etc_path }}/user_variables.yml" @@ -89,51 +108,15 @@ - { component: "tempest_install", value: "{{ run_tempest | bool }}" } - { component: "tempest_run", value: "{{ run_tempest | bool }}" } - { component: "core_openstack", value: "{{ core_openstack_install | bool }}" } - - block: - - name: copy ceph.yml - command: "/bin/cp -rf {{ remote_xci_flavor_files }}/ceph.yml {{openstack_osa_etc_path}}/conf.d/" - args: - creates: "{{ openstack_osa_etc_path }}/conf.d/ceph.yml" - - name: copy user_ceph.yml - command: "/bin/cp -rf {{ remote_xci_flavor_files }}/user_ceph.yml {{openstack_osa_etc_path}}/user_ceph.yml" - args: - creates: "{{ openstack_osa_etc_path }}/user_ceph.yml" - - name: copy user_variables_ceph.yml - command: "/bin/cp -rf {{ remote_xci_flavor_files }}/user_variables_ceph.yml {{openstack_osa_etc_path}}/user_variables_ceph.yml" - args: - creates: "{{ openstack_osa_etc_path }}/user_variables_ceph.yml" - when: xci_ceph_enabled == "true" - - block: - - name: copy user_variables_proxy.yml - command: "/bin/cp -rf {{ remote_xci_path }}/xci/installer/osa/files/user_variables_proxy.yml {{openstack_osa_etc_path}}/user_variables_proxy.yml" - args: - creates: "{{ openstack_osa_etc_path }}/user_variables_proxy.yml" - - name: "Configure http_proxy_env_url" - lineinfile: - path: "{{openstack_osa_etc_path}}/user_variables_proxy.yml" - regexp: "^http_proxy_env_url:.*" - line: "{{ 'http_proxy_env_url: ' + lookup('env','http_proxy') }}" - when: - - lookup('env','http_proxy') != "randomfoobarstring" - - name: copy OPNFV OpenStack playbook - command: "/bin/cp -rf {{ remote_xci_path }}/xci/installer/osa/files/setup-openstack.yml {{openstack_osa_path}}/playbooks" - args: - creates: "{{ openstack_osa_path }}/playbooks/setup-openstack.yml" - - name: copy pinned versions of OSA Roles and global requirements - command: "/bin/cp -rf {{ remote_xci_path }}/xci/installer/osa/files/{{ item }} {{openstack_osa_path}}/{{ item }}" - args: - creates: "{{ openstack_osa_path }}/{{ item }}" - with_items: - - "ansible-role-requirements.yml" - - "global-requirement-pins.txt" - when: - - openstack_osa_version != "master" - - name: copy pinned versions of OpenStack services - command: "/bin/cp -rf {{ remote_xci_path }}/xci/installer/osa/files/openstack_services.yml {{openstack_osa_path}}/playbooks/defaults/repo_packages/openstack_services.yml" - args: - creates: "{{ openstack_osa_path }}/playbooks/defaults/repo_packages/openstack_services.yml" + + - name: "Configure http_proxy_env_url" + lineinfile: + path: "{{openstack_osa_etc_path}}/user_variables_proxy.yml" + regexp: "^http_proxy_env_url:.*" + line: "{{ 'http_proxy_env_url: ' + lookup('env','http_proxy') }}" when: - - openstack_osa_version != "master" + - lookup('env','http_proxy') != "" + - include: "{{ xci_path }}/xci/playbooks/bootstrap-scenarios.yml" - name: bootstrap ansible on opnfv host command: "/bin/bash ./scripts/bootstrap-ansible.sh" -- cgit From 396ea65c98f71580a2e789c7d93c8d8611878b64 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 28 Mar 2018 16:10:28 +0100 Subject: xci: bootstrap-host: Make active network interface consistent When we run XCI for the first time, Ansible picks the first active interface as the default one. However, after we configure all the XCI bridges etc, and we try to run this role again, Ansible may have changed its mind about what interface is active and it could default to one of the bridges. This forces the role to redo the network configuration but this time the bridges are being attached to bridges so everything goes terribly wrong after that. The way to solve this would be to add a local fact about what interface should be considered as the 'real' default one so subsequent calls to this role to not destroy the network. This also drops the task which removed the network configuration files on SUSE platforms since Ansible is smart enough to not touch them if they are configured properly. Change-Id: Ic0525e934b1934a40d69e6cf977615ab9b3dac6d Signed-off-by: Markos Chandras --- .../roles/bootstrap-host/handlers/main.yml | 12 +++++ .../roles/bootstrap-host/tasks/network.yml | 59 ++++++++++++++-------- 2 files changed, 50 insertions(+), 21 deletions(-) create mode 100644 xci/playbooks/roles/bootstrap-host/handlers/main.yml diff --git a/xci/playbooks/roles/bootstrap-host/handlers/main.yml b/xci/playbooks/roles/bootstrap-host/handlers/main.yml new file mode 100644 index 00000000..b9103233 --- /dev/null +++ b/xci/playbooks/roles/bootstrap-host/handlers/main.yml @@ -0,0 +1,12 @@ +--- +# SPDX-license-identifier: Apache-2.0 +############################################################################## +# Copyright (c) 2018 SUSE Linux GmbH and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +- name: Reload facts + setup: + filter: ansible_local diff --git a/xci/playbooks/roles/bootstrap-host/tasks/network.yml b/xci/playbooks/roles/bootstrap-host/tasks/network.yml index ea9060e6..92e9195e 100644 --- a/xci/playbooks/roles/bootstrap-host/tasks/network.yml +++ b/xci/playbooks/roles/bootstrap-host/tasks/network.yml @@ -25,6 +25,31 @@ name: "{{ network_packages }}" state: present +- name: Ensure local facts directory exists + file: + path: "/etc/ansible/facts.d" + state: directory + +# NOTE(hwoarang) We have to check all levels of the local fact before we add it +# otherwise Ansible will fail. +- name: Record initial active interface + ini_file: + create: yes + section: network + state: present + option: xci_interface + value: "{{ ansible_default_ipv4.interface }}" + path: "/etc/ansible/facts.d/xci.fact" + when: ansible_local is not defined + or (ansible_local is defined and ansible_local.xci is not defined) + or (ansible_local is defined and ansible_local.xci is defined and ansible_local.xci.network is not defined) + or (ansible_local is defined and ansible_local.xci is defined and ansible_local.xci.network is defined and ansible_local.xci.network.xci_interface is not defined) + notify: + - Reload facts + +- name: Run handlers + meta: flush_handlers + - block: - name: configure modules lineinfile: @@ -48,33 +73,25 @@ src: "{{ ansible_os_family | lower }}/{{ ansible_hostname }}.interface.j2" dest: "/etc/network/interfaces" - name: restart network service - shell: "/sbin/ifconfig {{ ansible_default_ipv4.interface }} 0 && /sbin/ifdown -a && /sbin/ifup -a" + shell: "/sbin/ifconfig {{ ansible_local.xci.network.xci_interface }} 0 && /sbin/ifdown -a && /sbin/ifup -a" async: 15 poll: 0 when: ansible_os_family | lower == "debian" - block: - - name: Remove existing network configuration - file: - path: "/etc/sysconfig/network/{{ item }}" - state: absent - with_items: - - "ifcfg-eth0" - - "ifroute-eth0" - - name: Configure networking on SUSE template: src: "{{ ansible_os_family | lower }}/suse.interface.j2" dest: "/etc/sysconfig/network/ifcfg-{{ item.name }}" with_items: - - { name: "{{ ansible_default_ipv4.interface }}" } - - { name: "{{ ansible_default_ipv4.interface }}.10", vlan_id: 10 } - - { name: "{{ ansible_default_ipv4.interface }}.30", vlan_id: 30 } - - { name: "{{ ansible_default_ipv4.interface }}.20", vlan_id: 20 } - - { name: "br-mgmt", bridge_ports: "{{ ansible_default_ipv4.interface }}.10", ip: "{{ host_info[inventory_hostname].MGMT_IP }}/22" } - - { name: "br-vxlan", bridge_ports: "{{ ansible_default_ipv4.interface }}.30", ip: "{{ host_info[inventory_hostname].VXLAN_IP }}/22" } - - { name: "br-vlan", bridge_ports: "{{ ansible_default_ipv4.interface }}", ip: "{{ host_info[inventory_hostname].VLAN_IP }}/24" } - - { name: "br-storage", bridge_ports: "{{ ansible_default_ipv4.interface }}.20", ip: "{{ host_info[inventory_hostname].STORAGE_IP }}/22" } + - { name: "{{ ansible_local.xci.network.xci_interface }}" } + - { name: "{{ ansible_local.xci.network.xci_interface }}.10", vlan_id: 10 } + - { name: "{{ ansible_local.xci.network.xci_interface }}.30", vlan_id: 30 } + - { name: "{{ ansible_local.xci.network.xci_interface }}.20", vlan_id: 20 } + - { name: "br-mgmt", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.10", ip: "{{ host_info[inventory_hostname].MGMT_IP }}/22" } + - { name: "br-vxlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.30", ip: "{{ host_info[inventory_hostname].VXLAN_IP }}/22" } + - { name: "br-vlan", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}", ip: "{{ host_info[inventory_hostname].VLAN_IP }}/24" } + - { name: "br-storage", bridge_ports: "{{ ansible_local.xci.network.xci_interface }}.20", ip: "{{ host_info[inventory_hostname].STORAGE_IP }}/22" } - name: Add postup/postdown scripts on SUSE copy: @@ -102,10 +119,10 @@ src: "{{ ansible_os_family | lower }}/interface.ifcfg.j2" dest: "/etc/sysconfig/network-scripts/ifcfg-{{ item.name }}" with_items: - - { name: "{{ ansible_default_ipv4.interface }}" , bridge: "br-vlan" } - - { name: "{{ ansible_default_ipv4.interface }}.10", bridge: "br-mgmt" , vlan_id: 10 } - - { name: "{{ ansible_default_ipv4.interface }}.20", bridge: "br-storage", vlan_id: 20 } - - { name: "{{ ansible_default_ipv4.interface }}.30", bridge: "br-vxlan" , vlan_id: 30 } + - { name: "{{ ansible_local.xci.network.xci_interface }}" , bridge: "br-vlan" } + - { name: "{{ ansible_local.xci.network.xci_interface }}.10", bridge: "br-mgmt" , vlan_id: 10 } + - { name: "{{ ansible_local.xci.network.xci_interface }}.20", bridge: "br-storage", vlan_id: 20 } + - { name: "{{ ansible_local.xci.network.xci_interface }}.30", bridge: "br-vxlan" , vlan_id: 30 } - name: Configure networking on CentOS for bridges template: src: "{{ ansible_os_family | lower }}/bridge.ifcfg.j2" -- cgit