From 9f084a910c4dfe0f720a97cc92ca0587b20f3075 Mon Sep 17 00:00:00 2001
From: Andy McCrae <andy.mccrae@gmail.com>
Date: Thu, 8 Dec 2016 12:40:58 +0000
Subject: [PATCH] Add support for neutron network names for
 cleaning/provisioning

This patch adds the ability to specify a cleaning and provisioning
network for Ironic. If none are specified then Ironic continues to
function as it does now.

Ironic role will calculate the UUID of the neutron network assuming a
network name is provided.

Additionally, this is added to testing by configuring a network to add
with the network-name.

Change-Id: I9be6f351c0da292ac8b861d2168e73d1861e1603
---
 defaults/main.yml                             | 12 +++++
 ...tron-network-support-669c382ea8bd3b98.yaml | 17 +++++++
 tasks/ironic_get_neutron_uuids.yml            | 41 ++++++++++++++++
 tasks/ironic_post_install.yml                 |  8 ++++
 templates/ironic.conf.j2                      |  6 +++
 tests/host_vars/ironic1.yml                   | 19 +++-----
 tests/host_vars/localhost.yml                 | 13 +++--
 tests/host_vars/openstack1.yml                | 22 ++++++---
 tests/host_vars/swift-storage1.yml            |  6 +--
 tests/inventory                               |  2 +-
 tests/os_ironic-overrides.yml                 | 21 ++++++++-
 tests/test-configure-ironic.yml               | 47 +++++++++++++++++++
 tests/test.yml                                |  3 ++
 13 files changed, 188 insertions(+), 29 deletions(-)
 create mode 100644 releasenotes/notes/ironic-neutron-network-support-669c382ea8bd3b98.yaml
 create mode 100644 tasks/ironic_get_neutron_uuids.yml
 create mode 100644 tests/test-configure-ironic.yml

diff --git a/defaults/main.yml b/defaults/main.yml
index 2287bae3..3ef5df76 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -102,7 +102,19 @@ ironic_galera_database: ironic
 ## Keystone authentication middleware
 ironic_keystone_auth_plugin: password
 
+# Neutron network - Set these in a playbook/task - can be set manually.
+# Only "name" or "uuid" is needed, uuid will take preference if both are specified.
+# The cleaning network is not required to be set - it will default to the same as
+# the provisioning network if not specified.
+# ironic_neutron_provisioning_network_uuid: "UUID for provisioning network in neutron"
+# ironic_neutron_cleaning_network_uuid: "UUID for cleaning network in neutron"
+# ironic_neutron_provisioning_network_name: "Name of provisioning network in neutron"
+# ironic_neutron_cleaning_network_name: "Name of cleaning network in neutron"
+
 # Integrated Openstack configuration
+ironic_openstack_driver_list: "pxe_ipmitool, agent_ipmitool"
+ironic_enabled_network_interfaces_list: "flat,noop{{ (ironic_neutron_provisioning_network_uuid is defined) | ternary(',neutron','') }}"
+ironic_default_network_interface: "{{ (ironic_neutron_provisioning_network_uuid is defined) | ternary('neutron','flat') }}"
 ironic_openstack_driver_list: agent_ipmitool
 ironic_openstack_auth_strategy: keystone
 ironic_openstack_api_url: ''  # Not required when we have keystone
