diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml index a7f7c408e4..3f3072d1ca 100644 --- a/ansible/group_vars/all.yml +++ b/ansible/group_vars/all.yml @@ -104,6 +104,9 @@ heat_api_cfn_port: "8000" murano_api_port: "8082" +ironic_api_port: "6385" + + #################### # Openstack options #################### @@ -146,7 +149,9 @@ enable_heat: "yes" enable_horizon: "yes" enable_swift: "no" enable_murano: "no" +enable_ironic: "no" +ironic_keystone_user: "ironic" #################### # RabbitMQ options diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one index d820c3e606..ab6eceeb27 100644 --- a/ansible/inventory/all-in-one +++ b/ansible/inventory/all-in-one @@ -60,6 +60,8 @@ control [ceph-osd:children] storage +[ironic:children] +control # Additional control implemented here. These groups allow you to control which # services run on which hosts at a per-service level. @@ -140,3 +142,16 @@ murano [murano-engine:children] murano + +# Ironic +[ironic-api:children] +ironic + +[ironic-conductor:children] +ironic + +[ironic-discoverd:children] +ironic + +[ironic-pxe:children] +ironic diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode index e677fcaeff..cc643be11e 100644 --- a/ansible/inventory/multinode +++ b/ansible/inventory/multinode @@ -62,6 +62,9 @@ control [murano:children] control +[ironic:children] +control + [ceph-mon:children] control @@ -148,3 +151,16 @@ murano [murano-engine:children] murano + +# Ironic +[ironic-api:children] +ironic + +[ironic-conductor:children] +ironic + +[ironic-discoverd:children] +ironic + +[ironic-pxe:children] +ironic diff --git a/ansible/roles/haproxy/templates/haproxy.cfg.j2 b/ansible/roles/haproxy/templates/haproxy.cfg.j2 index 637cb1ce1d..0c8d59c912 100644 --- a/ansible/roles/haproxy/templates/haproxy.cfg.j2 +++ b/ansible/roles/haproxy/templates/haproxy.cfg.j2 @@ -141,3 +141,11 @@ listen heat_api_cfn server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + api_interface]['ipv4']['address'] }}:{{ heat_api_cfn_port }} check inter 2000 rise 2 fall 5 {% endfor %} {% endif %} + +{% if enable_ironic | bool %} +listen ironic_api + bind {{ kolla_internal_address}}:{{ ironic_api_port }} +{% for host in groups['ironic-api'] %} + server {{ hostvars[host]['ansible_hostname'] }} {{ hostvars[host]['ansible_' + api_interface]['ipv4']['address'] }}:{{ ironic_api_port }} check inter 2000 rise 2 fall 5 +{% endfor %} +{% endif %} diff --git a/ansible/roles/ironic/defaults/main.yml b/ansible/roles/ironic/defaults/main.yml new file mode 100644 index 0000000000..8a9ee32cda --- /dev/null +++ b/ansible/roles/ironic/defaults/main.yml @@ -0,0 +1,42 @@ +--- +project_name: "ironic" + +#################### +# Database +#################### +ironic_database_name: "ironic" +ironic_database_user: "ironic" +ironic_database_address: "{{ kolla_internal_address }}" + + +#################### +# Docker +#################### +ironic_api_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-ironic-api" +ironic_api_tag: "{{ openstack_release }}" +ironic_api_image_full: "{{ ironic_api_image }}:{{ ironic_api_tag }}" + +ironic_conductor_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-ironic-conductor" +ironic_conductor_tag: "{{ openstack_release }}" +ironic_conductor_image_full: "{{ ironic_conductor_image }}:{{ ironic_conductor_tag }}" + +ironic_discoverd_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-ironic-discoverd" +ironic_discoverd_tag: "{{ openstack_release }}" +ironic_discoverd_image_full: "{{ ironic_discoverd_image }}:{{ ironic_discoverd_tag }}" + +ironic_pxe_image: "{{ docker_registry ~ '/' if docker_registry else '' }}{{ docker_namespace }}/{{ kolla_base_distro }}-{{ kolla_install_type }}-ironic-pxe" +ironic_pxe_tag: "{{ openstack_release }}" +ironic_pxe_image_full: "{{ ironic_pxe_image }}:{{ ironic_pxe_tag }}" + + +#################### +# Openstack +#################### +ironic_public_address: "{{ kolla_external_address }}" +ironic_admin_address: "{{ kolla_internal_address }}" +ironic_internal_address: "{{ kolla_internal_address }}" + +ironic_logging_verbose: "{{ openstack_logging_verbose }}" +ironic_logging_debug: "{{ openstack_logging_debug }}" + +openstack_ironic_auth: "{'auth_url':'{{ openstack_auth_v2.auth_url }}','username':'{{ openstack_auth_v2.username }}','password':'{{ openstack_auth_v2.password }}','project_name':'{{ openstack_auth_v2.project_name }}'}" diff --git a/ansible/roles/ironic/meta/main.yml b/ansible/roles/ironic/meta/main.yml new file mode 100644 index 0000000000..6b4fff8fef --- /dev/null +++ b/ansible/roles/ironic/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: common } diff --git a/ansible/roles/ironic/tasks/bootstrap.yml b/ansible/roles/ironic/tasks/bootstrap.yml new file mode 100644 index 0000000000..2f99cf59fe --- /dev/null +++ b/ansible/roles/ironic/tasks/bootstrap.yml @@ -0,0 +1,64 @@ +--- +- name: Creating Ironic database + command: docker exec -t kolla_ansible /usr/bin/ansible localhost + -m mysql_db + -a "login_host='{{ database_address }}' + login_port='{{ mariadb_port }}' + login_user='{{ database_user }}' + login_password='{{ database_password }}' + name='{{ ironic_database_name }}'" + register: database + changed_when: "{{ database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}" + failed_when: database.stdout.split()[2] != 'SUCCESS' + run_once: True + +- name: Creating Ironic database user and setting permissions + command: docker exec -t kolla_ansible /usr/bin/ansible localhost + -m mysql_user + -a "login_host='{{ database_address }}' + login_port='{{ mariadb_port }}' + login_user='{{ database_user }}' + login_password='{{ database_password }}' + name='{{ ironic_database_name }}' + password='{{ ironic_database_password }}' + host='%' + priv='{{ ironic_database_name }}.*:ALL' + append_privs='yes'" + register: database_user_create + changed_when: "{{ database.stdout.find('localhost | SUCCESS => ') != -1 and (database_user_create.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}" + failed_when: database_user_create.stdout.split()[2] != 'SUCCESS' + run_once: True + +- name: Starting Ironic bootstrap container + docker: + detach: False + docker_api_version: "{{ docker_api_version }}" + net: host + pull: "{{ docker_pull_policy }}" + restart_policy: "no" + state: reloaded + registry: "{{ docker_registry }}" + username: "{{ docker_registry_username }}" + password: "{{ docker_registry_password }}" + insecure_registry: "{{ docker_insecure_registry }}" + name: bootstrap_ironic + image: "{{ ironic_api_image_full }}" + volumes: "{{ node_config_directory }}/ironic-api/:/opt/kolla/config_files/:ro" + env: + KOLLA_BOOTSTRAP: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + run_once: True + when: database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed + +# https://github.com/ansible/ansible-modules-core/pull/1031 +- name: Waiting for Ironic bootstrap container to exit + command: docker wait bootstrap_ironic + run_once: True + when: database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed + +- name: Cleaning up boostrap container + docker: + name: bootstrap_ironic + image: "{{ ironic_api_image_full }}" + state: absent + when: database.stdout.find('localhost | SUCCESS => ') != -1 and (database.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed diff --git a/ansible/roles/ironic/tasks/config.yml b/ansible/roles/ironic/tasks/config.yml new file mode 100644 index 0000000000..45a3f7ea5b --- /dev/null +++ b/ansible/roles/ironic/tasks/config.yml @@ -0,0 +1,78 @@ +--- +- include: ../../config.yml + vars: + service_name: "ironic-api" + config_source: + - "roles/ironic/templates/ironic.conf.j2" + - "/etc/kolla/config/global.conf" + - "/etc/kolla/config/database.conf" + - "/etc/kolla/config/messaging.conf" + - "/etc/kolla/config/{{ project_name }}.conf" + - "/etc/kolla/config/{{ project_name }}/{{ service_name }}.conf" + config_template_dest: + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_minimal" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_global" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_database" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_messaging" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_augment" + - "{{ node_templates_directory }}/{{ service_name }}/{{ service_name }}.conf_augment" + config_dest: "{{ node_config_directory }}/{{ service_name }}/ironic.conf" + when: inventory_hostname in groups['ironic-api'] + +- name: Copying Ironic API JSON configuration file + template: + src: "roles/ironic/templates/ironic-api.json.j2" + dest: "{{ node_config_directory }}/ironic-api/config.json" + +- include: ../../config.yml + vars: + service_name: "ironic-conductor" + config_source: + - "roles/ironic/templates/ironic.conf.j2" + - "/etc/kolla/config/global.conf" + - "/etc/kolla/config/database.conf" + - "/etc/kolla/config/messaging.conf" + - "/etc/kolla/config/{{ project_name }}.conf" + - "/etc/kolla/config/{{ project_name }}/{{ service_name }}.conf" + config_template_dest: + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_minimal" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_global" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_database" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_messaging" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_augment" + - "{{ node_templates_directory }}/{{ service_name }}/{{ service_name }}.conf_augment" + config_dest: "{{ node_config_directory }}/{{ service_name }}/ironic.conf" + when: inventory_hostname in groups['ironic-conductor'] + +- name: Copying Ironic conductor JSON configuration file + template: + src: "roles/ironic/templates/ironic-conductor.json.j2" + dest: "{{ node_config_directory }}/ironic-conductor/config.json" + +- include: ../../config.yml + vars: + service_name: "ironic-discoverd" + config_source: + - "roles/ironic/templates/discoverd.conf.j2" + - "/etc/kolla/config/global.conf" + - "/etc/kolla/config/database.conf" + - "/etc/kolla/config/messaging.conf" + - "/etc/kolla/config/{{ project_name }}/discoverd.conf" + config_template_dest: + - "{{ node_templates_directory }}/{{ service_name }}/discoverd.conf_minimal" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_global" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_database" + - "{{ node_templates_directory }}/{{ service_name }}/{{ project_name }}.conf_messaging" + - "{{ node_templates_directory }}/{{ service_name }}/discoverd.conf_augment" + config_dest: "{{ node_config_directory }}/{{ service_name }}/discoverd.conf" + when: inventory_hostname in groups['ironic-discoverd'] + +- name: Copying Ironic discoverd JSON configuration file + template: + src: "roles/ironic/templates/ironic-discoverd.json.j2" + dest: "{{ node_config_directory }}/ironic-discoverd/config.json" + +- name: Copying Ironic PXE JSON configuration file + template: + src: "roles/ironic/templates/ironic-pxe.json.j2" + dest: "{{ node_config_directory }}/ironic-pxe/config.json" diff --git a/ansible/roles/ironic/tasks/main.yml b/ansible/roles/ironic/tasks/main.yml new file mode 100644 index 0000000000..5c48120b7c --- /dev/null +++ b/ansible/roles/ironic/tasks/main.yml @@ -0,0 +1,8 @@ +--- +- include: register.yml + +- include: config.yml + +- include: bootstrap.yml + +- include: start.yml diff --git a/ansible/roles/ironic/tasks/register.yml b/ansible/roles/ironic/tasks/register.yml new file mode 100644 index 0000000000..ce44210f20 --- /dev/null +++ b/ansible/roles/ironic/tasks/register.yml @@ -0,0 +1,37 @@ +--- +- name: Creating the Ironic service and endpoint + command: docker exec -t kolla_ansible /usr/bin/ansible localhost + -m kolla_keystone_service + -a "service_name=ironic + service_type=baremetal + description='Ironic bare metal provisioning service' + endpoint_region={{ openstack_region_name }} + admin_url='http://{{ ironic_admin_address }}:{{ ironic_api_port }}' + internal_url='http://{{ ironic_internal_address }}:{{ ironic_api_port }}' + public_url='http://{{ ironic_public_address }}:{{ ironic_api_port }}' + region_name={{ openstack_region_name }} + auth={{ '{{ openstack_ironic_auth }}' }}" + -e "{'openstack_ironic_auth':{{ openstack_ironic_auth }}}" + register: ironic_endpoint + changed_when: "{{ ironic_endpoint.stdout.find('localhost | SUCCESS => ') != -1 and (ironic_endpoint.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}" + until: ironic_endpoint.stdout.split()[2] == 'SUCCESS' + retries: 10 + delay: 5 + run_once: True + +- name: Creating the Ironic project, user, and role + command: docker exec -t kolla_ansible /usr/bin/ansible localhost + -m kolla_keystone_user + -a "project=service + user=ironic + password={{ ironic_keystone_password }} + role=admin + region_name={{ openstack_region_name }} + auth={{ '{{ openstack_ironic_auth }}' }}" + -e "{'openstack_ironic_auth':{{ openstack_ironic_auth }}}" + register: ironic_user + changed_when: "{{ ironic_user.stdout.find('localhost | SUCCESS => ') != -1 and (ironic_user.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed }}" + until: ironic_user.stdout.split()[2] == 'SUCCESS' + retries: 10 + delay: 5 + run_once: True diff --git a/ansible/roles/ironic/tasks/start.yml b/ansible/roles/ironic/tasks/start.yml new file mode 100644 index 0000000000..4b6c5b4530 --- /dev/null +++ b/ansible/roles/ironic/tasks/start.yml @@ -0,0 +1,77 @@ +--- +- name: Starting Ironic-api container + docker: + docker_api_version: "{{ docker_api_version }}" + net: host + pull: "{{ docker_pull_policy }}" + restart_policy: "{{ docker_restart_policy }}" + restart_policy_retry: "{{ docker_restart_policy_retry }}" + state: reloaded + registry: "{{ docker_registry }}" + username: "{{ docker_registry_username }}" + password: "{{ docker_registry_password }}" + insecure_registry: "{{ docker_insecure_registry }}" + name: ironic-api + image: "{{ ironic_api_image_full }}" + volumes: "{{ node_config_directory }}/ironic-api/:/opt/kolla/config_files/:ro" + env: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + when: inventory_hostname in groups['ironic-api'] + +- name: Starting Ironic-conductor container + docker: + docker_api_version: "{{ docker_api_version }}" + net: host + pull: "{{ docker_pull_policy }}" + restart_policy: "{{ docker_restart_policy }}" + restart_policy_retry: "{{ docker_restart_policy_retry }}" + state: reloaded + registry: "{{ docker_registry }}" + username: "{{ docker_registry_username }}" + password: "{{ docker_registry_password }}" + insecure_registry: "{{ docker_insecure_registry }}" + name: ironic-conductor + image: "{{ ironic_conductor_image_full }}" + volumes: "{{ node_config_directory }}/ironic-conductor/:/opt/kolla/config_files/:ro" + env: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + when: inventory_hostname in groups['ironic-conductor'] + +- name: Starting Ironic-discoverd container + docker: + docker_api_version: "{{ docker_api_version }}" + net: host + pull: "{{ docker_pull_policy }}" + restart_policy: "{{ docker_restart_policy }}" + restart_policy_retry: "{{ docker_restart_policy_retry }}" + state: reloaded + registry: "{{ docker_registry }}" + username: "{{ docker_registry_username }}" + password: "{{ docker_registry_password }}" + insecure_registry: "{{ docker_insecure_registry }}" + privileged: True + name: ironic-discoverd + image: "{{ ironic_discoverd_image_full }}" + volumes: "{{ node_config_directory }}/ironic-discoverd/:/opt/kolla/config_files/:ro" + env: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + when: inventory_hostname in groups['ironic-discoverd'] + +- name: Starting Ironic-pxe container + docker: + docker_api_version: "{{ docker_api_version }}" + net: host + pull: "{{ docker_pull_policy }}" + restart_policy: "{{ docker_restart_policy }}" + restart_policy_retry: "{{ docker_restart_policy_retry }}" + state: reloaded + registry: "{{ docker_registry }}" + username: "{{ docker_registry_username }}" + password: "{{ docker_registry_password }}" + insecure_registry: "{{ docker_insecure_registry }}" + name: ironic-pxe + image: "{{ ironic_pxe_image_full }}" + volumes: "{{ node_config_directory }}/ironic-pxe/:/opt/kolla/config_files/:ro" + env: + KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" + when: inventory_hostname in groups['ironic-pxe'] diff --git a/ansible/roles/ironic/templates/discoverd.conf.j2 b/ansible/roles/ironic/templates/discoverd.conf.j2 new file mode 100644 index 0000000000..1f64d564ac --- /dev/null +++ b/ansible/roles/ironic/templates/discoverd.conf.j2 @@ -0,0 +1,11 @@ +[discoverd] +database = inspector.sqlite3 +os_auth_url = http://{{ kolla_internal_address }}:{{ keystone_public_port }}/v2.0 +os_username = {{ openstack_auth.username }} +os_password = {{ openstack_auth.password }} +os_tenant_name = {{ openstack_auth.project_name }} +identity_uri = {{ openstack_auth.auth_url }} + +# Note: this will be in the firewall section once upgraded to inspector +# unsure of the correct interface here +dnsmasq_interface = {{ api_interface }} diff --git a/ansible/roles/ironic/templates/ironic-api.json.j2 b/ansible/roles/ironic/templates/ironic-api.json.j2 new file mode 100644 index 0000000000..dd2caadf40 --- /dev/null +++ b/ansible/roles/ironic/templates/ironic-api.json.j2 @@ -0,0 +1,11 @@ +{ + "command": "/usr/bin/ironic-api", + "config_files": [ + { + "source": "/opt/kolla/config_files/ironic.conf", + "dest": "/etc/ironic/ironic.conf", + "owner": "ironic", + "perm": "0600" + } + ] +} diff --git a/ansible/roles/ironic/templates/ironic-conductor.json.j2 b/ansible/roles/ironic/templates/ironic-conductor.json.j2 new file mode 100644 index 0000000000..e77781c112 --- /dev/null +++ b/ansible/roles/ironic/templates/ironic-conductor.json.j2 @@ -0,0 +1,11 @@ +{ + "command": "/usr/bin/ironic-conductor", + "config_files": [ + { + "source": "/opt/kolla/config_files/ironic.conf", + "dest": "/etc/ironic/ironic.conf", + "owner": "ironic", + "perm": "0600" + } + ] +} diff --git a/ansible/roles/ironic/templates/ironic-discoverd.json.j2 b/ansible/roles/ironic/templates/ironic-discoverd.json.j2 new file mode 100644 index 0000000000..a4dc91d569 --- /dev/null +++ b/ansible/roles/ironic/templates/ironic-discoverd.json.j2 @@ -0,0 +1,11 @@ +{ + "command": "/usr/bin/ironic-discoverd --config-file /etc/ironic-discoverd/discoverd.conf", + "config_files": [ + { + "source": "/opt/kolla/config_files/discoverd.conf", + "dest": "/etc/ironic-discoverd/discoverd.conf", + "owner": "root", + "perm": "0600" + } + ] +} diff --git a/ansible/roles/ironic/templates/ironic-pxe.json.j2 b/ansible/roles/ironic/templates/ironic-pxe.json.j2 new file mode 100644 index 0000000000..f8f1666e7b --- /dev/null +++ b/ansible/roles/ironic/templates/ironic-pxe.json.j2 @@ -0,0 +1,4 @@ +{ + "command": "/usr/sbin/in.tftpd --verbose --foreground --user root --address 0.0.0.0:69 --map-file /tftpboot/map-file /tftpboot", + "config_files": [] +} diff --git a/ansible/roles/ironic/templates/ironic.conf.j2 b/ansible/roles/ironic/templates/ironic.conf.j2 new file mode 100644 index 0000000000..6860aee12d --- /dev/null +++ b/ansible/roles/ironic/templates/ironic.conf.j2 @@ -0,0 +1,30 @@ +[DEFAULT] +debug = {{ ironic_logging_debug }} +verbose = {{ ironic_logging_verbose }} + +admin_token = {{ keystone_admin_token }} + +[database] +connection = mysql://{{ ironic_database_user }}:{{ ironic_database_password }}@{{ ironic_database_address }}/{{ ironic_database_name }} + +[keystone_authtoken] +auth_uri = http://{{ kolla_internal_address }}:{{ keystone_public_port }} +auth_url = http://{{ kolla_internal_address }}:{{ keystone_admin_port }} +auth_plugin = password +project_domain_id = default +user_domain_id = default +project_name = service +username = {{ ironic_keystone_user }} +password = {{ ironic_keystone_password }} + +[glance] +glance_host = {{ kolla_internal_address }} + +[neutron] +url = http://{{ kolla_internal_address }}:{{ neutron_server_port }} + +[oslo_messaging_rabbit] +rabbit_host = {{ kolla_internal_address }} +rabbit_userid = {{ rabbitmq_user }} +rabbit_password = {{ rabbitmq_password }} +rabbit_ha_queues = true diff --git a/ansible/roles/neutron/tasks/ironic-check.yml b/ansible/roles/neutron/tasks/ironic-check.yml new file mode 100644 index 0000000000..f32a58a72d --- /dev/null +++ b/ansible/roles/neutron/tasks/ironic-check.yml @@ -0,0 +1,4 @@ +--- +# TODO(SamYaple): run verification checks at start of playbook +- fail: msg="neutron_plugin_agent must use openvswitch with Ironic" + when: enable_ironic | bool and neutron_plugin_agent != "openvswitch" diff --git a/ansible/roles/neutron/tasks/main.yml b/ansible/roles/neutron/tasks/main.yml index 5c48120b7c..3ff2244691 100644 --- a/ansible/roles/neutron/tasks/main.yml +++ b/ansible/roles/neutron/tasks/main.yml @@ -1,4 +1,7 @@ --- +# enforce ironic usage only with openvswtich +- include: ironic-check.yml + - include: register.yml - include: config.yml diff --git a/ansible/roles/neutron/templates/ml2_conf.ini.j2 b/ansible/roles/neutron/templates/ml2_conf.ini.j2 index 92ec89c87c..18816147f4 100644 --- a/ansible/roles/neutron/templates/ml2_conf.ini.j2 +++ b/ansible/roles/neutron/templates/ml2_conf.ini.j2 @@ -1,8 +1,14 @@ # ml2_conf.ini [ml2] +{% if enable_ironic | bool %} +type_drivers = flat +tenant_network_types = flat +mechanism_drivers = openvswitch +{% else %} # Changing type_drivers after bootstrap can lead to database inconsistencies type_drivers = flat,vlan,vxlan tenant_network_types = vxlan +{% endif %} {% if neutron_plugin_agent == "openvswitch" %} mechanism_drivers = openvswitch,l2population @@ -11,7 +17,11 @@ mechanism_drivers = linuxbridge,l2population {% endif %} [ml2_type_vlan] +{% if enable_ironic | bool %} +network_vlan_ranges = physnet1 +{% else %} network_vlan_ranges = +{% endif %} [ml2_type_flat] flat_networks = physnet1 diff --git a/ansible/roles/nova/templates/nova.conf.j2 b/ansible/roles/nova/templates/nova.conf.j2 index 28be05408e..a07751261e 100644 --- a/ansible/roles/nova/templates/nova.conf.j2 +++ b/ansible/roles/nova/templates/nova.conf.j2 @@ -30,7 +30,6 @@ linuxnet_interface_driver = nova.network.linux_net.LinuxOVSInterfaceDriver linuxnet_interface_driver = nova.network.linux_net.BridgeInterfaceDriver {% endif %} -compute_driver = libvirt.LibvirtDriver allow_resize_to_same_host = true # Though my_ip is not used directly, lots of other variables use $my_ip @@ -46,6 +45,27 @@ novncproxy_port = {{ nova_novncproxy_port }} novncproxy_base_url = http://{{ kolla_internal_address }}:{{ nova_novncproxy_port }}/vnc_auto.html {% endif %} +{% if enable_ironic | bool %} +compute_driver = nova.virt.ironic.IronicDriver +scheduler_host_manager = nova.scheduler.ironic_host_manager.IronicHostManager +ram_allocation_ratio = 1.0 +reserved_host_memory_mb = 0 +compute_manager = ironic.nova.compute.manager.ClusteredComputeManager +scheduler_use_baremetal_filters = True +{% else %} +compute_driver = libvirt.LibvirtDriver +{% endif %} + +{% if enable_ironic == 'yes' %} +[ironic] +#(TODO) remember to update this once discoverd is replaced by inspector +admin_username = {{ ironic_keystone_user }} +admin_password = {{ ironic_keystone_password }} +admin_url = {{ openstack_auth.auth_url }} +admin_tenant_name = {{ openstack_auth.project_name }} +api_endpoint = http://{{ kolla_internal_address }}:{{ ironic_api_port }}/v1 +{% endif %} + [oslo_messaging_rabbit] rabbit_host = {{ kolla_internal_address }} rabbit_userid = {{ rabbitmq_user }} diff --git a/ansible/site.yml b/ansible/site.yml index 6f12363607..b31c6a546a 100755 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -51,3 +51,7 @@ - hosts: [murano-api, murano-engine] roles: - { role: murano, tags: murano, when: enable_murano | bool } + +- hosts: [ironic-api, ironic-conductor, ironic-discoverd, ironic-pxe] + roles: + - {role: ironic, tags: ironic, when: enable_ironic | bool } diff --git a/doc/ironic-guide.rst b/doc/ironic-guide.rst new file mode 100644 index 0000000000..da8795d63a --- /dev/null +++ b/doc/ironic-guide.rst @@ -0,0 +1,42 @@ +Ironic in Kolla +=============== + +Overview +-------- +Currently Kolla can deploy the Ironic services: + +- ironic-api +- ironic-conductor +- ironic-discoverd + +As well as a required PXE service, deployed as ironic-pxe. + +Current status +-------------- +The Ironic implementation is "tech preview", so currently instances can only be +deployed on baremetal. Further work will be done to allow scheduling for both +virtualized and baremetal deployments. Most probably at that time discoverd +will be replaced by ironic-inspector. + +Post-deployment configuration +----------------------------- +Configuration based off upstream documentation_. + +Again, remember that enabling Ironic reconfigures nova compute (driver and +scheduler) as well as changes neutron network settings. Further neutron setup +is required as outlined below. + +Create the flat network to launch the instances: +:: + + neutron net-create --tenant-id $TENANT_ID sharednet1 --shared \ + --provider:network_type flat --provider:physical_network physnet1 + + neutron subnet-create sharednet1 $NETWORK_CIDR --name $SUBNET_NAME \ + --ip-version=4 --gateway=$GATEWAY_IP --allocation-pool \ + start=$START_IP,end=$END_IP --enable-dhcp + +And then the above ID is used to set cleaning_network_uuid in the neutron +section of ironic.conf. + +.. _documentation: http://docs.openstack.org/developer/ironic/deploy/install-guide.html diff --git a/docker/ironic/ironic-api/Dockerfile.j2 b/docker/ironic/ironic-api/Dockerfile.j2 index 112ff8b2df..016b3560bd 100644 --- a/docker/ironic/ironic-api/Dockerfile.j2 +++ b/docker/ironic/ironic-api/Dockerfile.j2 @@ -4,15 +4,16 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla) {% if install_type == 'binary' %} {% if base_distro in ['centos', 'fedora', 'oraclelinux', 'rhel'] %} -RUN yum -y install \ - openstack-ironic-api \ +# Install delorean version even though version number is less +# http://lists.openstack.org/pipermail/openstack-dev/2015-August/073100.html +RUN VER_TO_GET=$(yum --showduplicates list openstack-ironic-api | awk '/delorean/ {print $2}') \ + && yum -y install openstack-ironic-api-$VER_TO_GET \ && yum clean all {% endif %} {% endif %} COPY start.sh / -COPY config-external.sh /opt/kolla/ CMD ["/start.sh"] diff --git a/docker/ironic/ironic-api/start.sh b/docker/ironic/ironic-api/start.sh index 9d449defbe..60b3ea5a08 100755 --- a/docker/ironic/ironic-api/start.sh +++ b/docker/ironic/ironic-api/start.sh @@ -1,10 +1,13 @@ #!/bin/bash set -o errexit -CMD="/usr/bin/ironic-api" -ARGS="" - source /opt/kolla/kolla-common.sh -set_configs -exec $CMD $ARGS +# Bootstrap and exit if KOLLA_BOOTSTRAP variable is set. This catches all cases +# of the KOLLA_BOOTSTRAP variable being set, including empty. +if [[ "${!KOLLA_BOOTSTRAP[@]}" ]]; then + su -s /bin/sh -c "ironic-dbsync upgrade" ironic + exit 0 +fi + +exec $CMD diff --git a/docker/ironic/ironic-base/Dockerfile.j2 b/docker/ironic/ironic-base/Dockerfile.j2 index 2f8207c0ea..bb05d2dd75 100644 --- a/docker/ironic/ironic-base/Dockerfile.j2 +++ b/docker/ironic/ironic-base/Dockerfile.j2 @@ -10,6 +10,7 @@ RUN yum -y install \ python-oslo-log \ python-oslo-concurrency \ python-oslo-policy \ + python-oslo-versionedobjects \ && yum clean all {% endif %} diff --git a/docker/ironic/ironic-conductor/Dockerfile.j2 b/docker/ironic/ironic-conductor/Dockerfile.j2 index f62f7b7a0f..7fe401b4d1 100644 --- a/docker/ironic/ironic-conductor/Dockerfile.j2 +++ b/docker/ironic/ironic-conductor/Dockerfile.j2 @@ -4,15 +4,16 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla) {% if install_type == 'binary' %} {% if base_distro in ['centos', 'fedora', 'oraclelinux', 'rhel'] %} -RUN yum -y install \ - openstack-ironic-conductor \ +# Install delorean version even though version number is less +# http://lists.openstack.org/pipermail/openstack-dev/2015-August/073100.html +RUN VER_TO_GET=$(yum --showduplicates list openstack-ironic-conductor | awk '/delorean/ {print $2}') \ + && yum -y install openstack-ironic-conductor-$VER_TO_GET \ && yum clean all {% endif %} {% endif %} COPY start.sh / -COPY config-external.sh /opt/kolla/ CMD ["/start.sh"] diff --git a/docker/ironic/ironic-conductor/config-external.sh b/docker/ironic/ironic-conductor/config-external.sh deleted file mode 100644 index b838ee19d0..0000000000 --- a/docker/ironic/ironic-conductor/config-external.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -SOURCE="/opt/kolla/ironic-api/ironic.conf" -TARGET="/etc/ironic/ironic.conf" -OWNER="ironic" - -if [[ -f "$SOURCE" ]]; then - cp $SOURCE $TARGET - chown ${OWNER}: $TARGET - chmod 0644 $TARGET -fi diff --git a/docker/ironic/ironic-conductor/start.sh b/docker/ironic/ironic-conductor/start.sh index c766f04c5b..e6b7c5bb5f 100755 --- a/docker/ironic/ironic-conductor/start.sh +++ b/docker/ironic/ironic-conductor/start.sh @@ -1,10 +1,6 @@ #!/bin/bash set -o errexit -CMD="/usr/bin/ironic-conductor" -ARGS="" - source /opt/kolla/kolla-common.sh -set_configs -exec $CMD $ARGS +exec $CMD diff --git a/docker/ironic/ironic-discoverd/Dockerfile.j2 b/docker/ironic/ironic-discoverd/Dockerfile.j2 index 1843cb24cf..5e15c8d585 100644 --- a/docker/ironic/ironic-discoverd/Dockerfile.j2 +++ b/docker/ironic/ironic-discoverd/Dockerfile.j2 @@ -4,15 +4,22 @@ MAINTAINER Kolla Project (https://launchpad.net/kolla) {% if install_type == 'binary' %} {% if base_distro in ['centos', 'fedora', 'oraclelinux', 'rhel'] %} -RUN yum -y install \ - openstack-ironic-discoverd \ - && yum clean all +RUN pip install ironic-discoverd +# discoverd no longer in delorean 9/28/2015, switch to inspector on TODO +#RUN yum -y install \ +# openstack-ironic-discoverd \ +# && yum clean all {% endif %} + +{% elif install_type == 'source' %} + +RUN echo '{{ install_type }} not yet available for {{ base_distro }}' \ + && /bin/false + {% endif %} COPY start.sh / -COPY config-external.sh /opt/kolla/ CMD ["/start.sh"] diff --git a/docker/ironic/ironic-discoverd/config-external.sh b/docker/ironic/ironic-discoverd/config-external.sh deleted file mode 100644 index a3f82b8f30..0000000000 --- a/docker/ironic/ironic-discoverd/config-external.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -SOURCE="/opt/kolla/ironic-discoverd/discoverd.conf" -TARGET="/etc/ironic-discoverd/discoverd.conf" -OWNER="ironic" - -if [[ -f "$SOURCE" ]]; then - cp $SOURCE $TARGET - chown ${OWNER}: $TARGET - chmod 0644 $TARGET -fi diff --git a/docker/ironic/ironic-discoverd/start.sh b/docker/ironic/ironic-discoverd/start.sh index 093dc517af..e6b7c5bb5f 100755 --- a/docker/ironic/ironic-discoverd/start.sh +++ b/docker/ironic/ironic-discoverd/start.sh @@ -1,10 +1,6 @@ #!/bin/bash set -o errexit -CMD="/usr/bin/ironic-discoverd" -ARGS="" - source /opt/kolla/kolla-common.sh -set_configs -exec $CMD $ARGS +exec $CMD diff --git a/docker/ironic/ironic-pxe/Dockerfile.j2 b/docker/ironic/ironic-pxe/Dockerfile.j2 new file mode 100644 index 0000000000..d4484d1dba --- /dev/null +++ b/docker/ironic/ironic-pxe/Dockerfile.j2 @@ -0,0 +1,35 @@ +FROM {{ namespace }}/{{ base_distro }}-{{ install_type }}-base:{{ tag }} +MAINTAINER Kolla Project (https://launchpad.net/kolla) + +{% if install_type == 'binary' %} + {% if base_distro in ['centos', 'fedora', 'oraclelinux', 'rhel'] %} + +RUN yum -y install tftp-server syslinux-tftpboot \ + && yum clean all + +# PXE configuration +RUN mkdir -p /tftpboot \ + && cp /var/lib/tftpboot/chain.c32 /tftpboot \ + && echo 're ^(/tftpboot/) /tftpboot/\2' > /tftpboot/map-file \ + && echo 're ^/tftpboot/ /tftpboot/' >> /tftpboot/map-file \ + && echo 're ^(^/) /tftpboot/\1' >> /tftpboot/map-file \ + && echo 're ^([^/]) /tftpboot/\1' >> /tftpboot/map-file + + {% elif base_distro in ['ubuntu', 'debian'] %} +RUN echo '{{ install_type }} not yet available for {{ base_distro }}' \ + && /bin/false + + {% endif %} + +{% elif install_type == 'source' %} + +RUN echo '{{ install_type }} not yet available for {{ base_distro }}' \ + && /bin/false + +{% endif %} + +COPY start.sh / + +CMD ["/start.sh"] + +{{ include_footer }} diff --git a/docker/ironic/ironic-pxe/start.sh b/docker/ironic/ironic-pxe/start.sh new file mode 100755 index 0000000000..e6b7c5bb5f --- /dev/null +++ b/docker/ironic/ironic-pxe/start.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -o errexit + +source /opt/kolla/kolla-common.sh + +exec $CMD diff --git a/etc/kolla/config/discoverd.conf b/etc/kolla/config/discoverd.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/etc/kolla/config/ironic.conf b/etc/kolla/config/ironic.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/etc/kolla/config/ironic/discoverd.conf b/etc/kolla/config/ironic/discoverd.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/etc/kolla/config/ironic/ironic-api.conf b/etc/kolla/config/ironic/ironic-api.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/etc/kolla/config/ironic/ironic-conductor.conf b/etc/kolla/config/ironic/ironic-conductor.conf new file mode 100644 index 0000000000..e69de29bb2 diff --git a/etc/kolla/passwords.yml b/etc/kolla/passwords.yml index b50ddd3dd8..04a30e7975 100644 --- a/etc/kolla/passwords.yml +++ b/etc/kolla/passwords.yml @@ -53,6 +53,9 @@ heat_domain_admin_password: "password" murano_database_password: "password" murano_keystone_password: "password" +ironic_database_password: "password" +ironic_keystone_password: "password" + #################### # RabbitMQ options diff --git a/tests/test_build.py b/tests/test_build.py index a58327a510..8feb98d00d 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -39,7 +39,9 @@ class BuildTest(base.BaseTestCase): # these are images that are known to not build properly excluded_images = ["gnocchi-base", - "murano-base"] + "murano-base", + "ironic-pxe", + "ironic-discoverd"] failures = 0 for image, result in bad_results.iteritems():