blob: 37d8dc6a3d71feee42ee15af84316442161c0256 [file] [log] [blame]
Scott Bakerc3ce3e72016-06-20 17:35:19 -07001import os
2import requests
3import socket
4import sys
5import base64
6from django.db.models import F, Q
7from xos.config import Config
8from synchronizers.base.syncstep import SyncStep
9from core.models import Service, Port, Controller, Tag, Tenant
10from core.models.service import COARSE_KIND
Scott Bakerc3ce3e72016-06-20 17:35:19 -070011from xos.logger import Logger, logging
12from requests.auth import HTTPBasicAuth
Scott Baker855a9df2016-09-09 09:23:50 -070013from services.vtn.models import VTNService
Scott Bakerc3ce3e72016-06-20 17:35:19 -070014
15# hpclibrary will be in steps/..
16parentdir = os.path.join(os.path.dirname(__file__),"..")
17sys.path.insert(0,parentdir)
18
19logger = Logger(level=logging.INFO)
20
21# XXX should save and load this
22glo_saved_vtn_maps = []
23
24class SyncPortAddresses(SyncStep):
25 requested_interval = 0 # 3600
26 provides=[Port]
27 observes=Port
28
29 def __init__(self, **args):
30 SyncStep.__init__(self, **args)
31
32 def call(self, **args):
33 global glo_saved_vtn_maps
34
Scott Baker855a9df2016-09-09 09:23:50 -070035 vtn_service = VTNService.get_service_objects().all()
36 if not vtn_service:
37 raise Exception("SyncPortAddresses: No VTN Service")
38 vtn_service = vtn_service[0]
39 if vtn_service.vtnAPIVersion >= 2:
40 logger.info("skipping SyncPortAddresses due to VTN API Version")
41 return
42
Scott Bakerc3ce3e72016-06-20 17:35:19 -070043 # build up a dictionary of port-->[wan_addrs] mappings
44 port_addrs = {}
Andy Bavier59012632016-09-14 08:41:56 -040045 try:
46 from services.vsg.models import VSGTenant
Scott Bakerc3ce3e72016-06-20 17:35:19 -070047
Andy Bavier59012632016-09-14 08:41:56 -040048 logger.info("sync'ing vsg tenant to port addresses")
Scott Bakerc3ce3e72016-06-20 17:35:19 -070049
Andy Bavier59012632016-09-14 08:41:56 -040050 for vsg in VSGTenant.get_tenant_objects().all():
51 if not vsg.instance:
52 logger.info("skipping vsg %s because it has no instance" % vsg)
Scott Bakerc3ce3e72016-06-20 17:35:19 -070053
Andy Bavier59012632016-09-14 08:41:56 -040054 wan_ip = vsg.wan_container_ip
55 if not wan_ip:
56 logger.info("skipping vsg %s because it has no wan_container_ip" % vsg)
Scott Bakerc3ce3e72016-06-20 17:35:19 -070057
Andy Bavier59012632016-09-14 08:41:56 -040058 wan_mac = vsg.wan_container_mac
59 if not wan_mac:
60 logger.info("skipping vsg %s because it has no wan_container_mac" % vsg)
Scott Bakerc3ce3e72016-06-20 17:35:19 -070061
Andy Bavier59012632016-09-14 08:41:56 -040062 lan_network = vsg.get_lan_network(vsg.instance)
63 if not lan_network:
64 logger.info("skipping vsg %s because it has no lan_network" % vsg)
Scott Bakerc3ce3e72016-06-20 17:35:19 -070065
Andy Bavier59012632016-09-14 08:41:56 -040066 lan_port = Port.objects.filter(instance = vsg.instance, network=lan_network)
67 if not lan_port:
68 logger.info("skipping vsg %s because it has no lan_port" % vsg)
69 lan_port = lan_port[0]
Scott Bakerc3ce3e72016-06-20 17:35:19 -070070
Andy Bavier59012632016-09-14 08:41:56 -040071 if not lan_port.port_id:
72 logger.info("skipping vsg %s because its lan_port has no port_id" % vsg)
73
74 if not (lan_port.pk in port_addrs):
75 port_addrs[lan_port.pk] = []
76 entry = {"mac_address": wan_mac, "ip_address": wan_ip}
77 addr_pairs = port_addrs[lan_port.pk]
Scott Bakerc3ce3e72016-06-20 17:35:19 -070078 if not entry in addr_pairs:
79 addr_pairs.append(entry)
80
Andy Bavier59012632016-09-14 08:41:56 -040081 # now do the VM_WAN_IP from the instance
82 if vsg.instance:
83 wan_vm_ip = vsg.wan_vm_ip
84 wan_vm_mac = vsg.wan_vm_mac
85 entry = {"mac_address": wan_vm_mac, "ip_address": wan_vm_ip}
86 if not entry in addr_pairs:
87 addr_pairs.append(entry)
88 except:
89 logger.info("No VSG service present")
90
Scott Bakerc3ce3e72016-06-20 17:35:19 -070091 # Get all ports in all controllers
92 ports_by_id = {}
93 for controller in Controller.objects.all():
94 if not controller.admin_tenant:
95 logger.info("controller %s has no admin_tenant" % controller)
96 continue
97 try:
98 driver = self.driver.admin_driver(controller = controller)
Zack Williamsabe24da2016-06-27 13:09:00 -070099 # FIXME: after LTS merge, use neutron (new name) instead of quantum (old name)
100 # the following if is a workaround
101 if hasattr( driver.shell, "neutron"):
102 ports = driver.shell.neutron.list_ports()["ports"]
103 else:
104 ports = driver.shell.quantum.list_ports()["ports"]
Scott Bakerc3ce3e72016-06-20 17:35:19 -0700105 except:
106 logger.log_exc("failed to get ports from controller %s" % controller)
107 continue
108
109 for port in ports:
110 ports_by_id[port["id"]] = port
111
112 for port_pk in port_addrs.keys():
113 port = Port.objects.get(pk=port_pk)
114 addr_pairs = port_addrs[port_pk]
115 neutron_port = ports_by_id.get(port.port_id,None)
116 if not neutron_port:
117 logger.info("failed to get neutron port for port %s" % port)
118 continue
119
120 ips = [x["ip_address"] for x in addr_pairs]
121
122 changed = False
123
124 # delete addresses in neutron that don't exist in XOS
125 aaps = neutron_port.get("allowed_address_pairs", [])
126 for aap in aaps[:]:
127 if not aap["ip_address"] in ips:
128 logger.info("removing address %s from port %s" % (aap["ip_address"], port))
129 aaps.remove(aap)
130 changed = True
131
132 aaps_ips = [x["ip_address"] for x in aaps]
133
134 # add addresses in XOS that don't exist in neutron
135 for addr in addr_pairs:
136 if not addr["ip_address"] in aaps_ips:
137 logger.info("adding address %s to port %s" % (addr, port))
138 aaps.append( addr )
139 aaps_ips.append(addr["ip_address"])
140 changed = True
141
142 if changed:
143 logger.info("updating port %s" % port)
Zack Williamsabe24da2016-06-27 13:09:00 -0700144 # FIXME: See FIXME above, remove after LTS merge
145 if hasattr( driver.shell, "neutron"):
146 driver.shell.neutron.update_port(port.port_id, {"port": {"allowed_address_pairs": aaps}})
147 else:
148 driver.shell.quantum.update_port(port.port_id, {"port": {"allowed_address_pairs": aaps}})
Scott Bakerc3ce3e72016-06-20 17:35:19 -0700149