From 54965c878ba227fbc19d92f4d2676a8b65db51ff Mon Sep 17 00:00:00 2001
From: Mark Goddard <mark@stackhpc.com>
Date: Mon, 28 Jan 2019 13:20:52 +0000
Subject: [PATCH] Improve standalone ironic support

Adds a new flag, 'enable_openstack_core', which defaults to 'yes'.
Setting this flag to 'no' will disable the core OpenStack services,
including Glance, Heat, Horizon, Keystone, Neutron, and Nova.

Improves the default configuration of OpenStack Ironic when used in
standalone mode. In particular, configures a noauth mode when Keystone
is disabled, and allows the iPXE server to be used for provisioning as
well as inspection if Neutron is disabled.

Documentation for standalone ironic will be updated separately.

This patch was developed and tested using Bikolla [1].

[1] https://github.com/markgoddard/bikolla

Change-Id: Ic47f5ad81b8126a51e52a445097f7950dba233cd
Implements: blueprint standalone-ironic
---
 ansible/group_vars/all.yml                    | 18 +++++++++-------
 ansible/roles/ironic/defaults/main.yml        |  2 +-
 .../roles/ironic/templates/inspector.ipxe.j2  |  8 +++++++
 .../ironic/templates/ironic-inspector.conf.j2 | 10 +++++++++
 ansible/roles/ironic/templates/ironic.conf.j2 | 18 +++++++++++++---
 etc/kolla/globals.yml                         | 21 +++++++++++++++----
 .../ironic-standalone-66dbb02a190c8b5d.yaml   |  9 ++++++++
 7 files changed, 71 insertions(+), 15 deletions(-)
 create mode 100644 releasenotes/notes/ironic-standalone-66dbb02a190c8b5d.yaml

diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index b53e135f18..b737745d63 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -430,16 +430,20 @@ nova_console: "novnc"
 # Valid options are [ public, internal, admin ]
 openstack_interface: "admin"
 
+# Enable core OpenStack services. This includes:
+# glance, keystone, neutron, nova, heat, and horizon.
+enable_openstack_core: "yes"
+
 # These roles are required for Kolla to be operation, however a savvy deployer
 # could disable some of these required roles and run their own services.
-enable_glance: "yes"
+enable_glance: "{{ enable_openstack_core | bool }}"
 enable_haproxy: "yes"
 enable_keepalived: "{{ enable_haproxy | bool }}"
-enable_keystone: "yes"
+enable_keystone: "{{ enable_openstack_core | bool }}"
 enable_mariadb: "yes"
 enable_memcached: "yes"
-enable_neutron: "yes"
-enable_nova: "yes"
+enable_neutron: "{{ enable_openstack_core | bool }}"
+enable_nova: "{{ enable_openstack_core | bool }}"
 enable_rabbitmq: "{{ 'yes' if om_rpc_transport == 'rabbit' or om_notify_transport == 'rabbit' else 'no' }}"
 enable_outward_rabbitmq: "{{ enable_murano | bool }}"
 
@@ -479,8 +483,8 @@ enable_fluentd: "yes"
 enable_freezer: "no"
 enable_gnocchi: "no"
 enable_grafana: "no"
-enable_heat: "yes"
-enable_horizon: "yes"
+enable_heat: "{{ enable_openstack_core | bool }}"
+enable_horizon: "{{ enable_openstack_core | bool }}"
 enable_horizon_blazar: "{{ enable_blazar | bool }}"
 enable_horizon_cloudkitty: "{{ enable_cloudkitty | bool }}"
 enable_horizon_congress: "{{ enable_congress | bool }}"
@@ -545,7 +549,7 @@ enable_nova_ssh: "yes"
 enable_octavia: "no"
 enable_onos: "no"
 enable_opendaylight: "no"
-enable_openvswitch: "{{ neutron_plugin_agent != 'linuxbridge' }}"
+enable_openvswitch: "{{ enable_neutron | bool and neutron_plugin_agent != 'linuxbridge' }}"
 enable_ovs_dpdk: "no"
 enable_osprofiler: "no"
 enable_panko: "no"
diff --git a/ansible/roles/ironic/defaults/main.yml b/ansible/roles/ironic/defaults/main.yml
index dd45736dea..5f9415594a 100644
--- a/ansible/roles/ironic/defaults/main.yml
+++ b/ansible/roles/ironic/defaults/main.yml
@@ -182,7 +182,7 @@ ironic_console_serial_speed: "115200n8"
 ironic_ipxe_url: http://{{ api_interface_address }}:{{ ironic_ipxe_port }}
 ironic_enable_rolling_upgrade: "yes"
 ironic_inspector_kernel_cmdline_extras: []
