blob: 5ab5223da3181191bd19ec4f1bb3fe69c0116819 [file] [log] [blame]
Scott Bakerc3ce3e72016-06-20 17:35:19 -07001from rest_framework.decorators import api_view
2from rest_framework.response import Response
3from rest_framework.reverse import reverse
4from rest_framework import serializers
5from rest_framework import generics
6from rest_framework import viewsets
7from rest_framework.decorators import detail_route, list_route
8from rest_framework.views import APIView
Scott Bakerc3800fa2016-08-25 15:30:43 -07009from rest_framework import status
Scott Bakerc3ce3e72016-06-20 17:35:19 -070010from core.models import *
11from services.vtn.models import VTNService
12from django.forms import widgets
13from django.conf.urls import patterns, url
14from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
15from django.shortcuts import get_object_or_404
16from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
17from xos.exceptions import *
18import json
19import subprocess
20
Scott Bakerc3800fa2016-08-25 15:30:43 -070021VTN_SERVCOMP_KINDS=["PRIVATE","VSG"]
22
Scott Bakerc3ce3e72016-06-20 17:35:19 -070023class VTNServiceSerializer(PlusModelSerializer):
24 id = ReadOnlyField()
25
26 privateGatewayMac = serializers.CharField(required=False)
27 localManagementIp = serializers.CharField(required=False)
28 ovsdbPort = serializers.IntegerField(required=False)
29 sshPort = serializers.IntegerField(required=False)
30 sshUser = serializers.CharField(required=False)
31 sshKeyFile = serializers.CharField(required=False)
32 mgmtSubnetBits = serializers.IntegerField(required=False)
33 xosEndpoint = serializers.CharField(required=False)
34 xosUser = serializers.CharField(required=False)
35 xosPassword = serializers.CharField(required=False)
36
Scott Bakerc3ce3e72016-06-20 17:35:19 -070037 humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
38 class Meta:
39 model = VTNService
40 fields = ('humanReadableName', 'id', 'privateGatewayMac', 'localManagementIp', 'ovsdbPort', 'sshPort', 'sshUser', 'sshKeyFile',
41 'mgmtSubnetBits', 'xosEndpoint', 'xosUser', 'xosPassword')
42
43 def getHumanReadableName(self, obj):
44 return obj.__unicode__()
45
Scott Bakerc3800fa2016-08-25 15:30:43 -070046class VTNNetwork(object):
47 def __init__(self, xos_network=None):
48 self.xos_network = xos_network
49
50 def get_controller_network(self):
51 for cn in self.xos_network.controllernetworks.all():
52 # TODO: find the right one
53 return cn
54 return None
55
56 def get_cn_field(self, fieldname):
57 cn=self.get_controller_network()
58 if not cn:
59 return None
60 return getattr(cn, fieldname)
61
62 @property
63 def id(self):
64 return self.get_cn_field("net_id")
65
66 @property
67 def name(self):
68 return self.xos_network.name
69
70 @property
71 def subnet(self):
72 return self.get_cn_field("subnet")
73
74 @property
75 def gateway(self):
76 return self.get_cn_field("gateway")
77
78 @property
79 def segmentation_id(self):
80 return self.get_cn_field("segmentation_id")
81
82 @property
83 def type(self):
84 return self.xos_network.template.vtn_kind
85
86 @property
87 def providerNetworks(self):
88 slice = self.xos_network.owner
89 service = slice.service
90 if not service:
91 return []
92
93 nets=[]
94 for tenant in service.subscribed_tenants.all():
95 if tenant.provider_service:
96 bidirectional = tenant.connect_method!="private-unidirectional"
97 for slice in tenant.provider_service.slices.all():
98 for net in slice.networks.all():
99 if net.template.vtn_kind not in VTN_SERVCOMP_KINDS:
100 continue
101
102 if not net.controllernetworks.exists():
103 continue
104
105 cn = net.controllernetworks.all()[0]
106 nets.append({"id": cn.net_id,
107 "name": net.name,
108 "bidirectional": bidirectional})
109 return nets
110
111 @property
112 def subscriberNetworks(self):
113 slice = self.xos_network.owner
114 service = slice.service
115 if not service:
116 return []
117
118 nets=[]
119 for tenant in service.provided_tenants.all():
120 if tenant.subscriber_service:
121 bidirectional = tenant.connect_method!="private-unidirectional"
122 for slice in tenant.subscriber_service.slices.all():
123 for net in slice.networks.all():
124 if net.template.vtn_kind not in VTN_SERVCOMP_KINDS:
125 continue
126
127 if not net.controllernetworks.exists():
128 continue
129
130 cn = net.controllernetworks.all()[0]
131 nets.append({"id": cn.net_id,
132 "name": net.name,
133 "bidirectional": bidirectional})
134 return nets
135
136 @property
137 def ownerSliceName(self):
138 if self.xos_network.owner:
139 return self.xos_network.owner.name
140 return None
141
142 @property
143 def ownerServiceName(self):
144 if self.xos_network.owner and self.xos_network.owner.service:
145 return self.xos_network.owner.service.name
146 return None
147
148class VTNNetworkSerializer(serializers.Serializer):
149 id = ReadOnlyField()
150 name = serializers.CharField(required=False)
151 subnet = serializers.CharField(required=False)
152 gateway = serializers.CharField(required=False)
153 segmentation_id = serializers.CharField(required=False)
154
155 class Meta:
156 fields = ('id', 'name', 'subnet', 'gateway', 'segmentation_id')
157
158class VTNServiceNetworkSerializer(serializers.Serializer):
159 id = ReadOnlyField()
160 type = serializers.CharField(required=False)
161 subscriberNetworks = serializers.SerializerMethodField("getSubscriberNetworks")
162 providerNetworks = serializers.SerializerMethodField("getProviderNetworks")
163 ownerSliceName = ReadOnlyField()
164 ownerServiceName = ReadOnlyField()
165
166 class Meta:
167 fields = ('id', 'type', "subscriberNetworks", "providerNetworks", "ownerSliceName", "ownerServiceName")
168
169 def getSubscriberNetworks(self, obj):
170 return obj.subscriberNetworks
171
172 def getProviderNetworks(self, obj):
173 return obj.providerNetworks
174
175class VTNPort(object):
176 def __init__(self, xos_port=None):
177 self.xos_port = xos_port
178
179 def get_controller_network(self):
180 for cn in self.xos_port.network.controllernetworks.all():
181 # TODO: find the right one
182 return cn
183 return None
184
185 def get_vsg_tenant(self):
186 from services.vsg.models import VSGTenant
187 for tenant in VSGTenant.get_tenant_objects().all():
188 if tenant.instance == self.xos_port.instance:
189 return tenant
190 return None
191
192 @property
193 def vlan_id(self):
194 if not self.xos_port.instance:
195 return None
196 tags = Tag.select_by_content_object(self.xos_port.instance).filter(name="s_tag")
197 if not tags:
198 return None
199 return tags[0].value
200
201 @property
202 def floating_address_pairs(self):
203 address_pairs = []
204 vsg = self.get_vsg_tenant()
205 if vsg:
206 if vsg.wan_container_ip and vsg.wan_container_mac:
207 address_pairs.append({"ip_address": vsg.wan_container_ip,
208 "mac_address": vsg.wan_container_mac})
209
210 if vsg.wan_vm_ip and vsg.wan_vm_mac:
211 address_pairs.append({"ip_address": vsg.wan_vm_ip,
212 "mac_address": vsg.wan_vm_mac})
213
214 return address_pairs
215
216 @property
217 def id(self):
218 return self.xos_port.port_id
219
220 @property
221 def name(self):
222 return "port-%s" % self.xos_port.id
223
224 @property
225 def network_id(self):
226 cn = self.get_controller_network()
227 if not cn:
228 return None
229 return cn.net_id
230
231 @property
232 def mac_address(self):
233 return self.xos_port.mac
234
235 @property
236 def ip_address(self):
237 return self.xos_port.ip
238
239class VTNPortSerializer(serializers.Serializer):
240 id = ReadOnlyField()
241 name = serializers.CharField(required=False)
242 network_id = serializers.CharField(required=False)
243 mac_address = serializers.CharField(required=False)
244 ip_address = serializers.CharField(required=False)
245
246 class Meta:
247 fields = ('id', 'name', 'network_id', 'mac_address', 'ip_address')
248
249class FloatingAddressPairSerializer(serializers.Serializer):
250 ip_address = ReadOnlyField()
251 mac_address = ReadOnlyField()
252
253class VTNServicePortSerializer(serializers.Serializer):
254 id = ReadOnlyField()
255 vlan_id = serializers.IntegerField(required=False)
256
257 # TODO: structure this better
258 floating_address_pairs = serializers.SerializerMethodField("getFloatingAddressPairs")
259
260 class Meta:
261 fields = ('id', 'vlan_id')
262
263 def getFloatingAddressPairs(self, obj):
264 return obj.floating_address_pairs
265
Scott Bakerc3ce3e72016-06-20 17:35:19 -0700266class VTNViewSet(XOSViewSet):
267 base_name = "vtn"
268 method_name = "vtn"
269 method_kind = "viewset"
270
271 # these are just because ViewSet needs some queryset and model, even if we don't use the
272 # default endpoints
273 queryset = VTNService.get_service_objects().all()
274 model = VTNService
275 serializer_class = VTNServiceSerializer
276
Scott Bakerc3800fa2016-08-25 15:30:43 -0700277 custom_serializers = {"get_port": VTNPortSerializer,
278 "get_ports": VTNPortSerializer,
279 "get_network": VTNNetworkSerializer,
280 "get_networks": VTNNetworkSerializer}
281
Scott Bakerc3ce3e72016-06-20 17:35:19 -0700282 @classmethod
283 def get_urlpatterns(self, api_path="^"):
284 patterns = []
285
286 patterns.append( self.detail_url("services/$", {"get": "get_services"}, "services") )
287 patterns.append( self.detail_url("services_names/$", {"get": "get_services_names"}, "services") )
288 patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") )
289
290 # Not as RESTful as it could be, but maintain these endpoints for compability
291 patterns.append( self.list_url("services/$", {"get": "get_services"}, "rootvtn_services") )
292 patterns.append( self.list_url("services_names/$", {"get": "get_services_names"}, "rootvtn_services") )
293 patterns.append( self.list_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "rootvtn_get_service") )
294
Scott Bakerc3800fa2016-08-25 15:30:43 -0700295 # Neutron-replacement APIs
296 patterns.append( self.list_url("ports/$", {"get": "get_ports"}, "vtn_ports") )
297 patterns.append( self.list_url("ports/(?P<port_id>[a-zA-Z0-9\-_]+)/$", {"get": "get_port"}, "vtn_port") )
298 patterns.append( self.list_url("networks/$", {"get": "get_networks"}, "vtn_networks") )
299 patterns.append( self.list_url("networks/(?P<network_id>[a-zA-Z0-9\-_]+)/$", {"get": "get_network"}, "vtn_network") )
300
301 patterns.append( self.list_url("servicePorts/$", {"get": "get_service_ports"}, "vtn_service_ports") )
302 patterns.append( self.list_url("servicePorts/(?P<port_id>[a-zA-Z0-9\-_]+)/$", {"get": "get_service_port"}, "vtn_service_port") )
303 patterns.append( self.list_url("serviceNetworks/$", {"get": "get_service_networks"}, "vtn_service_networks") )
304 patterns.append( self.list_url("serviceNetworks/(?P<network_id>[a-zA-Z0-9\-_]+)/$", {"get": "get_service_network"}, "vtn_service_network") )
305
Scott Bakerc3ce3e72016-06-20 17:35:19 -0700306 patterns = patterns + super(VTNViewSet,self).get_urlpatterns(api_path)
307
308 return patterns
309
310 def get_services_names(self, request, pk=None):
311 result = {}
312 for service in Service.objects.all():
313 for id in service.get_vtn_src_names():
314 dependencies = service.get_vtn_dependencies_names()
315 if dependencies:
316 result[id] = dependencies
317 return Response(result)
318
319 def get_services(self, request, pk=None):
320 result = {}
321 for service in Service.objects.all():
322 for id in service.get_vtn_src_ids():
323 dependencies = service.get_vtn_dependencies_ids()
324 if dependencies:
325 result[id] = dependencies
326 return Response(result)
327
328 def get_service(self, request, pk=None, service=None):
329 for xos_service in Service.objects.all():
330 if service in xos_service.get_vtn_src_ids():
331 return Response(xos_service.get_vtn_dependencies_ids())
332 return Response([])
333
Scott Bakerc3800fa2016-08-25 15:30:43 -0700334 def get_ports(self, request):
335 result=[]
336 for port in Port.objects.all():
337 result.append(VTNPortSerializer(VTNPort(port)).data)
338 return Response(result)
339
340 def get_port(self, request, port_id=None):
341 port = Port.objects.filter(port_id = port_id)
342 if port:
343 port=port[0]
344 else:
345 return Response("Failed to find port %s" % port_id, status=status.HTTP_404_NOT_FOUND)
346 return Response(VTNPortSerializer(VTNPort(port)).data)
347
348 def get_service_ports(self, request):
349 result=[]
350 for port in Port.objects.all():
351 result.append(VTNServicePortSerializer(VTNPort(port)).data)
352 return Response(result)
353
354 def get_service_port(self, request, port_id=None):
355 port = Port.objects.filter(port_id = port_id)
356 if port:
357 port=port[0]
358 else:
359 return Response("Failed to find port %s" % port_id, status=status.HTTP_404_NOT_FOUND)
360 return Response(VTNServicePortSerializer(VTNPort(port)).data)
361
362 def get_networks(self, request):
363 result=[]
364 for network in Network.objects.all():
365 result.append(VTNNetworkSerializer(VTNNetwork(network)).data)
366 return Response(result)
367
368 def get_network(self, request, network_id=None):
369 network = Network.objects.filter(network_id = network_id)
370 if network:
371 network=network[0]
372 else:
373 return Response("Failed to find network %s" % network_id, status=status.HTTP_404_NOT_FOUND)
374 return Response(VTNNetworkSerializer(VTNNetwork(network)).data)
375
376 def get_service_networks(self, request):
377 result=[]
378 for network in Network.objects.all():
379 result.append(VTNServiceNetworkSerializer(VTNNetwork(network)).data)
380 return Response(result)
381
382 def get_service_network(self, request, network_id=None):
383 network = Network.objects.filter(network_id = network_id)
384 if network:
385 network=network[0]
386 else:
387 return Response("Failed to find network %s" % network_id, status=status.HTTP_404_NOT_FOUND)
388 return Response(VTNServiceNetworkSerializer(VTNNetwork(network)).data)
389
390
Scott Bakerc3ce3e72016-06-20 17:35:19 -0700391