diff --git a/releasenotes/notes/ironic-neutron-network-support-669c382ea8bd3b98.yaml b/releasenotes/notes/ironic-neutron-network-support-669c382ea8bd3b98.yaml
new file mode 100644
index 00000000..9bf7ef79
--- /dev/null
+++ b/releasenotes/notes/ironic-neutron-network-support-669c382ea8bd3b98.yaml
@@ -0,0 +1,17 @@
+features:
+  - Add support for ``neutron`` as an
+    ``enabled_network_interface``.
+  - The ``ironic_neutron_provisioning_network_name`` and
+    ``ironic_neutron_cleaning_network_name`` variable can
+    be set to the name of the neutron network to use for
+    provisioning and cleaning. The ansible tasks will
+    determine the appropriate UUID for that network.
+    Alternatively,
+    ``ironic_neutron_provisioning_network_uuid`` or
+    ``ironic_neutron_cleaning_network`` can be used to
+    directly specify the UUID of the networks. If both
+    ``ironic_neutron_provisioning_network_name`` and
+    ``ironic_neutron_provisioning_network_uuid`` are
+    specified, the specified UUID will be used.
+    If only the provisioning network is specified, the
+    cleaning network will default to the same network.
diff --git a/tasks/ironic_get_neutron_uuids.yml b/tasks/ironic_get_neutron_uuids.yml
new file mode 100644
index 00000000..13f7e67a
--- /dev/null
+++ b/tasks/ironic_get_neutron_uuids.yml
@@ -0,0 +1,41 @@
+---
+# Copyright 2016, Rackspace US, Inc.
+#
+# 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: Install neutronclient
+  pip:
+    name: python-neutronclient
+    state: "{{ ironic_pip_package_state }}"
+    extra_args: "{{ pip_install_options | default('') }}"
+  register: install_packages
+  until: install_packages|success
+  retries: 5
+  delay: 2
+
+- name: Create neutron network
+  neutron:
+    command: get_networks
+    net_name: "{{ ironic_neutron_provisioning_network_name }}"
+    openrc_path: /root/openrc
+
+- name: Set provisioning UUID fact
+  set_fact:
+     ironic_neutron_provisioning_network_uuid: "{{ neutron_networks[ironic_neutron_provisioning_network_name].id }}"
+
+- name: Set cleaning UUID fact
+  set_fact:
+     ironic_neutron_cleaning_network_uuid: "{{ neutron_networks[ironic_neutron_cleaning_network_name].id"
+  when:
+    - ironic_neutron_cleaning_network_name is defined
+    - ironic_neutron_cleaning_network_uuid is not defined
diff --git a/tasks/ironic_post_install.yml b/tasks/ironic_post_install.yml
index 5481df82..5338155b 100644
--- a/tasks/ironic_post_install.yml
+++ b/tasks/ironic_post_install.yml
@@ -102,6 +102,14 @@
   tags:
     - always
 
+# Get the cleaning/provisioning network UUIDs
+- include: ironic_get_neutron_uuids.yml
+  when:
+    - ironic_neutron_provisioning_network_uuid is not defined
+    - ironic_neutron_provisioning_network_name is defined
+  tags:
+    - always
+
 - name: Generate ironic config
   config_template:
     src: "{{ item.src }}"
diff --git a/templates/ironic.conf.j2 b/templates/ironic.conf.j2
index 8c2e026d..97a963fe 100644
--- a/templates/ironic.conf.j2
+++ b/templates/ironic.conf.j2
@@ -10,6 +10,8 @@ enabled_drivers = {{ ironic_driver_list }}
 host = {{ inventory_hostname }}
 
 memcached_servers = {{ memcached_servers }}
+enabled_network_interfaces = {{ ironic_enabled_network_interfaces_list }}
+default_network_interface = {{ ironic_default_network_interface }}
 
 [agent]
 
@@ -114,6 +116,10 @@ project_domain_name = {{ neutron_service_domain_name |default("Default") }}
 # Keystone client plugin authentication URL option
 auth_url = {{ keystone_service_adminurl }}
 insecure = {{ keystone_service_adminuri_insecure | bool }}
+{% if ironic_neutron_provisioning_network_name is defined %}
+provisioning_network_uuid = {{ ironic_neutron_provisioning_network_uuid | default('') }}
+cleaning_network_uuid = {{ ironic_neutron_cleaning_network_uuid | default(ironic_neutron_provisioning_network_uuid | default('')) }}
+{% endif %}
 
 [oneview]
 
