bifrost/playbooks/roles/ironic-install/tasks/main.yml

280 lines
14 KiB
YAML

# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
#
# 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: "Update Package Cache"
apt: update_cache=yes
- name: "Install packages"
apt: name={{ item }}
with_items: required_packages_ubuntu
# Step required for Ubuntu 14.10
- name: "Install 14.10 packages"
apt: name={{ item }}
with_items:
- pxelinux
when: ansible_distribution_version|version_compare('14.10', '>=')
- name: "Install testing packages"
apt: name={{ item }}
when: testing is defined and testing == true
with_items:
- libvirt-bin
- qemu-kvm
- sgabios
- name: "Ensuring /opt/stack is present"
file: name=/opt/stack state=directory owner=root group=root
- name: "Downloading Ironic"
command: git clone https://git.openstack.org/openstack/ironic chdir=/opt/stack creates=/opt/stack/ironic
- name: "Ironic - checking out master branch"
command: git checkout -f master chdir=/opt/stack/ironic
- name: "Ironic - resetting master branch"
command: git reset --hard master chdir=/opt/stack/ironic
- name: "Ironic - resyncing to current master branch"
command: git pull --ff-only chdir=/opt/stack/ironic/
- name: "Ironic - Apply CI changes if necessary"
script: parse_zuul_changes.py /opt/stack/ironic https://review.openstack.org openstack/ironic "{{ lookup('env', 'ZUUL_CHANGES') }}"
when: ci_testing == true
- name: "Ironic Client - Install from source if configured to do so."
include: ironicclient_source_install.yml
when: skip_install is not defined and ((ironicclient_source_install is defined and ironicclient_source_install == true) or ci_testing == true)
- name: "Ironic Client - Install from pip"
pip: name=python-ironicclient state=present
when: skip_install is not defined and (ironicclient_source_install is not defined or ironicclient_source_install == false) and (ci_testing == false)
- name: "proliantutils - Install from pip"
pip: name=proliantutils state=present
when: skip_install is not defined
- name: "Shade - Install from source if configured to do so"
include: shade_source_install.yml
when: skip_install is not defined and ((shade_source_install is defined and shade_source_install == true) or ci_testing == true)
- name: "Shade - Installing patched shade library."
pip: name=shade state=latest
when: skip_install is not defined and (shade_source_install is not defined or shade_source_install == false) and (ci_testing == false)
- name: "dib-utils - install from pip"
pip: name=dib-utils state=present
when: skip_install is not defined and create_image_via_dib == true
- name: "Include diskimage-builder installation"
include: dib_install.yml
when: create_image_via_dib == true
- name: "Starting MySQL"
service: name=mysql state=started
- name: "Starting rabbitmq-server"
service: name=rabbitmq-server state=started
- name: "RabbitMQ - Testing if hostname is defined firsts in /etc/hosts"
command: grep -i "127.0.0.1*.{{ ansible_hostname }}\ localhost" /etc/hosts
ignore_errors: yes
register: test_grep_fix_hostname
- name: "RabbitMQ - Fixing /etc/hosts"
command: sed -i 's/localhost/{{ ansible_hostname }} localhost/' /etc/hosts
when: test_grep_fix_hostname.rc != 0
- name: "Ensuring guest user is removed from rabbitmq"
rabbitmq_user: user=guest state=absent force=yes
- name: "Creating Ironic user in RabbitMQ"
rabbitmq_user: user=ironic password={{ ironic_db_password }} force=yes state=present configure_priv=.* write_priv=.* read_priv=.*
no_log: true
- name: "MySQL - Creating DB"
mysql_db: login_user=root login_password={{ mysql_password }} name=ironic state=present encoding=utf8
register: test_created_db
when: ci_testing_zuul is not defined
- name: "MySQL - Creating user for Ironic"
mysql_user: login_user=root login_password={{ mysql_password }} name=ironic password={{ ironic_db_password }} priv=ironic.*:ALL state=present
when: ci_testing_zuul is not defined
- name: "MySQL - Creating DB - OpenStack CI"
mysql_db: login_user=openstack_citest login_password=openstack_citest name=ironic state=present encoding=utf8
register: test_created_db
when: ci_testing_zuul is defined
- name: "MySQL - Creating user for Ironic - OpenStack CI"
mysql_user: login_user=openstack_citest login_password=openstack_citest name=ironic password={{ ironic_db_password }} priv=ironic.*:ALL state=present
when: ci_testing_zuul is defined
- name: "Install Ironic using pip"
pip: name=/opt/stack/ironic state=latest
when: skip_install is not defined
- name: "Ensure /etc/ironic exists"
file: name=/etc/ironic state=directory
- name: "Place Ironic Config file"
template: src=ironic.conf.j2 dest=/etc/ironic/ironic.conf
- name: "Place Ironic IPA Agent PXE configuration file"
template: src=agent_config.template.j2 dest=/etc/ironic/agent_config.template
- name: "Copy policy.json to /etc/ironic"
copy: src=/opt/stack/ironic/etc/ironic/policy.json dest=/etc/ironic/
- name: "Creating Ironic DB Schema"
command: ironic-dbsync --config-file /etc/ironic/ironic.conf create_schema
when: test_created_db.changed == true
- name: "Upgrading Ironic DB Schema"
command: ironic-dbsync --config-file /etc/ironic/ironic.conf upgrade
when: test_created_db.changed == false
- name: "Creating an ironic service group"
group: name=ironic
- name: "Creating an ironic service user"
user: name=ironic group=ironic
- name: "Adding ironic user to libvirtd group"
user: name=ironic group=libvirtd append=yes
when: testing == true
- name: "Creating SSH directory for ironic user"
local_action: file path=/home/ironic/.ssh owner=ironic group=ironic mode=0700 state=directory
when: testing == true
- name: "Checking for ironic user SSH key"
local_action: stat path=/home/ironic/.ssh/id_rsa
register: test_ironic_pvt_key
- name: "Generating SSH key for ironic user"
local_action: command ssh-keygen -f /home/ironic/.ssh/id_rsa -N ""
when: testing == true and test_ironic_pvt_key.stat.exists == false
- name: "Setting ownership on ironic SSH private key"
local_action: file name=/home/ironic/.ssh/id_rsa owner=ironic group=ironic mode=0600 state=file
when: testing == true and test_ironic_pvt_key.stat.exists == false
- name: "Setting ownership on ironic SSH public key"
local_action: file name=/home/ironic/.ssh/id_rsa.pub owner=ironic group=ironic mode=0644 state=file
when: testing == true and test_ironic_pvt_key.stat.exists == false
- name: "Creating authorized_keys file for ironic user"
command: cp -p /home/ironic/.ssh/id_rsa.pub /home/ironic/.ssh/authorized_keys
when: testing == true
- name: "Placing services"
template: src=init_template.j2 dest=/etc/init/{{item.service_name}}.conf owner=root group=root
with_items:
- { service_name: 'ironic-api', username: 'ironic', args: '--config-file /etc/ironic/ironic.conf'}
- { service_name: 'ironic-conductor', username: 'ironic', args: '--config-file /etc/ironic/ironic.conf'}
- name: "Start ironic-conductor"
service: name=ironic-conductor state=started
- name: "Start ironic-api"
service: name=ironic-api state=started
- name: "Start ironic-conductor"
service: name=ironic-conductor state=restarted
- name: "Start ironic-api"
service: name=ironic-api state=reloaded
- name: "Setting up PXE and iPXE folders"
file: name={{item}} owner=ironic group=ironic state=directory
with_items:
- /tftpboot
- /tftpboot/pxelinux.cfg
- "{{ http_boot_folder }}"
- name: "Placing tftpd map-file"
copy: src=tftpboot-map-file dest=/tftpboot/map-file owner=ironic group=ironic
- name: "Disable service tftpd-hpa"
service: name=tftpd-hpa state=stopped enabled=no
- name: "Placing pxelinux.0 (pre-14.10)"
copy: src=/usr/lib/syslinux/pxelinux.0 dest=/tftpboot
when: ansible_distribution_version|version_compare('14.10', '<')
- name: "Placing pxelinux.0 (>=14.10)"
copy: src=/usr/lib/PXELINUX/pxelinux.0 dest=/tftpboot
when: ansible_distribution_version|version_compare('14.10', '>=')
- name: "Place boot.ipxe helper script to HTTP root"
copy: src=boot.ipxe dest=/httpboot/boot.ipxe
- name: "Place tftp config file"
copy: src=xinetd.tftp dest=/etc/xinetd.d/tftp
- name: "Copy iPXE image into place"
copy: src=/usr/lib/ipxe/undionly.kpxe dest=/tftpboot/
- name: "Deploy dnsmasq configuration file"
template: src=dnsmasq.conf.j2 dest=/etc/dnsmasq.conf
when: include_dhcp_server == true or '"true" in include_dhcp_server'
# NOTE(Shrews) When testing, we want to use our custom dnsmasq.conf file,
# not the one supplied by libvirt. And the libvirt started dnsmasq processes
# are not controlled by upstart, so we need to manually kill those.
- name: "Looking for libvirt dnsmasq config"
stat: path=/etc/dnsmasq.d/libvirt-bin
register: test_libvirt_dnsmasq
when: include_dhcp_server == true or '"true" in include_dhcp_server'
- name: "Disabling libvirt dnsmasq config"
command: mv /etc/dnsmasq.d/libvirt-bin /etc/dnsmasq.d/libvirt-bin~
when: (include_dhcp_server == true or '"true" in include_dhcp_server') and test_libvirt_dnsmasq.stat.exists == true and testing == true
- name: "Stopping existing libvirt dnsmasq processes"
command: killall -w dnsmasq
when: testing == true and (include_dhcp_server == true or '"true" in include_dhcp_server')
# NOTE(Shrews) We need to enable ip forwarding for the libvirt bridge to
# operate properly with dnsmasq. This should be done before starting dnsmasq.
- name: "Enabling IP forwarding in sysctl"
sysctl: name="net.ipv4.ip_forward" value=1 sysctl_set=yes state=present reload=yes
when: testing == true
# NOTE(Shrews) Ubuntu packaging+apparmor issue prevents libvirt from loading
# the ROM from /usr/share/misc.
- name: "Looking for sgabios in /usr/share/qemu"
stat: path=/usr/share/qemu/sgabios.bin
register: test_sgabios_qemu
- name: "Looking for sgabios in /usr/share/misc"
stat: path=/usr/share/misc/sgabios.bin
register: test_sgabios_misc
- name: "Place sgabios.bin"
command: cp /usr/share/misc/sgabios.bin /usr/share/qemu/sgabios.bin
when: test_sgabios_qemu == false and test_sgabios_misc == true and testing == true
- name: "Deploying nginx configuration file for serving HTTP requests"
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
- name: "Ensuring services are running with current config"
service: name={{ item }} state=restarted
with_items:
- xinetd
- nginx
- name: "Ensuring dnsmasq is running with current config"
service: name={{ item }} state=restarted
with_items:
- dnsmasq
when: include_dhcp_server == true or '"true" in include_dhcp_server'
- name: "Sending services a reload signal"
service: name={{ item }} state=reloaded
with_items:
- xinetd
- nginx
- name: "Sending services a force-reload signal"
command: /etc/init.d/dnsmasq force-reload
when: include_dhcp_server == true or '"true" in include_dhcp_server'
# Similar logic to below can be utilized to retrieve files
- name: "Determine if folder exists, else create and populate folder."
stat: path=/tftpboot/master_images
register: test_master_images
- name: "Create master_images folder"
file: name=/tftpboot/master_images state=directory owner=ironic group=ironic
when: test_master_images.stat.exists == false
# This is overly complex, however get_url will always re-retrieve the file
# if it already exists, and this is to prevent that behavior.
- name: "Test if CoreOS kernel is present"
stat: path={{ http_boot_folder }}/coreos_production_pxe.vmlinuz
register: test_core_os_kernel_present
- name: "Download CoreOS kernel"
get_url: url=http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe.vmlinuz dest={{ http_boot_folder }}/coreos_production_pxe.vmlinuz
when: test_core_os_kernel_present.stat.exists == false
- name: "Test if CoreOS image is present"
stat: path={{ http_boot_folder }}/coreos_production_pxe_image-oem.cpio.gz
register: test_core_os_image_present
- name: "Download CoreOS image"
get_url: url=http://tarballs.openstack.org/ironic-python-agent/coreos/files/coreos_production_pxe_image-oem.cpio.gz dest={{ http_boot_folder }}/coreos_production_pxe_image-oem.cpio.gz
when: test_core_os_image_present.stat.exists == false
- name: "Download cirros to use for deployment if requested"
get_url: url=http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-x86_64-disk.img dest="{{deploy_image}}"
# TODO(TheJulia): We may want to revise any boolean operators to
# comparison statements like the one below when they are able to be
# set via the command line as there are oddities across ansible
# versions with auto-translation of true/false values.
when: use_cirros == true or "'true' in use_cirros"
- name: "Test if Ubuntu 14.04 server cloud amd64 is present"
stat: path={{ deploy_image }}
register: test_os_image_present
- name: "Download Ubuntu image"
get_url: url=http://cloud-images.ubuntu.com/releases/trusty/release/ubuntu-14.04-server-cloudimg-amd64.tar.gz dest=/httpboot/ubuntu-14.04-server-cloudimg-amd64.tar.gz
when: test_os_image_present.stat.exists == false and create_image_via_dib == false
- name: "Extract Ubuntu image"
unarchive: src=/httpboot/ubuntu-14.04-server-cloudimg-amd64.tar.gz dest=/httpboot/ creates=/httpboot/trusty-server-cloudimg-amd64.img
when: test_os_image_present.stat.exists == false and create_image_via_dib == false
# Create bootable image takes a partition image, prepends space for a
# bootloader, partition table, and then installs the bootloader.
#
# If attempting to utilize a base Ubuntu image, diskimage-builder
# is the recommended, and default path.
- name: "Creating bootable image"
include: create_bootable_image.yml
when: test_os_image_present.stat.exists == false and transform_boot_image == true and create_image_via_dib == false
# DIB is presently the default path.
- name: "Creating image via disk image builder"
include: create_dib_image.yml
when: test_os_image_present.stat.exists == false and transform_boot_image == false and create_image_via_dib == true
- name: "Explicitly permit nginx port (TCP) for file downloads from nodes to be provisioned"
command: iptables -I INPUT -p tcp --dport {{nginx_port}} -i {{network_interface}} -j ACCEPT
- name: "Explicitly permit TCP/6385 for IPA callback"
command: iptables -I INPUT -p tcp --dport 6385 -i {{network_interface}} -j ACCEPT