Commit 1d546431 authored by Christos Stavrakakis's avatar Christos Stavrakakis

cyclades: Add name to Ganeti NICs

Add 'name' attribute to newly created NICs. Currently, the name of the
NICs will not be used to refer to NICs, as it will be in Synnefo 0.15.
Names are added only to ease the migration to version 0.15. Also, this
commit updates snf-dispatcher to preserve the name of the NIC, if any,
when updating instance NICs.

Finally, the commit updates handling of firewall tags by adding a second
tag that contains the name of the NIC. The tags with the name of the
NICs will be kept in Synnefo 0.15, and the old tags with the index of
the NIC will be removed.
parent 67370918
......@@ -23,6 +23,7 @@ Cyclades
enable the use of this feature.
* Fix warning message while getting object permissions to appear only when
path is None and the object has permissions
* Add name to newly created NICs and the corresponding firewall tags.
.. _Changelog-0.14.9:
......@@ -336,7 +336,11 @@ def add(request, net, args):"Connecting VM %s to Network %s(%s)", vm, net, address)
backend.connect_to_network(vm, net, address)
index= NetworkInterface.objects.filter(machine=vm).count()
nic = NetworkInterface.objects.create(machine=vm, network=net,
ipv4=address, state="BUILDING")
backend.connect_to_network(vm, nic)
return HttpResponse(status=202)
......@@ -351,7 +351,6 @@ def do_create_server(userid, name, password, flavor, image, metadata={},
if network is None:
# Allocate IP from public network
(network, address) = util.get_public_ip(backend)
nic = {'ip': address, 'network': network.backend_id}
address = util.get_network_free_address(network)
......@@ -370,8 +369,9 @@ def do_create_server(userid, name, password, flavor, image, metadata={},
# Create VM's public NIC. Do not wait notification form ganeti hooks to
# create this NIC, because if the hooks never run (e.g. building error)
# the VM's public IP address will never be released!
NetworkInterface.objects.create(machine=vm, network=network, index=0,
ipv4=address, state="BUILDING")
nic = NetworkInterface.objects.create(machine=vm, network=network,
index=0, ipv4=address,
# Also we must create the VM metadata in the same transaction.
for key, val in metadata.items():
......@@ -701,6 +701,11 @@ class NetworkInterface(models.Model):
def __unicode__(self):
return '%s@%s' % (,
def backend_uuid(self):
"""Return the name of NIC in Ganeti."""
return "%snic-%s" % (settings.BACKEND_PREFIX_ID, str(
class PoolTable(models.Model):
available_map = models.TextField(default="", null=False)
......@@ -160,11 +160,14 @@ def process_ganeti_nics(ganeti_nics):
"""Process NIC dict from ganeti hooks."""
new_nics = []
for i, new_nic in enumerate(ganeti_nics):
network = new_nic.get('network', '')
n = str(network)
pk = utils.id_from_network_name(n)
network_name = new_nic.get('network', '')
network_id = utils.id_from_network_name(network_name)
net = Network.objects.get(id=network_id)
net = Network.objects.get(pk=pk)
nic_name = new_nic.get("name", None)
nic_id = None
if nic_name is not None:
nic_id = utils.id_from_nic_name(nic_name)
# Get the new nic info
mac = new_nic.get('mac', '')
......@@ -186,7 +189,8 @@ def process_ganeti_nics(ganeti_nics):
'ipv4': ipv4,
'ipv6': ipv6,
'firewall_profile': firewall_profile,
'state': 'ACTIVE'}
'state': 'ACTIVE',
'id': nic_id}
return new_nics
......@@ -410,7 +414,9 @@ def create_instance(vm, public_nic, flavor, image):
kw['disks'][0]['provider'] = provider
kw['disks'][0]['origin'] = flavor.disk_origin
kw['nics'] = [public_nic]
kw['nics'] = [{"name": public_nic.backend_uuid,
"ip": public_nic.ipv4}]
# kw['os'] = settings.GANETI_OS_PROVIDER
kw['ip_check'] = False
......@@ -626,8 +632,10 @@ def disconnect_network(network, backend, group=None):
return job_ids
def connect_to_network(vm, network, address=None):
def connect_to_network(vm, nic):
backend = vm.backend
network =
address = nic.ipv4
network = Network.objects.select_for_update().get(
bnet, created = BackendNetwork.objects.get_or_create(backend=backend,
......@@ -637,7 +645,9 @@ def connect_to_network(vm, network, address=None):
depends = [[job, ["success", "error", "canceled"]] for job in depend_jobs]
nic = {'ip': address, 'network': network.backend_id}
nic = {'ip': address,
'network': network.backend_id,
'name': nic.backend_uuid}
log.debug("Connecting vm %s to network %s(%s)", vm, network, address)
......@@ -666,6 +676,11 @@ def set_firewall_profile(vm, profile):
except KeyError:
raise ValueError("Unsopported Firewall Profile: %s" % profile)
public_nic = vm.nics.filter(network__public=True)[0]
except IndexError:
public_nic = None
log.debug("Setting tag of VM %s to %s", vm, profile)
with pooled_rapi_client(vm) as client:
......@@ -673,8 +688,16 @@ def set_firewall_profile(vm, profile):
for t in _firewall_tags.values():
client.DeleteInstanceTags(vm.backend_vm_id, [t],
if public_nic is not None:
tag_with_name = t.replace("0", public_nic.backend_uuid)
client.DeleteInstanceTags(vm.backend_vm_id, [tag_with_name],
client.AddInstanceTags(vm.backend_vm_id, [tag], dry_run=settings.TEST)
if public_nic is not None:
tag_with_name = tag.replace("0", public_nic.backend_uuid)
client.AddInstanceTags(vm.backend_vm_id, [tag_with_name],
# XXX NOP ModifyInstance call to force process_net_status to run
# on the dispatcher
......@@ -240,10 +240,11 @@ def get_nics_from_instance(i):
ips = zip(itertools.repeat('ipv4'), i['nic.ips'])
macs = zip(itertools.repeat('mac'), i['nic.macs'])
networks = zip(itertools.repeat('network'), i['nic.networks.names'])
names = zip(itertools.repeat('name'), i['nic.names'])
# modes = zip(itertools.repeat('mode'), i['nic.modes'])
# links = zip(itertools.repeat('link'), i['nic.links'])
# nics = zip(ips,macs,modes,networks,links)
nics = zip(ips, macs, networks)
nics = zip(ips, macs, networks, names)
nics = map(lambda x: dict(x), nics)
nics = dict(enumerate(nics))
return nics
......@@ -73,6 +73,19 @@ def id_to_network_name(id):
return "%snet-%s" % (settings.BACKEND_PREFIX_ID, str(id))
def id_from_nic_name(name):
"""Returns NIC's Django id, given a Ganeti's NIC name.
if not str(name).startswith(settings.BACKEND_PREFIX_ID):
raise ValueError("Invalid NIC name: %s" % name)
ns = str(name).replace(settings.BACKEND_PREFIX_ID + 'nic-', "", 1)
if not ns.isdigit():
raise ValueError("Invalid NIC name: %s" % name)
return int(ns)
def get_rsapi_state(vm):
"""Returns the API state for a virtual machine
......@@ -117,11 +117,11 @@ def get_instance_nics(instance, logger):
client = cli.GetClient()
fields = ["nic.networks.names", "nic.ips", "nic.macs", "nic.modes",
"nic.links", "tags"]
"nic.links", "nic.names", "tags"]
info = client.QueryInstances([instance], fields, use_locking=False)
networks, ips, macs, modes, links, tags = info[0]
nic_keys = ["network", "ip", "mac", "mode", "link"]
nics = zip(networks, ips, macs, modes, links)
networks, ips, macs, modes, links, names, tags = info[0]
nic_keys = ["network", "ip", "mac", "mode", "link", "name"]
nics = zip(networks, ips, macs, modes, links, names)
nics = map(lambda x: dict(zip(nic_keys, x)), nics)
except ganeti_errors.OpPrereqError:
# Not running on master! Load the conf file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment