Commit 9ef9388c authored by David Johnson's avatar David Johnson

Make VM and wfagent names appear as node names in the Capnet Protocol.

This was tonight's adventure.  Holy cow.  I feel like I need to go take
a shower.  Apparently, despite the fact that Neutron and Nova have
coexisted for many years, Nova VMs have a hostname that doesn't resolve
to anything, and that Neutron knows nothing about.  This causes all
kinds of local hangups (i.e., sudo, ssh UseDNS), but ok, whatever.
Neutron has its own "DNS" names for the VMs; Nova has its own.  They
don't share info.

For us, it matters because we want the tenants to be able to create VMs
and wfagents with meaningful names, and have those names returned to the
Capnet Protocol as the node names.

Well, Neutron and Nova do not share this information.  The real way to
solve this is to ask Nova for the VM name from the Capnet Neutron agent,
when said agent sees a port binding update.  But we want to process
those pretty fast, and calling out to Keystone/Nova for a lookup on the
hot path is quite undesirable.  So instead, since we already have a
Capnet-specific binding update call that pushes local OVS dpid and
ofportno from the local node to the controller (which distributes it to
whichever Capnet agents are writing metadata files), if we can "find" a
nova VM name locally, we add that to the binding, and then the Neutron
server adds the name to the ports table in the DB.  Currently, we find
this by whacking through the libvirt.xml until we find an instance who
owns the device_name we are sending the binding update for.

It seems that the Neutron people have already staged in db schema
changes to support their pending new DNS feature.  This is coming, but
it's not here yet.  So we can use the new table field, but the
Neutron-Nova DNS thing doesn't exist in Liberty.  Eventually, Nova will
tell Neutron the name of the port and other DNS information.
parent 778fa76f
Pipeline #1211 skipped
......@@ -220,6 +220,18 @@ class CapnetDBMixin(agents_db.AgentDbMixin):
port_id = binding['port_id']
session = context.session
# yank out 'name' and 'dns_name' and put into port
name = None
dns_name = None
if 'name' in binding:
name = binding['name']
del binding['name']
pass
if 'dns_name' in binding:
name = binding['dns_name']
del binding['dns_name']
pass
with session.begin(subtransactions=True):
query = session.query(CapnetPortBinding).filter(
CapnetPortBinding.port_id==port_id)
......@@ -254,6 +266,17 @@ class CapnetDBMixin(agents_db.AgentDbMixin):
cpb = query.first()
foo = cpb.wfagent
with session.begin(subtransactions=True):
if not cpb.port is None and (name or dns_name):
if name:
cpb.port.name = name
if dns_name:
cpb.port.dns_name = dns_name
cpb = session.merge(cpb)
pass
pass
self.__db_capnet_port_binding_notify(context,dict(cpb))
pass
......
......@@ -397,6 +397,7 @@ class CapnetControllerMetadataManager(object):
"""
LOG.debug("creating metadata dict from binding %s" % (str(binding),))
wfagent_name = None
if 'role' in binding:
role = binding['role']
elif 'wfagent' in binding and not binding['wfagent'] is None:
......@@ -406,6 +407,9 @@ class CapnetControllerMetadataManager(object):
# For now, wfagents aren't special; just nodes
role = 'node'
pass
if 'name' in binding['wfagent']:
wfagent_name = binding['wfagent']['name']
pass
else:
role = 'node'
pass
......@@ -456,11 +460,16 @@ class CapnetControllerMetadataManager(object):
domain_id = "%s-%s" % (network_id,subnet_id)
owner_id = tenant_id
name = None
if 'name' in binding['port'] and binding['port']['name']:
name = binding['port']['name']
elif 'dns_name' in binding['port'] and binding['port']['dns_name']:
dns_name = binding['port']['dns_name']
pass
mac = binding['port']['mac_address']
port_id = binding['port_id']
ipaddr = binding['ipallocation']['ip_address']
# XXX: get from nova???
nodename = ipaddr or port_id
nodename = name or wfagent_name or ipaddr or port_id
# XXX: we currently don't get a mask!
mask = '24'
line = "node %s %s %s %s %s %s %s %s %s" \
......@@ -1124,6 +1133,8 @@ class CapnetWorkflowAgentManager(object):
port = self._setup_wfagent_port(context,wfagent)
interface_name = self.ensure_running(wfagent,port)
self.agents[wfagent.id] = wfagent
return interface_name
def delete(self,context,wfagent):
......@@ -1155,6 +1166,21 @@ class CapnetWorkflowAgentManager(object):
pass
pass
def get_wfagent_name_by_port_id(self,port_id):
wfagent = None
for wfagent in self.agents:
if wfagent.port_id == port_id:
break
else:
wfagent = None
pass
pass
if not wfagent is None and 'name' in wfagent:
return wfagent.name
pass
return None
def _bind(self,context,wfagent):
"""
......@@ -1949,6 +1975,52 @@ class CapnetNeutronAgent(service.Service):
resync_b = self.treat_devices_removed(device_info['removed'])
# If one of the above operations fails => resync with plugin
return (resync_a | resync_b)
def __find_vm_name(self,device_name):
"""
This is a nasty, nasty hack to find a VM name for a nova VM, and
pass it to Neutron. We scrape it out of whichever libvirt
config file contains the device name! Oh, I feel dirty. But
it's Neutron's fault for not actually having a valid DNS story
that corresponds to Nova's VM name. Whoever thought that might
be something anyone would ever want...
"""
NOVADIR = '/var/lib/nova/instances'
try:
dirs = os.listdir(NOVADIR)
for dir in dirs:
lvcf = '%s/%s/libvirt.xml' % (NOVADIR,dir)
if os.path.exists(lvcf):
LOG.debug("considering instance %s" % (dir,))
f = file(lvcf)
found_dname = False
found_vname = False
vname = None
for line in f:
LOG.debug("line = %s" % (line,))
if 'target dev' in line and device_name in line:
found_dname = True
if '<nova:name>' in line and '</nova:name>' in line:
found_vname = True
vname = line.replace(' ','')
vname = vname.replace('<nova:name>','')
vname = vname.replace('</nova:name>','')
vname = vname.rstrip('\n')
pass
if found_dname and found_vname:
break
pass
f.close()
if found_dname and found_vname:
# Found it!
return vname
pass
pass
except:
import traceback
traceback.print_exc()
pass
return None
def treat_devices_added_updated(self, devices):
try:
......@@ -1998,6 +2070,13 @@ class CapnetNeutronAgent(service.Service):
cn_binding['ofport'] = port.ofport
cn_binding['device_name'] = port.port_name
cn_binding['host'] = cfg.CONF.host
# XXX: if Nova VM, figure out the name -- ugh.
if device_details['device_owner'] == 'compute:nova':
vm_name = self.__find_vm_name(port.port_name)
if vm_name:
cn_binding['dns_name'] = vm_name
pass
LOG.debug("sending binding update: %s" % (str(cn_binding),))
......
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