Wednesday, December 23, 2015

Openstack SDK attach cloud network

I don't think the current OpenStack SDK supports the nova api extension for virtual interfaces.

I'm not a nova guy.

I don't understand the difference between the OpenStack compute v2 os-interfaces API - and the Openstack compute os-virtual-interfacesv2 extension API.

But rackspace seems to have had to write an extension for the novaclient CLI to make it able to attach a new virtual interfaces for a cloud network to a running instance.

I was thinking I might have to write a new resource to support the api extension (probably just crib from the existing ServerInterface) - but it turned out there's already support in OpenStackSDK to boot instances with extra networks.

Here's what I'm using:
#!/usr/bin/env python
import os
import requests
import sys

# default instance and network attributes
IMAGE = '09de0a66-3156-48b4-90a5-1cf25a905207'
FLAVOR = 'general1-4'
NETWORK = 'my-test'
CIDR = ''

auth_url = os.environ.get(
    'OS_AUTHURL', '')
# username and *password* must be set in the envrion
username = os.environ['OS_USERNAME']
password = os.environ['OS_PASSWORD']

# something about the rackspace cert makes requests mad

from openstack import connection
from openstack.compute.v2._proxy import _server

# the openstacksdk doesn't support admin_pass
class PatchedServerResource(_server.Server):

    def create_by_id(self, *args, **kwargs):
        resp = super(PatchedServerResource, self).create_by_id(*args, **kwargs)
        self._attrs['adminPass'] = resp.get('adminPass')
        return resp

_server.Server = PatchedServerResource

conn = connection.Connection(auth_url=auth_url,

conn.profile.set_region(conn.profile.ALL, REGION)

def _get_or_create_network(name):
    # this doesn't seem to work
    # network =

    # so we just search by hand
    for n in
        if == name:
            return n
    network =, ip_version='4', cidr=CIDR)
    return network

def main():
        server_name = sys.argv[1]
    except IndexError:
        return 'USAGE: %s <server-name>' % sys.argv[0]

    image = conn.compute.find_image(IMAGE)
    flavor = conn.compute.find_flavor(FLAVOR)
    network = _get_or_create_network(NETWORK)
    network_ids = (,
        # must explicitly include Public & Service networks
    server = conn.compute.create_server(
        name=server_name, image=image, flavor=flavor,
        networks=[{'uuid': id_} for id_ in network_ids]
    print 'pass', server['adminPass']
    server = conn.compute.wait_for_server(server)
    print 'ip', server.access_ipv4

if __name__ == "__main__":

So... that's not terrible.  You can see there's a few hacks in there - some defaults are globals for simplicity instead of bothering with argparse - credentials from environ for the same reason - I made the conn instance a global because it's easier to get ahold of in a repl just by importing - there's that weird cert error - some ugly monkey patching to get at admin_pass - another function for finding a network by name to work around something I hit in the Rackspace neutron API.

Having to add the awkward default static uuid's for the Public and Service networks sorta threw me on my first go 'round.

But all in all this works for creating new servers with a private cloud network on the Rackspace cloud.  Hooray!

1 comment:

Blogger said...

DreamHost is ultimately the best web-hosting provider with plans for any hosting requirments.