diff --git a/tests/host_vars/ironic1.yml b/tests/host_vars/ironic1.yml
index 465c94a0..576b8db6 100644
--- a/tests/host_vars/ironic1.yml
+++ b/tests/host_vars/ironic1.yml
@@ -16,12 +16,7 @@
 ansible_host: 10.1.1.104
 ansible_become: True
 ansible_user: root
-tunnel_address: 10.1.2.104
-neutron_local_ip: 10.1.2.104
-neutron_provider_networks:
-  network_types: "vxlan,flat"
-  network_mappings: "flat:eth12"
-  network_vxlan_ranges: "1:1000"
+ipmi_address: 10.1.4.104
 container_name: "{{ inventory_hostname }}"
 container_networks:
   management_address:
@@ -30,14 +25,14 @@ container_networks:
     interface: "eth1"
     netmask: "255.255.255.0"
     type: "veth"
-  tunnel_address:
-    address: "{{ tunnel_address }}"
-    bridge: "br-vxlan"
+  ipmi_address:
+    address: "{{ ipmi_address }}"
+    bridge: "br-ipmi"
     interface: "eth2"
     netmask: "255.255.255.0"
     type: "veth"
-  vlan_address:
-    bridge: "br-vlan"
-    interface: "eth12"
+  prov_address:
+    bridge: "br-prov"
+    interface: "eth11"
     netmask: null
     type: "veth"
diff --git a/tests/host_vars/localhost.yml b/tests/host_vars/localhost.yml
index 863f3083..d600d435 100644
--- a/tests/host_vars/localhost.yml
+++ b/tests/host_vars/localhost.yml
@@ -13,10 +13,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-neutron_provider_networks:
-  network_types: "vxlan,flat"
-  network_mappings: "flat:eth12"
-  network_vxlan_ranges: "1:1000"
 ansible_become: True
 neutron_local_ip:  10.1.2.1
 ansible_python_interpreter: "/usr/bin/python2"
@@ -25,6 +21,13 @@ bridges:
     ip_addr: "10.1.1.1"
   - name: "br-vxlan"
     ip_addr: "10.1.2.1"
-  - name: "br-vlan"
+  - name: "br-flat"
     ip_addr: "10.1.3.1"
     veth_peer: "eth12"
+  - name: "br-ipmi"
+    ip_addr: "10.1.4.1"
+  - name: "br-storage"
+    ip_addr: "10.1.5.1"
+  - name: "br-prov"
+    ip_addr: "10.1.6.1"
+    veth_peer: "eth11"
diff --git a/tests/host_vars/openstack1.yml b/tests/host_vars/openstack1.yml
index 5c664bb8..627f2d15 100644
--- a/tests/host_vars/openstack1.yml
+++ b/tests/host_vars/openstack1.yml
@@ -18,10 +18,7 @@ ansible_become: True
 ansible_user: root
 tunnel_address: 10.1.2.102
 neutron_local_ip: 10.1.2.102
-neutron_provider_networks:
-  network_types: "vxlan,flat"
-  network_mappings: "flat:eth12"
-  network_vxlan_ranges: "1:1000"
+storage_address: 10.1.5.102
 container_name: "{{ inventory_hostname }}"
 container_networks:
   management_address:
@@ -36,8 +33,19 @@ container_networks:
     interface: "eth2"
     netmask: "255.255.255.0"
     type: "veth"
-  vlan_address:
-    bridge: "br-vlan"
-    interface: "eth12"
+  storage_address:
+    address: "{{ storage_address }}"
+    bridge: "br-storage"
+    interface: "eth3"
+    netmask: "255.255.255.0"
+    type: "veth"
+  prov_address:
+    bridge: "br-prov"
+    interface: "eth11"
     netmask: null
     type: "veth"
+  flat_address:
+    bridge: "br-flat"
+    interface: "eth12"
+    netmask: null
+    type: veth
diff --git a/tests/host_vars/swift-storage1.yml b/tests/host_vars/swift-storage1.yml
index 90862dc4..65a2cc9c 100644
--- a/tests/host_vars/swift-storage1.yml
+++ b/tests/host_vars/swift-storage1.yml
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 ansible_host: 10.1.1.103
-storage_address: 10.1.2.103
+storage_address: 10.1.5.103
 ansible_user: root
 ansible_become: True
 container_networks:
