
Modifying the public zone is questionable, let's use our own zone. Also let's make sure network_interface actually belongs to it. Change-Id: I63f5fa4845aa8f1c90a0c73dd78deb45aaaa4fd1
423 lines
14 KiB
YAML
423 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: "Fail if authentication configuration conflicts."
|
|
fail:
|
|
msg: >
|
|
noauth_mode and enable_keystone are mutually exclusive options.
|
|
Please set one to "false".
|
|
when: >
|
|
noauth_mode | bool == true and enable_keystone is defined and
|
|
enable_keystone | bool == true
|
|
|
|
- name: "Setup firewalld"
|
|
include_tasks: setup_firewalld.yml
|
|
when: ansible_distribution in ["CentOS", "RedHat"]
|
|
|
|
# NOTE(sean-k-mooney) only the RabbitMQ server and MySQL db are started
|
|
# during bootstrapping. all other services are started in the Start phase.
|
|
- name: "Start database service"
|
|
service: name={{ mysql_service_name }} state=started enabled=yes
|
|
when: ironic.database.host == 'localhost'
|
|
|
|
- name: "Create 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
|
|
when: use_rabbitmq
|
|
|
|
- name: "Set mysql_username if environment variable mysql_user is set"
|
|
set_fact:
|
|
mysql_username: "{{ lookup('env', 'mysql_user') }}"
|
|
when: lookup('env', 'mysql_user') | length > 0
|
|
no_log: true
|
|
|
|
- name: "Set mysql_password if environment variable mysql_pass is set"
|
|
set_fact:
|
|
mysql_password: "{{ lookup('env', 'mysql_pass') }}"
|
|
when: lookup('env', 'mysql_pass') | length > 0
|
|
no_log: true
|
|
|
|
- name: "Set MySQL socket fact for Red Hat family"
|
|
set_fact:
|
|
mysql_socket_path: "/var/lib/mysql/mysql.sock"
|
|
when: ansible_os_family | lower == 'redhat'
|
|
|
|
- name: "Set MySQL socket fact for Debian family"
|
|
set_fact:
|
|
mysql_socket_path: "/var/run/mysqld/mysqld.sock"
|
|
when: ansible_os_family | lower == 'debian'
|
|
|
|
- name: "Set MySQL socket fact for other systems"
|
|
set_fact:
|
|
mysql_socket_path: "/var/run/mysql/mysql.sock"
|
|
when: (ansible_os_family | lower) not in ['redhat', 'debian']
|
|
|
|
- name: "MySQL - Creating DB"
|
|
mysql_db:
|
|
login_unix_socket: "{{ mysql_socket_path | default(omit) }}"
|
|
name: "{{ ironic.database.name }}"
|
|
state: present
|
|
encoding: utf8
|
|
login_user: "{{ mysql_username | default(None) }}"
|
|
login_password: "{{ mysql_password | default(None) }}"
|
|
register: test_created_db
|
|
when: ironic.database.host == 'localhost'
|
|
|
|
- name: "MySQL - Creating user for Ironic"
|
|
mysql_user:
|
|
login_unix_socket: "{{ mysql_socket_path | default(omit) }}"
|
|
name: "{{ ironic.database.username }}"
|
|
password: "{{ ironic.database.password }}"
|
|
priv: "{{ ironic.database.name }}.*:ALL"
|
|
state: present
|
|
login_user: "{{ mysql_username | default(None) }}"
|
|
login_password: "{{ mysql_password | default(None) }}"
|
|
when: ironic.database.host == 'localhost'
|
|
|
|
- name: "Create an ironic service group"
|
|
group:
|
|
name: "ironic"
|
|
- name: "Create an ironic service user"
|
|
user:
|
|
name: "ironic"
|
|
group: "ironic"
|
|
- name: "Ensure /etc/ironic exists"
|
|
file:
|
|
name: "/etc/ironic"
|
|
state: directory
|
|
owner: "ironic"
|
|
group: "ironic"
|
|
mode: 0755
|
|
# Note(TheJulia): The rootwrap copies will need to be re-tooled
|
|
# to possibly directly retreive current files if a source install
|
|
# is not utilized.
|
|
- name: "Copy rootwrap.conf from ironic source folder"
|
|
copy:
|
|
src: "{{ ironic_git_folder }}/etc/ironic/rootwrap.conf"
|
|
dest: "/etc/ironic/rootwrap.conf"
|
|
remote_src: yes
|
|
mode: 0644
|
|
owner: root
|
|
group: root
|
|
when: not skip_install | bool
|
|
# Note(ashestakov): "copy" module in ansible doesn't support recursive
|
|
# copying on remote host. "cp" command used instead.
|
|
- name: "Copy rootwrap.d contents from ironic source folder"
|
|
command: cp -r "{{ ironic_git_folder }}/etc/ironic/rootwrap.d/" "/etc/ironic/rootwrap.d"
|
|
when: not skip_install | bool
|
|
|
|
- name: "Generate admin htpasswd for ironic"
|
|
htpasswd:
|
|
path: /etc/ironic/htpasswd
|
|
crypt_scheme: bcrypt
|
|
name: "{{ admin_username }}"
|
|
password: "{{ admin_password }}"
|
|
when:
|
|
- not enable_keystone | bool
|
|
|
|
- name: "Generate user htpasswd for ironic"
|
|
htpasswd:
|
|
path: /etc/ironic/htpasswd
|
|
crypt_scheme: bcrypt
|
|
name: "{{ default_username }}"
|
|
password: "{{ default_password }}"
|
|
when:
|
|
- not noauth_mode | bool
|
|
- not enable_keystone | bool
|
|
|
|
- name: "Populate keystone for Bifrost"
|
|
include: keystone_setup.yml
|
|
when: enable_keystone is defined and enable_keystone | bool == true
|
|
|
|
# NOTE(pas-ha) needed to e.g. pick up new interfaces after libvirt install
|
|
- name: "Refresh facts"
|
|
setup:
|
|
gather_timeout: "{{ fact_gather_timeout }}"
|
|
|
|
- name: "Generate ironic Configuration"
|
|
include: ironic_config.yml
|
|
|
|
- name: "Create the log directories (if requested)"
|
|
file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
mode: 0700
|
|
owner: "ironic"
|
|
group: "ironic"
|
|
loop:
|
|
- "{{ ironic_log_dir | default('') }}"
|
|
- "{{ ironic_agent_deploy_logs_local_path | default('') }}"
|
|
when: item | length > 0
|
|
|
|
- name: "Create ironic DB Schema"
|
|
command: ironic-dbsync --config-file /etc/ironic/ironic.conf create_schema
|
|
environment: "{{ bifrost_venv_env }}"
|
|
when: >
|
|
ironic.database.host == 'localhost' and
|
|
test_created_db.changed | bool == true
|
|
|
|
- name: "Upgrade ironic DB Schema"
|
|
command: ironic-dbsync --config-file /etc/ironic/ironic.conf upgrade
|
|
environment: "{{ bifrost_venv_env }}"
|
|
when: >
|
|
ironic.database.host != 'localhost' or
|
|
test_created_db.changed | bool == false
|
|
|
|
- name: "Create service folder"
|
|
file:
|
|
path: "{{ init_dest_dir }}"
|
|
state: directory
|
|
mode: 0755
|
|
|
|
- name: "Install ironic-inspector to permit use of inspection interface"
|
|
include: inspector_bootstrap.yml
|
|
when: enable_inspector | bool == true
|
|
|
|
- name: "Get ironic-api & ironic-conductor install location"
|
|
shell: echo $(dirname $(which ironic-api))
|
|
register: ironic_install_prefix
|
|
environment: "{{ bifrost_venv_env }}"
|
|
|
|
- name: "Set permissions for /var/lib/ironic for the ironic user"
|
|
file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
mode: 0750
|
|
owner: "ironic"
|
|
group: "{{ nginx_user }}"
|
|
loop:
|
|
- "/var/lib/ironic"
|
|
- "/var/lib/ironic/master_images"
|
|
- "/var/lib/ironic/images"
|
|
|
|
- name: "Place ironic services"
|
|
template:
|
|
src: systemd_template.j2
|
|
dest: "{{ init_dest_dir }}{{ item.service_name }}.service"
|
|
owner: "root"
|
|
group: "root"
|
|
loop:
|
|
- service_path: "{{ ironic_install_prefix.stdout | default('') }}"
|
|
service_name: 'ironic-api'
|
|
username: 'ironic'
|
|
args: '--config-file /etc/ironic/ironic.conf'
|
|
- service_path: "{{ ironic_install_prefix.stdout | default('') }}"
|
|
service_name: 'ironic-conductor'
|
|
username: 'ironic'
|
|
args: '--config-file /etc/ironic/ironic.conf'
|
|
|
|
- name: "Create and populate /tftpboot"
|
|
include: create_tftpboot.yml
|
|
- name: "Setup Inventory Hosts Directory"
|
|
file:
|
|
path: "/etc/dnsmasq.d/bifrost.hosts.d"
|
|
state: directory
|
|
owner: "root"
|
|
group: "root"
|
|
mode: 0755
|
|
when: inventory_dhcp | bool == true
|
|
- name: "Setup Inventory DHCP Hosts Directory"
|
|
file:
|
|
path: "/etc/dnsmasq.d/bifrost.dhcp-hosts.d"
|
|
state: directory
|
|
owner: "root"
|
|
group: "root"
|
|
mode: 0755
|
|
when: inventory_dhcp | bool == true
|
|
- name: "Retrieve interface IP informations"
|
|
set_fact:
|
|
itf_infos: "{{ internal_interface }}"
|
|
dhcp_netaddr: "{{ dhcp_pool_start }}/{{ dhcp_static_mask }}"
|
|
when: include_dhcp_server | bool == true
|
|
- name: "Compute interface and DHCP network informations"
|
|
set_fact:
|
|
itf_netaddr1: "{{ itf_infos['address'] }}/{{ itf_infos['netmask'] }}"
|
|
itf_netaddr2: "{{ itf_infos['network'] }}/{{ itf_infos['netmask'] }}"
|
|
itf_broadcast: "{{ itf_infos['broadcast'] }}/{{ itf_infos['netmask'] }}"
|
|
dhcp_netaddr: "{{ dhcp_netaddr | ipaddr('network') }}/{{ dhcp_static_mask }}"
|
|
when: include_dhcp_server | bool == true
|
|
- name: "Validate interface network addresses"
|
|
fail:
|
|
msg: >
|
|
Interface {{ ans_network_interface }} network incoherence
|
|
{{ itf_netaddr1 | ipaddr('network') }}/{{ itf_netaddr1 | ipaddr('prefix') }}
|
|
vs {{ itf_netaddr2 }}/{{ itf_netaddr2 | ipaddr('prefix') }}
|
|
when:
|
|
- include_dhcp_server | bool
|
|
- itf_netaddr1 | ipaddr('network') != itf_netaddr2 | ipaddr('network')
|
|
- name: "Validate interface broadcast addresses"
|
|
fail:
|
|
msg: >
|
|
Interface {{ ans_network_interface }} broadcast incoherence
|
|
{{ itf_netaddr1 | ipaddr('broadcast') }}/{{ itf_netaddr1 | ipaddr('prefix') }}
|
|
vs {{ itf_broadcast | ipaddr('broadcast') }}/{{ itf_broadcast | ipaddr('prefix') }}
|
|
when:
|
|
- include_dhcp_server | bool
|
|
- itf_netaddr1 | ipaddr('broadcast') != itf_broadcast | ipaddr('broadcast')
|
|
- name: "Validate DHCP and interface addresses"
|
|
debug:
|
|
msg: >
|
|
Interface {{ ans_network_interface }} and DHCP networks are incoherent
|
|
{{ itf_netaddr2 | ipaddr('network') }}/{{ itf_netaddr2 | ipaddr('prefix') }}
|
|
{{ dhcp_netaddr | ipaddr('network') }}/{{ dhcp_netaddr | ipaddr('prefix') }}
|
|
overriding DHCP with interface settings"
|
|
when:
|
|
- include_dhcp_server | bool
|
|
- itf_netaddr2 | ipaddr('network') != dhcp_netaddr | ipaddr('network')
|
|
- name: "Computing new DHCP informations"
|
|
set_fact:
|
|
dhcp_start_ip: "{{ dhcp_pool_start.split('.')[-1] }}"
|
|
dhcp_end_ip: "{{ dhcp_pool_end.split('.')[-1] }}"
|
|
dhcp_netaddr: "{{ itf_netaddr1 | ipaddr('network') }}"
|
|
when:
|
|
- include_dhcp_server | bool == true
|
|
- itf_netaddr2 | ipaddr('network') != dhcp_netaddr | ipaddr('network')
|
|
# Note(olivierbourdon38): we could do much more complex network
|
|
# computation to derive exact (or way closer to exact) range for
|
|
# the new network depending on netmasks and indexes.
|
|
- name: "Computing new DHCP range"
|
|
set_fact:
|
|
dhcp_pool_start: "{{ '.'.join(dhcp_netaddr.split('.')[0:-1]) }}.{{ dhcp_start_ip }}"
|
|
dhcp_pool_end: "{{ '.'.join(dhcp_netaddr.split('.')[0:-1]) }}.{{ dhcp_end_ip }}"
|
|
when:
|
|
- include_dhcp_server | bool == true
|
|
- itf_netaddr2 | ipaddr('network') != dhcp_netaddr | ipaddr('network')
|
|
- name: "Deploy dnsmasq configuration file"
|
|
template: src=dnsmasq.conf.j2 dest=/etc/dnsmasq.conf
|
|
when: include_dhcp_server | bool == true
|
|
# NOTE(Shrews) When testing, we want to use our custom dnsmasq.conf file,
|
|
# not the one supplied by libvirt.
|
|
- name: "Look for libvirt dnsmasq config"
|
|
stat: path=/etc/dnsmasq.d/libvirt-bin
|
|
register: test_libvirt_dnsmasq
|
|
when: include_dhcp_server | bool == true
|
|
- name: "Disable libvirt dnsmasq config"
|
|
command: mv /etc/dnsmasq.d/libvirt-bin /etc/dnsmasq.d/libvirt-bin~
|
|
when: >
|
|
include_dhcp_server | bool == true and
|
|
test_libvirt_dnsmasq.stat.exists | bool == true and
|
|
testing | bool == true
|
|
- name: "Deploy nginx configuration file for serving HTTP requests"
|
|
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
|
|
- name: "Download Ironic Python Agent kernel & image"
|
|
include: download_ipa_image.yml
|
|
when: create_ipa_image | bool == false and download_ipa | bool == true
|
|
- name: "Download cirros to use for deployment if requested"
|
|
get_url:
|
|
url: "{{ cirros_deploy_image_upstream_url }}"
|
|
dest: "{{ deploy_image }}"
|
|
owner: ironic
|
|
group: ironic
|
|
mode: 0644
|
|
when: use_cirros | bool == true
|
|
- name: "Create a checksum file for cirros"
|
|
shell: md5sum {{ deploy_image_filename }} > {{ deploy_image_filename }}.CHECKSUMS
|
|
args:
|
|
chdir: "{{ http_boot_folder }}"
|
|
when: use_cirros | bool
|
|
- name: >
|
|
"Explicitly permit nginx port (TCP) for file downloads from nodes to be provisioned
|
|
and TCP/6385 for IPA callback"
|
|
iptables:
|
|
chain: INPUT
|
|
action: insert
|
|
protocol: tcp
|
|
destination_port: "{{ item }}"
|
|
in_interface: "{{ network_interface }}"
|
|
jump: ACCEPT
|
|
loop:
|
|
- "{{ file_url_port }}"
|
|
- 6385
|
|
when: ansible_distribution not in ["CentOS", "RedHat"]
|
|
|
|
- name: "Enable services in firewalld"
|
|
firewalld:
|
|
service: "{{ item }}"
|
|
zone: "{{ 'libvirt' if testing | bool else firewalld_internal_zone }}"
|
|
state: enabled
|
|
permanent: yes
|
|
immediate: yes
|
|
loop:
|
|
- dhcp
|
|
- dhcpv6
|
|
- tftp
|
|
when: ansible_distribution in ["CentOS", "RedHat"]
|
|
|
|
- name: "Enable ports in firewalld"
|
|
firewalld:
|
|
port: "{{ item }}/tcp"
|
|
zone: "{{ 'libvirt' if testing | bool else firewalld_internal_zone }}"
|
|
state: enabled
|
|
permanent: yes
|
|
immediate: yes
|
|
loop:
|
|
- "{{ file_url_port }}"
|
|
- 6385
|
|
when: ansible_distribution in ["CentOS", "RedHat"]
|
|
|
|
- block:
|
|
- name: "Explicitly allow nginx and IPA port (TCP) on selinux"
|
|
seport:
|
|
ports: "{{ file_url_port }},6385"
|
|
proto: tcp
|
|
setype: http_port_t
|
|
state: present
|
|
|
|
- name: "Add proper context on created data for tftpboot"
|
|
sefcontext:
|
|
target: "{{ item }}"
|
|
setype: tftpdir_t
|
|
state: present
|
|
loop:
|
|
- /tftpboot
|
|
- /tftpboot/pxelinux.cfg
|
|
|
|
- name: "Add proper context on created data for http_boot"
|
|
sefcontext:
|
|
target: "{{ http_boot_folder }}(/.*)?"
|
|
setype: httpd_sys_content_t
|
|
state: present
|
|
|
|
- name: Copy ironic policy file to temporary directory
|
|
copy:
|
|
src: ironic_policy.te
|
|
dest: /tmp/ironic_policy.te
|
|
|
|
- name: Check ironic policy module
|
|
command: checkmodule -M -m -o /tmp/ironic_policy.mod /tmp/ironic_policy.te
|
|
|
|
- name: Package ironic policy module
|
|
command: semodule_package -m /tmp/ironic_policy.mod -o /tmp/ironic_policy.pp
|
|
|
|
- name: Include ironic policy module
|
|
command: semodule -i /tmp/ironic_policy.pp
|
|
|
|
- name: Enable ironic policy module
|
|
command: semodule -e ironic_policy
|
|
when: (ansible_os_family == 'RedHat' or ansible_os_family == 'Suse') and
|
|
ansible_selinux.status == 'enabled' and ansible_selinux.mode == "enforcing"
|
|
- name: "Configure remote logging"
|
|
template: src=10-rsyslog-remote.conf.j2 dest=/etc/rsyslog.d/10-rsyslog-remote.conf
|
|
when:
|
|
- remote_syslog_server is defined
|
|
- remote_syslog_server | length > 0
|