mirror of
https://github.com/ansible/awx.git
synced 2026-03-18 09:27:31 -02:30
Adds facts processing for ansible_net_neighbors
* Adds logic for consuming ansible_net_neighbors facts This consumes facts emitted from Ansible over a websocket to Tower. This allows consumers in network to process the facts and emit messges to the network UI. This requires a special callback plugin to run in Tower to emit the messages into the websocket using the python websocket-client library.
This commit is contained in:
@@ -8,7 +8,9 @@ from awx.network_ui.models import DataSheet, DataBinding, DataType
|
|||||||
from awx.network_ui.models import Process, Stream
|
from awx.network_ui.models import Process, Stream
|
||||||
from awx.network_ui.models import Toolbox, ToolboxItem
|
from awx.network_ui.models import Toolbox, ToolboxItem
|
||||||
from awx.network_ui.serializers import yaml_serialize_topology
|
from awx.network_ui.serializers import yaml_serialize_topology
|
||||||
|
from awx.network_ui.messages import MultipleMessage, InterfaceCreate, LinkCreate, to_dict
|
||||||
import urlparse
|
import urlparse
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -259,7 +261,8 @@ class _Persistence(object):
|
|||||||
print "no sender"
|
print "no sender"
|
||||||
return
|
return
|
||||||
if isinstance(data[1], dict) and client_id != data[1].get('sender'):
|
if isinstance(data[1], dict) and client_id != data[1].get('sender'):
|
||||||
print "client_id mismatch expected:", client_id, "actual:", data[1].get('sender')
|
logger.error("client_id mismatch expected:", client_id, "actual:", data[1].get('sender'))
|
||||||
|
logger.error(pformat(data))
|
||||||
return
|
return
|
||||||
message_type = data[0]
|
message_type = data[0]
|
||||||
message_value = data[1]
|
message_value = data[1]
|
||||||
@@ -633,75 +636,73 @@ class _Discovery(object):
|
|||||||
def onFacts(self, message, topology_id):
|
def onFacts(self, message, topology_id):
|
||||||
send_updates = False
|
send_updates = False
|
||||||
logger.info("onFacts message key %s", message['key'])
|
logger.info("onFacts message key %s", message['key'])
|
||||||
logger.info("onFacts message %s", pformat(message))
|
#logger.info("onFacts message %s", pformat(message))
|
||||||
return
|
device_name = message['key']
|
||||||
name = message['key']
|
updates = MultipleMessage('MultipleMessage', [])
|
||||||
device, created = Device.objects.get_or_create(topology_id=topology_id,
|
try:
|
||||||
name=name,
|
device = Device.objects.get(topology_id=topology_id, name=device_name)
|
||||||
defaults=dict(x=0,
|
except ObjectDoesNotExist:
|
||||||
y=0,
|
logger.info("onFacts Could not find %s in topology %s", device_name, topology_id)
|
||||||
type="switch",
|
return
|
||||||
id=0))
|
|
||||||
|
|
||||||
if created:
|
|
||||||
device.id = device.pk
|
|
||||||
device.save()
|
|
||||||
send_updates = True
|
|
||||||
logger.info("onFacts Created device %s", device)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
interfaces = dpath.util.get(message, '/value/ansible_local/lldp/lldp')
|
interfaces = dpath.util.get(message, '/value/ansible_net_neighbors')
|
||||||
|
logger.info(pformat(interfaces))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
interfaces = []
|
interfaces = {}
|
||||||
for interface in interfaces:
|
logger.info("onFacts %s: ", pformat(interfaces))
|
||||||
logger.info("onFacts %s: ", pformat(interface))
|
"""
|
||||||
for inner_interface in interface.get('interface', []):
|
ansible_net_neighbors example:
|
||||||
name = inner_interface.get('name')
|
{u'eth1': [{u'host': u'Spine1', u'port': u'eth3'}],
|
||||||
if not name:
|
u'eth2': [{u'host': u'Spine2', u'port': u'eth3'}],
|
||||||
continue
|
u'eth3': [{u'host': u'Host2', u'port': u'eth1'}]}
|
||||||
interface, created = Interface.objects.get_or_create(device_id=device.pk,
|
"""
|
||||||
name=name,
|
for interface_name, neighbors in interfaces.iteritems():
|
||||||
defaults=dict(id=0))
|
logger.info("interface_name %s neighbors %s", interface_name, neighbors)
|
||||||
if created:
|
interface, created = Interface.objects.get_or_create(device_id=device.pk,
|
||||||
interface.id = interface.pk
|
name=interface_name,
|
||||||
interface.save()
|
defaults=dict(id=0))
|
||||||
send_updates = True
|
if created:
|
||||||
print "Created interface ", interface
|
interface.id = interface.pk
|
||||||
|
interface.save()
|
||||||
|
updates.messages.append(InterfaceCreate('InterfaceCreate',
|
||||||
|
0,
|
||||||
|
interface.device.id,
|
||||||
|
interface.id,
|
||||||
|
interface.name))
|
||||||
|
send_updates = True
|
||||||
|
logger.info("Created interface %s", interface)
|
||||||
|
|
||||||
|
|
||||||
|
for neighbor in neighbors:
|
||||||
|
logger.info("neighbor %s", neighbor)
|
||||||
connected_interface = None
|
connected_interface = None
|
||||||
connected_device = None
|
connected_device = None
|
||||||
|
neighbor_name = neighbor.get('host')
|
||||||
|
if not neighbor_name:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
connected_device = Device.objects.get(topology_id=topology_id, name=neighbor_name)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
continue
|
||||||
|
|
||||||
for chassis in inner_interface.get('chassis', []):
|
logger.info("neighbor %s %s", neighbor_name, connected_device.pk)
|
||||||
name = chassis.get('name', [{}])[0].get('value')
|
|
||||||
if not name:
|
|
||||||
continue
|
|
||||||
connected_device, created = Device.objects.get_or_create(topology_id=topology_id,
|
|
||||||
name=name,
|
|
||||||
defaults=dict(x=0,
|
|
||||||
y=0,
|
|
||||||
type="switch",
|
|
||||||
id=0))
|
|
||||||
if created:
|
|
||||||
connected_device.id = connected_device.pk
|
|
||||||
connected_device.save()
|
|
||||||
send_updates = True
|
|
||||||
print "Created device ", connected_device
|
|
||||||
break
|
|
||||||
|
|
||||||
if connected_device:
|
remote_interface_name = neighbor.get('port')
|
||||||
for port in inner_interface.get('port', []):
|
|
||||||
for port_id in port.get('id', []):
|
connected_interface, created = Interface.objects.get_or_create(device_id=connected_device.pk,
|
||||||
if port_id['type'] == 'ifname':
|
name=remote_interface_name,
|
||||||
name = port_id['value']
|
defaults=dict(id=0))
|
||||||
break
|
if created:
|
||||||
connected_interface, created = Interface.objects.get_or_create(device_id=connected_device.pk,
|
connected_interface.id = connected_interface.pk
|
||||||
name=name,
|
connected_interface.save()
|
||||||
defaults=dict(id=0))
|
updates.messages.append(InterfaceCreate('InterfaceCreate',
|
||||||
if created:
|
0,
|
||||||
connected_interface.id = connected_interface.pk
|
connected_interface.device.id,
|
||||||
connected_interface.save()
|
connected_interface.id,
|
||||||
print "Created interface ", connected_interface
|
connected_interface.name))
|
||||||
send_updates = True
|
logger.info("Created interface %s", connected_interface)
|
||||||
|
send_updates = True
|
||||||
|
|
||||||
if connected_device and connected_interface:
|
if connected_device and connected_interface:
|
||||||
exists = Link.objects.filter(Q(from_device_id=device.pk,
|
exists = Link.objects.filter(Q(from_device_id=device.pk,
|
||||||
@@ -718,14 +719,25 @@ class _Discovery(object):
|
|||||||
from_interface_id=interface.pk,
|
from_interface_id=interface.pk,
|
||||||
to_interface_id=connected_interface.pk,
|
to_interface_id=connected_interface.pk,
|
||||||
id=0)
|
id=0)
|
||||||
|
|
||||||
link.save()
|
link.save()
|
||||||
link.id = link.pk
|
link.id = link.pk
|
||||||
link.save()
|
link.save()
|
||||||
print "Created link ", link
|
updates.messages.append(LinkCreate('LinkCreate',
|
||||||
|
0,
|
||||||
|
link.id,
|
||||||
|
link.name,
|
||||||
|
link.from_device.id,
|
||||||
|
link.to_device.id,
|
||||||
|
link.from_interface.id,
|
||||||
|
link.to_interface.id))
|
||||||
|
logger.info("Created link %s", link)
|
||||||
send_updates = True
|
send_updates = True
|
||||||
|
|
||||||
if send_updates:
|
if send_updates:
|
||||||
send_snapshot(Group("topology-%s" % topology_id), topology_id)
|
logger.info("onFacts send_updates")
|
||||||
|
channel = Group("topology-%s" % topology_id)
|
||||||
|
channel.send({"text": json.dumps([updates.msg_type, to_dict(updates)])})
|
||||||
|
|
||||||
|
|
||||||
discovery = _Discovery()
|
discovery = _Discovery()
|
||||||
|
|||||||
32
awx/network_ui/messages.py
Normal file
32
awx/network_ui/messages.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
|
MultipleMessage = namedtuple('MultipleMessage', ['msg_type',
|
||||||
|
'messages'])
|
||||||
|
InterfaceCreate = namedtuple('InterfaceCreate', ['msg_type',
|
||||||
|
'sender',
|
||||||
|
'device_id',
|
||||||
|
'id',
|
||||||
|
'name'])
|
||||||
|
LinkCreate = namedtuple('LinkCreate', ['msg_type',
|
||||||
|
'sender',
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'from_device_id',
|
||||||
|
'to_device_id',
|
||||||
|
'from_interface_id',
|
||||||
|
'to_interface_id'])
|
||||||
|
|
||||||
|
|
||||||
|
def to_dict(message):
|
||||||
|
if isinstance(message, MultipleMessage):
|
||||||
|
d = dict(message._asdict())
|
||||||
|
inner_messages = []
|
||||||
|
for m in d['messages']:
|
||||||
|
inner_messages.append(to_dict(m))
|
||||||
|
d['messages'] = inner_messages
|
||||||
|
return d
|
||||||
|
else:
|
||||||
|
return dict(message._asdict())
|
||||||
Reference in New Issue
Block a user