-ironic_inspector_pxe_filter: iptables
+ironic_inspector_pxe_filter: "{% if enable_neutron | bool %}iptables{% else %}none{% endif %}"
 
 ####################
 ## Kolla
diff --git a/ansible/roles/ironic/templates/inspector.ipxe.j2 b/ansible/roles/ironic/templates/inspector.ipxe.j2
index c38277e50c..4675a0588d 100644
--- a/ansible/roles/ironic/templates/inspector.ipxe.j2
+++ b/ansible/roles/ironic/templates/inspector.ipxe.j2
@@ -3,6 +3,14 @@
 :retry_dhcp
 dhcp || goto retry_dhcp
 
+{# Standalone ironic: use ironic-configured PXE configs #}
+{% if not enable_neutron | bool %}
+# load the MAC-specific file or fail if it's not found
+:boot_system
+chain pxelinux.cfg/${mac:hexhyp} || goto inspector_ipa
+{% endif %}
+
+:inspector_ipa
 :retry_boot
 imgfree
 kernel --timeout 30000 {{ ironic_ipxe_url }}/ironic-agent.kernel ipa-inspection-callback-url=http://{{ kolla_internal_vip_address }}:{{ ironic_inspector_port }}/v1/continue systemd.journald.forward_to_console=yes BOOTIF=${mac} initrd=agent.ramdisk {{ ironic_inspector_kernel_cmdline_extras | join(' ') }} || goto retry_boot
diff --git a/ansible/roles/ironic/templates/ironic-inspector.conf.j2 b/ansible/roles/ironic/templates/ironic-inspector.conf.j2
index e7c93a4187..f423a33ee5 100644
--- a/ansible/roles/ironic/templates/ironic-inspector.conf.j2
+++ b/ansible/roles/ironic/templates/ironic-inspector.conf.j2
@@ -2,6 +2,9 @@
 debug = {{ ironic_logging_debug }}
 log_dir = /var/log/kolla/ironic-inspector
 
+{% if not enable_keystone | bool %}
+auth_strategy = noauth
+{% endif %}
 listen_address = {{ api_interface_address }}
 listen_port = {{ ironic_inspector_port }}
 transport_url = {{ rpc_transport_url }}
@@ -10,6 +13,7 @@ transport_url = {{ rpc_transport_url }}
 transport_url = {{ notify_transport_url }}
 
 [ironic]
+{% if enable_keystone | bool %}
 auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
 auth_type = password
 project_domain_id = {{ default_project_domain_id }}
@@ -18,7 +22,12 @@ project_name = service
 username = {{ ironic_inspector_keystone_user }}
 password = {{ ironic_inspector_keystone_password }}
 os_endpoint_type = internalURL
+{% else %}
+auth_type = none
+endpoint_override = {{ ironic_internal_endpoint }}
+{% endif %}
 
+{% if enable_keystone | bool %}
 [keystone_authtoken]
 www_authenticate_uri = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_public_port }}
 auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
@@ -32,6 +41,7 @@ password = {{ ironic_inspector_keystone_password }}
 memcache_security_strategy = ENCRYPT
 memcache_secret_key = {{ memcache_secret_key }}
 memcached_servers = {% for host in groups['memcached'] %}{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ memcached_port }}{% if not loop.last %},{% endif %}{% endfor %}
+{% endif %}
 
 {% if ironic_policy_file is defined %}
 [oslo_policy]
diff --git a/ansible/roles/ironic/templates/ironic.conf.j2 b/ansible/roles/ironic/templates/ironic.conf.j2
index c21b8b1e21..718b2421d4 100644
--- a/ansible/roles/ironic/templates/ironic.conf.j2
+++ b/ansible/roles/ironic/templates/ironic.conf.j2
@@ -59,7 +59,6 @@ memcache_secret_key = {{ memcache_secret_key }}
 memcached_servers = {% for host in groups['memcached'] %}{{ hostvars[host]['ansible_' + hostvars[host]['api_interface']]['ipv4']['address'] }}:{{ memcached_port }}{% if not loop.last %},{% endif %}{% endfor %}
 {% endif %}
 
-
 {% if enable_cinder | bool %}
 [cinder]
 auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
@@ -69,8 +68,9 @@ user_domain_id = default
 project_name = service
 username = {{ ironic_keystone_user }}
 password = {{ ironic_keystone_password }}
-
 {% endif %}
+
+{% if enable_glance | bool %}
 [glance]
 glance_api_servers = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ glance_api_port }}
 auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
@@ -80,7 +80,9 @@ user_domain_id = default
 project_name = service
 username = {{ ironic_keystone_user }}
 password = {{ ironic_keystone_password }}
+{% endif %}
 