@@ -26,7 +26,7 @@ container_networks:
     type: "veth"
   storage_address:
     address: "{{ storage_address }}"
-    bridge: "br-vxlan"
-    interface: "eth2"
+    bridge: "br-storage"
+    interface: "eth3"
     netmask: "255.255.255.0"
     type: "veth"
diff --git a/tests/inventory b/tests/inventory
index 1cfea3f7..2e6a1f21 100644
--- a/tests/inventory
+++ b/tests/inventory
@@ -100,7 +100,7 @@ openstack1
 openstack1
 
 [nova_compute]
-localhost
+openstack1
 
 [nova_conductor]
 openstack1
diff --git a/tests/os_ironic-overrides.yml b/tests/os_ironic-overrides.yml
index 2e9c2fc1..0e268ab6 100644
--- a/tests/os_ironic-overrides.yml
+++ b/tests/os_ironic-overrides.yml
@@ -13,7 +13,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-test_swift_repl_network: "eth2"
+test_swift_storage_network: "eth3"
+test_swift_repl_network: "eth3"
 nova_virt_type: ironic
 glance_file_store: swift
 test_swift_repl_number: 2
+nova_console_type: novnc
+
+neutron_provider_networks:
+  network_types: "vxlan,flat"
+  network_vxlan_ranges: "1:1000"
+  network_flat_networks: "flat,prov"
+  network_mappings: "flat:eth12,prov:eth11"
+
+# Must be set to a normal MTU
+neutron_network_device_mtu: 1500
+neutron_l2_population: True
+neutron_dhcp_config:
+  dhcp-option-force: "26,1500"
+  log-facility: "/var/log/neutron/neutron-dnsmasq.log"
+ironic_neutron_provisioning_network_name: "ironic-prov"
+neutron_l3: True
+neutron_metadata: True
+ironic_pip_package_state: latest
diff --git a/tests/test-configure-ironic.yml b/tests/test-configure-ironic.yml
new file mode 100644
index 00000000..70e8f857
--- /dev/null
+++ b/tests/test-configure-ironic.yml
@@ -0,0 +1,47 @@
+---
+# Copyright 2016, Rackspace US, Inc.
+#
+# 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: Setup localhost requirements
+  hosts: localhost
+  become: True
+  gather_facts: True
+  tasks:
+    - name: Install pip requirements
+      pip:
+        name: "python-neutronclient"
+        state: "{{ ironic_pip_package_state }}"
+      register: install_packages
+      until: install_packages|success
+      retries: 5
+      delay: 2
+    - name: Create br-prov network
+      neutron:
+        command: create_network
+        openrc_path: /root/openrc
+        net_name: "{{ ironic_neutron_provisioning_network_name }}"
+        provider_network_type: flat
+        provider_physical_network: prov
+        insecure: "{{ keystone_service_internaluri_insecure }}"
+    - name: Ensure public subnet exists
+      neutron:
+        command: create_subnet
+        openrc_path: /root/openrc
+        net_name: "{{ ironic_neutron_provisioning_network_name }}"
+        subnet_name: "ironic-prov-subnet"
+        cidr: "10.1.6.0/24"
+        insecure: "{{ keystone_service_internaluri_insecure }}"
+        allocation_pools: ""
+  vars_files:
+    - common/test-vars.yml
diff --git a/tests/test.yml b/tests/test.yml
index 3117caf3..65038fbf 100644
--- a/tests/test.yml
+++ b/tests/test.yml
@@ -34,6 +34,9 @@
 # Install Nova
 - include: common/test-install-nova.yml
 
+# Configure Ironic
+- include: test-configure-ironic.yml
+
 # Install Ironic
 - include: common/test-install-ironic.yml