OpenStack script to pre-allocate fixed IPs

The create-ports.py script allocates ports and indirectly gets fixed IPs from the DHCP server. The ports are named openstack000, openstack001 etc. and they are displayed in a format suitable for dnsmasq:

$ python create-ports.py --count 2 --net fsf-lan |  \
   sudo tee /etc/dnsmasq.d/openstack
host-record=openstack000,10.0.3.32
host-record=openstack001,10.0.3.33

If fsf-lan is a network shared with other tenants, it makes sure the IP are reserved, although they are not yet bound to an instance.

$ neutron port-list
+--------------------------------------+--------------+..
| id                                   | name         | ...
+--------------------------------------+--------------+...
| 1d1a05b1-383d-49ef-ae75-5ddcb5c714db | openstack001 |....
...
+--------------------------------------+--------------+...

An new instance can then be given a known IP with:

$ openstack server create --image ubuntu-trusty-14.04 \
  --flavor 1cpu-1G \
  --key-name teuthology \
  --nic net-id=d936f445-5d68-485a-94f2-b852fd6b7d0c,v4-fixed-ip=10.0.3.33 \
  --wait openstack001

In the case of teuthology it is useful because the DNS can be configured once and for all while instances are dynamically created using IPs from the DNS instead of relying on allocation from the OpenStack DHCP server.

The create-ports.py script is derived from osc-lib.py. The python-openstackclient API does not encapsulate the python-neutronclient API but it provides access to it via client_manager.network like so:

    client_manager = clientmanager.ClientManager(
        cli_options=cloud,
        verify=True,
        api_version=api_version,
    )
...
    net = client_manager.network.list_networks(name=opts.net)

The best documentation for python-neutronclient is the the client.py file from the sources. The body argument of the create_port function is a structure that looks like the following:

            body_value = {
                "port": {
                    "admin_state_up": True,
                    "name": name,
                    "network_id": network_id
                }
            }
            port = client_manager.network.create_port(body_value)

where the semantic and name of the fields can be inferred from the structure returned by the list_ports function. The output of the list_ports function can be displayed by using the –debug option:

$ python create-ports.py --debug --count 2 --net fsf-lan
...
RESP BODY: {"ports": [{"status": "DOWN", "name": "openstack001",
   "allowed_address_pairs": [], "admin_state_up": true,
   "network_id": "d936f445-5d68-485a-94f2-b852fd6b7d0c", ...
...