There are a couple things going on here.
First, the customer appears to be trying to manually provision network information by creating a 'network-interfaces' section in their user-data file:
#cloud-config
network-interfaces: |
iface eth0 inet static
[...]
This won't work; there's nothing in cloud-init that looks for network configuration information here.
Cloud-init does look for a network-interfaces key in the meta-data, but only when using the NoCloud data source. In all other situations it expects the cloud environment to provide this information via a different key.
When using the ConfigDrive data source, cloud-init will look for a "network_config" section in the meta-data. This can only be provisioned by OpenStack (that is, it can't be set explicitly by the user), and the following must be true:
- You must have injected_network_template set in /etc/nova/nova.conf.
- You must have flat_inject=True in /etc/nova/nova.conf.
- You must have created the associated subnet with --disable-dhcp
In this situation, nova will provide a 'network_config' key in the metadata that looks like this:
"network_config": {
"content_path": "/content/0000",
"name": "network_config",
}
And in openstack/content/0000 on the generated config drive you will find a file that Nova generated by rendering the template provided in injected_network_template. Unfortunately, the default template distributed with RHEL-OSP, at least on OSP-7, appears to be buggy: it is expecting top-level keys like 'address' and 'netmask', but is instead receiving a top-level 'interfaces' key that contains a list of interfaces.
But in fact the above is irrelevant, because that template generates a RHEL-style network configuration file, and cloud-init is expecting a debian-style "/etc/network/interfaces" file (even on RHEL platforms), so you'll need to point injected_network_template at something that looks like this:
{% for interface in interfaces %}
auto {{ interface.name }}
iface {{ interface.name }} inet static
address {{ interface.address }}
netmask {{ interface.netmask }}
broadcast {{ interface.broadcast }}
gateway {{ interface.gateway }}
dns-nameservers {{ interface.dns }}
{% endfor %}
With this in place, and assuming you've met the preconditions I noted earlier, you should be all set.
I've confirmed that this works on OSP-7 with a RHEL 6.6 guest. With an Ubuntu 15.04 (vivid) guest, it appears to result in a valid /etc/network/interfaces file but it required an explicit 'ifdown eth0; ifup eth0' to work, and I haven't diagnosed that issue yet.