Add support for network labels

This patch adds the ability to specify a net-label
instead of using a net-id (network UUID).

Rather than use network UUID's in our nodepool.yaml
config files it would be nice to use the more meaningful
network labels instead. This should make the config file
more readable across the various cloud providers and
matches how we use image names (instead of image
UUIDs) as well.

The current implementation relies on the os-tenant-networks
extension in Nova to provide the network label lookup.
Given that nodepool is currently focused around using
novaclient this made the most sense. We may at some point
in the future want to use the Neutron API directly for
this information or perhaps use a combination of both
approaches to accommodate a variety of provider API
deployment choices.

Tested locally on my TripleO overcloud using two
Neutron networks.

Change-Id: I9bdd35adf2d85659cf1b992ccd2fcf98fb124528
This commit is contained in:
Dan Prince 2014-06-05 22:04:15 -04:00
parent fc335e41be
commit e471cea178
4 changed files with 42 additions and 4 deletions

View File

@ -153,6 +153,9 @@ same name. Example::
boot-timeout: 120
launch-timeout: 900
template-hostname: '{image.name}-{timestamp}.template.openstack.org'
networks:
- net-id: 'some-uuid'
- net-label: 'some-network-name'
images:
- name: precise
base-image: 'Precise'
@ -199,6 +202,13 @@ Both `boot-timeout` and `launch-timeout` keys are optional. The
`boot-timeout` key defaults to 60 seconds and `launch-timeout` key
will default to 3600 seconds.
The optional `networks` section may be used to specify custom
Neutron networks that get attached to each node. You can specify
Neutron networks using either the `net-id` or `net-label`. If
only the `net-label` is specified the network UUID is automatically
queried via the Nova os-tenant-networks API extension (this requires
that the cloud provider has deployed this extension).
The `availability-zones` key is optional. Without it nodepool will rely
on nova to schedule an availability zone. If it is provided the value
should be a list of availability zone names. Nodepool will select one

View File

@ -1014,7 +1014,7 @@ class NodePool(threading.Thread):
p.boot_timeout = provider.get('boot-timeout', 60)
p.launch_timeout = provider.get('launch-timeout', 3600)
p.use_neutron = bool(provider.get('networks', ()))
p.nics = provider.get('networks')
p.networks = provider.get('networks')
p.azs = provider.get('availability-zones')
p.template_hostname = provider.get(
'template-hostname',
@ -1084,7 +1084,7 @@ class NodePool(threading.Thread):
new_pm.boot_timeout != old_pm.provider.boot_timeout or
new_pm.launch_timeout != old_pm.provider.launch_timeout or
new_pm.use_neutron != old_pm.provider.use_neutron or
new_pm.nics != old_pm.provider.nics or
new_pm.networks != old_pm.provider.networks or
new_pm.azs != old_pm.provider.azs):
return False
new_images = new_pm.images

View File

@ -20,6 +20,8 @@ import logging
import paramiko
import novaclient
import novaclient.client
import novaclient.extension
import novaclient.v1_1.contrib.tenant_networks
import threading
import time
@ -219,6 +221,12 @@ class DeleteImageTask(Task):
client.images.delete(**self.args)
class FindNetworkTask(Task):
def main(self, client):
network = client.tenant_networks.find(**self.args)
return dict(id=str(network.id))
class ProviderManager(TaskManager):
log = logging.getLogger("nodepool.ProviderManager")
@ -228,6 +236,7 @@ class ProviderManager(TaskManager):
self.provider = provider
self._client = self._getClient()
self._images = {}
self._networks = {}
self._cloud_metadata_read = False
self.__flavors = {}
self.__extensions = {}
@ -253,9 +262,11 @@ class ProviderManager(TaskManager):
self._cloud_metadata_read = True
def _getClient(self):
tenant_networks = novaclient.extension.Extension(
'tenant_networks', novaclient.v1_1.contrib.tenant_networks)
args = ['1.1', self.provider.username, self.provider.password,
self.provider.project_id, self.provider.auth_url]
kwargs = {}
kwargs = {'extensions': [tenant_networks]}
if self.provider.service_type:
kwargs['service_type'] = self.provider.service_type
if self.provider.service_name:
@ -295,6 +306,13 @@ class ProviderManager(TaskManager):
self._images[name] = image
return image
def findNetwork(self, label):
if label in self._networks:
return self._networks[label]
network = self.submitTask(FindNetworkTask(label=label))
self._networks[label] = network
return network
def deleteImage(self, name):
if name in self._images:
del self._images[name]
@ -323,7 +341,16 @@ class ProviderManager(TaskManager):
if az:
create_args['availability_zone'] = az
if self.provider.use_neutron:
create_args['nics'] = self.provider.nics
nics = []
for network in self.provider.networks:
if 'net-id' in network:
nics.append({'net-id': network['net-id']})
elif 'net-label' in network:
net_id = self.findNetwork(network['net-label'])['id']
nics.append({'net-id': net_id})
else:
raise Exception("Invalid 'networks' configuration.")
create_args['nics'] = nics
return self.submitTask(CreateServerTask(**create_args))

View File

@ -37,6 +37,7 @@ providers:
pool: 'fake'
networks:
- net-id: 'some-uuid'
- net-label: 'some-label'
images:
- name: nodepool-fake
base-image: 'Fake Precise'