+{% if enable_neutron | bool %}
 [neutron]
 url = {{ internal_protocol }}://{{ kolla_internal_fqdn }}:{{ neutron_server_port }}
 auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
@@ -91,9 +93,11 @@ project_name = service
 username = {{ ironic_keystone_user }}
 password = {{ ironic_keystone_password }}
 cleaning_network = {{ ironic_cleaning_network }}
+{% endif %}
 
 [inspector]
 enabled = true
+{% if enable_keystone | bool %}
 auth_url = {{ admin_protocol }}://{{ kolla_internal_fqdn }}:{{ keystone_admin_port }}
 auth_type = password
 project_domain_id = default
@@ -101,7 +105,10 @@ user_domain_id = default
 project_name = service
 username = {{ ironic_keystone_user }}
 password = {{ ironic_keystone_password }}
-service_url = {{ ironic_inspector_internal_endpoint }}
+{% else %}
+auth_type=none
+{% endif %}
+endpoint_override = {{ ironic_inspector_internal_endpoint }}
 
 [agent]
 deploy_logs_local_path = /var/log/kolla/ironic
@@ -128,3 +135,8 @@ http_url = {{ ironic_ipxe_url }}
 
 [oslo_middleware]
 enable_proxy_headers_parsing = True
+
+{% if not enable_neutron | bool %}
+[dhcp]
+dhcp_provider = none
+{% endif %}
diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml
index 5686aad338..0b95913d3c 100644
--- a/etc/kolla/globals.yml
+++ b/etc/kolla/globals.yml
@@ -171,6 +171,19 @@ kolla_internal_vip_address: "10.10.10.254"
 # Valid options are [ none, novnc, spice, rdp ]
 #nova_console: "novnc"
 
+# These roles are required for Kolla to be operation, however a savvy deployer
+# could disable some of these required roles and run their own services.
+#enable_glance: "{{ enable_openstack_core | bool }}"
+#enable_haproxy: "yes"
+#enable_keepalived: "{{ enable_haproxy | bool }}"
+#enable_keystone: "{{ enable_openstack_core | bool }}"
+#enable_mariadb: "yes"
+#enable_memcached: "yes"
+#enable_neutron: "{{ enable_openstack_core | bool }}"
+#enable_nova: "{{ enable_openstack_core | bool }}"
+#enable_rabbitmq: "{{ 'yes' if om_rpc_transport == 'rabbit' or om_notify_transport == 'rabbit' else 'no' }}"
+#enable_outward_rabbitmq: "{{ enable_murano | bool }}"
+
 # OpenStack services can be enabled or disabled with these options
 #enable_aodh: "no"
 #enable_barbican: "no"
@@ -202,9 +215,8 @@ kolla_internal_vip_address: "10.10.10.254"
 #enable_freezer: "no"
 #enable_gnocchi: "no"
 #enable_grafana: "no"
-#enable_haproxy: "yes"
-#enable_heat: "yes"
-#enable_horizon: "yes"
+#enable_heat: "{{ enable_openstack_core | bool }}"
+#enable_horizon: "{{ enable_openstack_core | bool }}"
 #enable_horizon_blazar: "{{ enable_blazar | bool }}"
 #enable_horizon_cloudkitty: "{{ enable_cloudkitty | bool }}"
 #enable_horizon_congress: "{{ enable_congress | bool }}"
@@ -264,7 +276,8 @@ kolla_internal_vip_address: "10.10.10.254"
 #enable_octavia: "no"
 #enable_onos: "no"
 #enable_opendaylight: "no"
-#enable_openvswitch: "{{ neutron_plugin_agent != 'linuxbridge' }}"
+#enable_openstack_core: "yes"
+#enable_openvswitch: "{{ enable_neutron | bool and neutron_plugin_agent != 'linuxbridge' }}"
 #enable_ovs_dpdk: "no"
 #enable_osprofiler: "no"
 #enable_panko: "no"
diff --git a/releasenotes/notes/ironic-standalone-66dbb02a190c8b5d.yaml b/releasenotes/notes/ironic-standalone-66dbb02a190c8b5d.yaml
new file mode 100644
index 0000000000..2fd4f13636
--- /dev/null
+++ b/releasenotes/notes/ironic-standalone-66dbb02a190c8b5d.yaml
@@ -0,0 +1,9 @@
+---
+features:
+  - |
+    Adds a new flag, ``enable_openstack_core``, which defaults to ``yes``.
+    Setting this flag to ``no`` will disable the core OpenStack services,
+    including Glance, Heat, Horizon, Keystone, Neutron, and Nova.
+  - |
+    Improves the default configuration of OpenStack Ironic when used in
+    standalone mode.