diff --git a/README.rst b/README.rst index c1a394732..46d0a2b75 100644 --- a/README.rst +++ b/README.rst @@ -256,6 +256,7 @@ Example:: "driver": "agent_ssh", "ansible_ssh_host": "192.168.122.2", "ipv4_address": "192.168.122.2", + "provisioning_ipv4_address": "10.0.0.9", "properties": { "cpu_arch": "x86_64", "ram": "3072", @@ -296,10 +297,11 @@ The CSV file has the following columns: 14. ``ipmi_transit_channel`` - Requires: ``ipmi_bridging`` set to dual 15. ``ipmi_transit_address`` - Requires: ``ipmi_bridging`` set to dual 16. ironic driver +17. Host provisioning IP Address Example definition:: - 00:11:22:33:44:55,root,undefined,192.168.122.1,1,8192,512,NA,NA,aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,hostname_100,192.168.2.100,,,,agent_ipmitool + 00:11:22:33:44:55,root,undefined,192.168.122.1,1,8192,512,NA,NA,aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee,hostname_100,192.168.2.100,,,,agent_ipmitool,10.0.0.9 This file format is fairly flexible and can be easily modified although the enrollment and deployment playbooks utilize the model diff --git a/bifrost/inventory.py b/bifrost/inventory.py index 4530f0da2..0e57b5e42 100755 --- a/bifrost/inventory.py +++ b/bifrost/inventory.py @@ -188,6 +188,9 @@ def _process_baremetal_data(data_source, groups, hostvars): host['addressing_mode'] = "dhcp" else: host['ansible_ssh_host'] = host['ipv4_address'] + + if 'provisioning_ipv4_address' not in host.keys(): + host['provisioning_ipv4_address'] = host['ipv4_address'] # Add each host to the values to be returned. groups['baremetal']['hosts'].append(host['name']) hostvars.update({host['name']: host}) @@ -228,8 +231,15 @@ def _process_baremetal_csv(data_source, groups, hostvars): host['ipv4_address'] = _val_or_none(row, 11) if not host['ipv4_address']: host['addressing_mode'] = "dhcp" + host['provisioning_ipv4_address'] = None else: host['ansible_ssh_host'] = host['ipv4_address'] + + if len(row) > 17: + host['provisioning_ipv4_address'] = row[18] + else: + host['provisioning_ipv4_address'] = host['ipv4_address'] + # Default Driver unless otherwise defined or determined. host['driver'] = "agent_ssh" diff --git a/bifrost/tests/functional/test_inventory_functional.py b/bifrost/tests/functional/test_inventory_functional.py index 015385c13..8d53154f7 100644 --- a/bifrost/tests/functional/test_inventory_functional.py +++ b/bifrost/tests/functional/test_inventory_functional.py @@ -41,7 +41,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, 192.168.1.3,,,,,agent_ipmitool""".replace('\n', '').replace('|', '\n') expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", - "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": + "name": "hostname1", "ipv4_address": "192.168.1.3", + "provisioning_ipv4_address": "192.168.1.3" ,"ansible_ssh_host": "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": null, "ipmi_target_channel": null, @@ -49,7 +50,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, [{"mac": "00:01:02:03:04:06"}], "properties": {"ram": "8192", "cpu_arch": "x86_64", "disk_size": "1024", "cpus": "2"}}, "hostname0": {"uuid": "00000000-0000-0000-0000-000000000001", "driver": "agent_ssh", - "name": "hostname0", "ipv4_address": "192.168.1.2", "ansible_ssh_host": + "name": "hostname0", "ipv4_address": "192.168.1.2", + "provisioning_ipv4_address": "192.168.1.2", "ansible_ssh_host": "192.168.1.2", "driver_info": {"power": {"ssh_virt_type": "virsh", "ssh_key_filename": "/home/ironic/.ssh/id_rsa", "ssh_username": "ironic", "ssh_port": 22, "ssh_address": "192.0.2.2"}}, "nics": @@ -69,7 +71,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", - "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": + "name": "hostname1", "ipv4_address": "192.168.1.3", + "provisioning_ipv4_address": "192.168.1.3", "ansible_ssh_host": "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": "20", "ipmi_target_channel": "10", @@ -92,7 +95,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", - "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": + "name": "hostname1", "ipv4_address": "192.168.1.3", + "provisioning_ipv4_address": "192.168.1.3", "ansible_ssh_host": "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": "20", "ipmi_target_channel": "10", @@ -112,6 +116,7 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1 expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", "name": "hostname1", "addressing_mode": "dhcp", "ipv4_address": null, + "provisioning_ipv4_address": null, "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": null, "ipmi_target_channel": null, "ipmi_transit_address": null, @@ -134,6 +139,7 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1 expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", "name": "hostname1", "addressing_mode": "dhcp", "ipv4_address": null, + "provisioning_ipv4_address": null, "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": null, "ipmi_target_channel": null, "ipmi_transit_address": null, @@ -157,7 +163,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": - "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", + "192.168.1.3", "provisioning_ipv4_address": "192.168.1.3", + "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": null, "ipmi_target_channel": null, "ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics": @@ -165,7 +172,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, "x86_64", "disk_size": "1024", "cpus": "2"}}, "hostname0": {"uuid": "00000000-0000-0000-0000-000000000001", "driver": "agent_ssh", "name": "hostname0", "ipv4_address": "192.168.1.2", "ansible_ssh_host": - "192.168.1.2", "driver_info": {"power": {"ssh_virt_type": "virsh", + "192.168.1.2", "provisioning_ipv4_address": "192.168.1.2", + "driver_info": {"power": {"ssh_virt_type": "virsh", "ssh_key_filename": "/home/ironic/.ssh/id_rsa", "ssh_username": "ironic", "ssh_port": 22, "ssh_address": "192.0.2.2"}}, "nics": [{"mac": "00:01:02:03:04:05"}], "properties": {"ram": "8192", @@ -184,7 +192,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, expected_hostvars = """{"hostname1": {"uuid": "00000000-0000-0000-0000-000000000002", "driver": "agent_ipmitool", "name": "hostname1", "ipv4_address": "192.168.1.3", "ansible_ssh_host": - "192.168.1.3", "driver_info": {"power": {"ipmi_address": "192.0.2.3", + "192.168.1.3", "provisioning_ipv4_address": "192.168.1.3", + "driver_info": {"power": {"ipmi_address": "192.0.2.3", "ipmi_password": "undefined", "ipmi_username": "root", "ipmi_target_address": null, "ipmi_target_channel": null, "ipmi_transit_address": null, "ipmi_transit_channel": null}}, "nics": @@ -192,7 +201,8 @@ unused,,00000000-0000-0000-0000-000000000002,hostname1, "x86_64", "disk_size": "1024", "cpus": "2"}}, "hostname0": {"uuid": "00000000-0000-0000-0000-000000000001", "driver": "agent_ssh", "name": "hostname0", "ipv4_address": "192.168.1.2", "ansible_ssh_host": - "192.168.1.2", "driver_info": {"power": {"ssh_virt_type": "virsh", + "192.168.1.2", "provisioning_ipv4_address": "192.168.1.2", + "driver_info": {"power": {"ssh_virt_type": "virsh", "ssh_key_filename": "/home/ironic/.ssh/id_rsa", "ssh_username": "ironic", "ssh_port": 22, "ssh_address": "192.0.2.2"}}, "nics": [{"mac": "00:01:02:03:04:05"}], "properties": {"ram": "8192", diff --git a/playbooks/roles/bifrost-deploy-nodes-dynamic/README.md b/playbooks/roles/bifrost-deploy-nodes-dynamic/README.md index e159d32ff..dee5a0816 100644 --- a/playbooks/roles/bifrost-deploy-nodes-dynamic/README.md +++ b/playbooks/roles/bifrost-deploy-nodes-dynamic/README.md @@ -56,10 +56,28 @@ instance_info: A dictionary containing the information to define an instance. expected are image_source, image_checksum, root_gb, however, any supported key/value can be submitted to the API. -inventory_dhcp: A boolean value, defaulted to false, which causes the role - to update a template file and reload dhsmasq upon each update - in order to perform static dhcp assignments utilizing the - ipv4_address parameter. + +inventory_dhcp: A boolean value, defaulted to false, which allows dnsmasq + to configure the IP of the machines, rather than putting + the IP configuration of the machine in the config drive. + If set to true, the role will create a file for each machine + under /etc/dnsmasq.d/bifrost.dhcp-hosts.d containing the mac, + name of the machine, lease time and optionally the IP address + that will be offered to the machine by DHCP. + This optional IP is controlled by the inventory_dhcp_static_ip + parameter. + +inventory_dhcp_static_ip: A boolean value, defaulted to true, which configures + the mechanism for setting up the IP of machines when + inventory_dhcp is enabled. + If set to true, it will read the value of the key + 'provisioning_ipv4_address' from the inventory section + of each machine and dnsmasq will assign that IP to each + machine accordingly. Note, that if you don't assign + the key 'provisioning_ipv4_address' it will default + to the value of 'ipv4_address'. + If set to false, dnsmasq will assign IPs + automatically from the configured DHCP range. noauth_mode: Controls if the module is called in noauth mode. By default, this is the standard mode of operation, @@ -67,7 +85,6 @@ noauth_mode: Controls if the module is called in noauth mode. which expects a clouds.yml file. More information about this file format can be found at: http://docs.openstack.org/developer/os-client-config/ - Dependencies ------------ diff --git a/playbooks/roles/bifrost-deploy-nodes-dynamic/defaults/main.yml b/playbooks/roles/bifrost-deploy-nodes-dynamic/defaults/main.yml index 6a78bae81..2e6d89579 100644 --- a/playbooks/roles/bifrost-deploy-nodes-dynamic/defaults/main.yml +++ b/playbooks/roles/bifrost-deploy-nodes-dynamic/defaults/main.yml @@ -8,5 +8,6 @@ http_boot_folder: "/httpboot" deploy_image_filename: "deployment_image.qcow2" deploy_image: "{{http_boot_folder}}/{{deploy_image_filename}}" inventory_dhcp: false +inventory_dhcp_static_ip: true deploy_url_protocol: "http" noauth_mode: true diff --git a/playbooks/roles/bifrost-deploy-nodes-dynamic/templates/dhcp-host.j2 b/playbooks/roles/bifrost-deploy-nodes-dynamic/templates/dhcp-host.j2 index fef151525..da4b107be 100644 --- a/playbooks/roles/bifrost-deploy-nodes-dynamic/templates/dhcp-host.j2 +++ b/playbooks/roles/bifrost-deploy-nodes-dynamic/templates/dhcp-host.j2 @@ -1,2 +1,6 @@ # This file is managed by bifrost -{{ nics[0]['mac'] }},{{ipv4_address}},{{name}},12h +{% if inventory_dhcp_static_ip %} +{{ nics[0]['mac'] }},{{provisioning_ipv4_address}},{{name}},12h +{% else %} +{{ nics[0]['mac'] }},{{name}},12h +{% endif %} diff --git a/releasenotes/notes/inventory_dhcp_provisioning_ipv4_address-d2779f1abc38324a.yaml b/releasenotes/notes/inventory_dhcp_provisioning_ipv4_address-d2779f1abc38324a.yaml new file mode 100644 index 000000000..ac50d417f --- /dev/null +++ b/releasenotes/notes/inventory_dhcp_provisioning_ipv4_address-d2779f1abc38324a.yaml @@ -0,0 +1,16 @@ +--- +features: + - + The inventory_dhcp feature permits configuration + of dnsmasq to provide the IP configuration on + servers deployed by Bifrost, rather than setting + that information into the config drive. + Previously, the feature assumed the IP set by + dnsmasq was both the provisioning and the + management IP, but on some scenarios that is + not always the case. + With the inclusion of the inventory_dhcp_static_ip + option a user can provide an specific provisioning + IP via the JSON/YAML/CSV inventory in a server by + server basis, which will be used just for the + provisioning.