blob: eab6cb37bca269ece17967bb4ee26932e3802e59 [file] [log] [blame]
Scott Baker3a055582016-03-25 10:55:03 -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
Scott Baker272ec452016-03-31 16:30:00 -07007from rest_framework import status
Scott Baker3a055582016-03-25 10:55:03 -07008from rest_framework.decorators import detail_route, list_route
9from rest_framework.views import APIView
10from core.models import *
11from django.forms import widgets
12from django.conf.urls import patterns, url
13from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot
Scott Baker272ec452016-03-31 16:30:00 -070014from api.xosapi_helpers import PlusModelSerializer, XOSViewSet, ReadOnlyField
Scott Baker3a055582016-03-25 10:55:03 -070015from django.shortcuts import get_object_or_404
16from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
17from xos.exceptions import *
18import json
19import subprocess
Scott Baker32ff03c2016-03-28 13:23:20 -070020from django.views.decorators.csrf import ensure_csrf_cookie
Scott Baker3a055582016-03-25 10:55:03 -070021
Scott Baker32ff03c2016-03-28 13:23:20 -070022class CordSubscriberNew(CordSubscriberRoot):
23 class Meta:
24 proxy = True
25 app_label = "cord"
Scott Baker3a055582016-03-25 10:55:03 -070026
Scott Baker32ff03c2016-03-28 13:23:20 -070027 def __init__(self, *args, **kwargs):
28 super(CordSubscriberNew, self).__init__(*args, **kwargs)
29
30 def __unicode__(self):
31 return u"cordSubscriber-%s" % str(self.id)
32
33 @property
34 def features(self):
35 return {"cdn": self.cdn_enable,
36 "uplink_speed": self.uplink_speed,
37 "downlink_speed": self.downlink_speed,
38 "uverse": self.enable_uverse,
39 "status": self.status}
40
41 @features.setter
42 def features(self, value):
43 self.cdn_enable = value.get("cdn", self.get_default_attribute("cdn_enable"))
44 self.uplink_speed = value.get("uplink_speed", self.get_default_attribute("uplink_speed"))
45 self.downlink_speed = value.get("downlink_speed", self.get_default_attribute("downlink_speed"))
46 self.enable_uverse = value.get("uverse", self.get_default_attribute("enable_uverse"))
47 self.status = value.get("status", self.get_default_attribute("status"))
48
Scott Baker75596d82016-03-31 11:53:57 -070049
Scott Bakerb311ef72016-03-28 15:07:36 -070050 def update_features(self, value):
51 d=self.features
52 d.update(value)
53 self.features = d
54
Scott Baker6b6e1ef2016-03-28 16:23:53 -070055 @property
56 def identity(self):
Scott Bakerda501fc2016-04-01 09:17:35 -070057 return {"account_num": self.service_specific_id,
58 "name": self.name}
Scott Baker6b6e1ef2016-03-28 16:23:53 -070059
60 @identity.setter
61 def identity(self, value):
Scott Bakerda501fc2016-04-01 09:17:35 -070062 self.service_specific_id = value.get("account_num", self.service_specific_id)
63 self.name = value.get("name", self.name)
Scott Baker6b6e1ef2016-03-28 16:23:53 -070064
65 def update_identity(self, value):
66 d=self.identity
67 d.update(value)
68 self.identity = d
69
70 @property
71 def related(self):
72 related = {}
73 if self.volt:
74 related["volt_id"] = self.volt.id
75 related["s_tag"] = self.volt.s_tag
76 related["c_tag"] = self.volt.c_tag
77 if self.volt.vcpe:
78 related["vsg_id"] = self.volt.vcpe.id
79 if self.volt.vcpe.instance:
80 related["instance_id"] = self.volt.vcpe.instance.id
81 related["instance_name"] = self.volt.vcpe.instance.name
82 related["wan_container_ip"] = self.volt.vcpe.wan_container_ip
Scott Bakere8b53682016-03-30 09:42:56 -070083 if self.volt.vcpe.instance.node:
84 related["compute_node_name"] = self.volt.vcpe.instance.node.name
Scott Baker6b6e1ef2016-03-28 16:23:53 -070085 return related
86
Scott Baker32ff03c2016-03-28 13:23:20 -070087 def save(self, *args, **kwargs):
88 super(CordSubscriberNew, self).save(*args, **kwargs)
89
Scott Bakerf6720582016-05-05 15:02:19 -070090class CordDevice(object):
91 def __init__(self, d={}, subscriber=None):
92 self.d = d
93 self.subscriber = subscriber
94
95 @property
96 def mac(self):
97 return self.d.get("mac", None)
98
99 @mac.setter
100 def mac(self, value):
101 self.d["mac"] = value
102
103 @property
104 def identity(self):
105 return {"name": self.d.get("name", None)}
106
107 @identity.setter
108 def identity(self, value):
109 self.d["name"] = value.get("name", None)
110
111 @property
112 def features(self):
113 return {"uplink_speed": self.d.get("uplink_speed", None),
114 "downlink_speed": self.d.get("downlink_speed", None)}
115
116 @features.setter
117 def features(self, value):
118 self.d["uplink_speed"] = value.get("uplink_speed", None)
119 self.d["downlink_speed"] = value.get("downlink_speed", None)
120
Scott Bakercaf3a932016-05-05 17:32:56 -0700121 def update_features(self, value):
122 d=self.features
123 d.update(value)
124 self.features = d
125
Scott Baker94da9c12016-05-06 12:32:58 -0700126 def update_identity(self, value):
127 d=self.identity
128 d.update(value)
129 self.identity = d
130
Scott Bakerf6720582016-05-05 15:02:19 -0700131 def save(self):
132 if self.subscriber:
133 dev=self.subscriber.find_device(self.mac)
134 if dev:
Scott Bakercaf3a932016-05-05 17:32:56 -0700135 self.subscriber.update_device(**self.d)
Scott Bakerf6720582016-05-05 15:02:19 -0700136 else:
137 self.subscriber.create_device(**self.d)
138
Scott Bakerda501fc2016-04-01 09:17:35 -0700139# Add some structure to the REST API by subdividing the object into
140# features, identity, and related.
141
Scott Bakerb311ef72016-03-28 15:07:36 -0700142class FeatureSerializer(serializers.Serializer):
143 cdn = serializers.BooleanField(required=False)
144 uplink_speed = serializers.IntegerField(required=False)
145 downlink_speed = serializers.IntegerField(required=False)
146 uverse = serializers.BooleanField(required=False)
147 status = serializers.CharField(required=False)
Scott Baker32ff03c2016-03-28 13:23:20 -0700148
Scott Baker6b6e1ef2016-03-28 16:23:53 -0700149class IdentitySerializer(serializers.Serializer):
150 account_num = serializers.CharField(required=False)
Scott Bakerda501fc2016-04-01 09:17:35 -0700151 name = serializers.CharField(required=False)
Scott Baker6b6e1ef2016-03-28 16:23:53 -0700152
Scott Bakerf6720582016-05-05 15:02:19 -0700153class DeviceFeatureSerializer(serializers.Serializer):
154 uplink_speed = serializers.IntegerField(required=False)
155 downlink_speed = serializers.IntegerField(required=False)
156
157class DeviceIdentitySerializer(serializers.Serializer):
158 name = serializers.CharField(required=False)
159
160class DeviceSerializer(serializers.Serializer):
161 mac = serializers.CharField(required=True)
162 identity = DeviceIdentitySerializer(required=False)
163 features = DeviceFeatureSerializer(required=False)
164
165 class Meta:
166 fields = ('mac', 'identity', 'features')
167
Scott Baker272ec452016-03-31 16:30:00 -0700168class CordSubscriberSerializer(PlusModelSerializer):
Scott Baker3a055582016-03-25 10:55:03 -0700169 id = ReadOnlyField()
Scott Baker3a055582016-03-25 10:55:03 -0700170 humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
Scott Baker75596d82016-03-31 11:53:57 -0700171 features = FeatureSerializer(required=False)
172 identity = IdentitySerializer(required=False)
Scott Baker6b6e1ef2016-03-28 16:23:53 -0700173 related = serializers.DictField(required=False)
Scott Baker3a055582016-03-25 10:55:03 -0700174
Scott Bakerd52e1d92016-03-31 12:00:15 -0700175 nested_fields = ["features", "identity"]
176
Scott Baker3a055582016-03-25 10:55:03 -0700177 class Meta:
Scott Baker32ff03c2016-03-28 13:23:20 -0700178 model = CordSubscriberNew
179 fields = ('humanReadableName',
180 'id',
Scott Baker6b6e1ef2016-03-28 16:23:53 -0700181 'features',
182 'identity',
183 'related')
Scott Baker3a055582016-03-25 10:55:03 -0700184
185 def getHumanReadableName(self, obj):
186 return obj.__unicode__()
187
Scott Baker32ff03c2016-03-28 13:23:20 -0700188# @ensure_csrf_cookie
Scott Baker3a055582016-03-25 10:55:03 -0700189class CordSubscriberViewSet(XOSViewSet):
190 base_name = "subscriber"
Scott Baker40fa2302016-03-25 13:33:11 -0700191 method_name = "subscriber"
Scott Baker3a055582016-03-25 10:55:03 -0700192 method_kind = "viewset"
Scott Baker32ff03c2016-03-28 13:23:20 -0700193 queryset = CordSubscriberNew.get_tenant_objects().select_related().all()
194 serializer_class = CordSubscriberSerializer
Scott Baker3a055582016-03-25 10:55:03 -0700195
Scott Baker6291e492016-04-05 21:27:10 -0700196 custom_serializers = {"set_features": FeatureSerializer,
197 "set_feature": FeatureSerializer,
198 "set_identities": IdentitySerializer,
Scott Bakerf6720582016-05-05 15:02:19 -0700199 "set_identity": IdentitySerializer,
200 "get_devices": DeviceSerializer,
Scott Baker61e116d2016-05-05 16:34:53 -0700201 "add_device": DeviceSerializer,
202 "get_device_feature": DeviceFeatureSerializer,
203 "set_device_feature": DeviceFeatureSerializer}
Scott Baker6291e492016-04-05 21:27:10 -0700204
Scott Baker3a055582016-03-25 10:55:03 -0700205 @classmethod
Scott Baker3dbdc872016-03-28 13:22:10 -0700206 def get_urlpatterns(self, api_path="^"):
Scott Baker40fa2302016-03-25 13:33:11 -0700207 patterns = super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path)
Scott Baker32ff03c2016-03-28 13:23:20 -0700208 patterns.append( self.detail_url("features/$", {"get": "get_features", "put": "set_features"}, "features") )
209 patterns.append( self.detail_url("features/(?P<feature>[a-zA-Z0-9\-_]+)/$", {"get": "get_feature", "put": "set_feature"}, "get_feature") )
Scott Baker118ea232016-03-28 16:39:56 -0700210 patterns.append( self.detail_url("identity/$", {"get": "get_identities", "put": "set_identities"}, "identities") )
211 patterns.append( self.detail_url("identity/(?P<identity>[a-zA-Z0-9\-_]+)/$", {"get": "get_identity", "put": "set_identity"}, "get_identity") )
Scott Baker3a055582016-03-25 10:55:03 -0700212
Scott Bakerf6720582016-05-05 15:02:19 -0700213 patterns.append( self.detail_url("devices/$", {"get": "get_devices", "post": "add_device"}, "devicees") )
Scott Bakerc1ada2a2016-05-06 12:45:07 -0700214 patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/$", {"get": "get_device", "delete": "delete_device"}, "getset_device") )
Scott Baker61e116d2016-05-05 16:34:53 -0700215 patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/features/(?P<feature>[a-zA-Z0-9\-_]+)/$", {"get": "get_device_feature", "put": "set_device_feature"}, "getset_device_feature") )
Scott Baker94da9c12016-05-06 12:32:58 -0700216 patterns.append( self.detail_url("devices/(?P<mac>[a-zA-Z0-9\-_:]+)/identity/(?P<identity>[a-zA-Z0-9\-_]+)/$", {"get": "get_device_identity", "put": "set_device_identity"}, "getset_device_identity") )
Scott Bakerf6720582016-05-05 15:02:19 -0700217
Scott Baker272ec452016-03-31 16:30:00 -0700218 patterns.append( url(self.api_path + "account_num_lookup/(?P<account_num>[0-9\-]+)/$", self.as_view({"get": "account_num_detail"}), name="account_num_detail") )
219
220 patterns.append( url(self.api_path + "ssidmap/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") )
221 patterns.append( url(self.api_path + "ssidmap/$", self.as_view({"get": "ssidlist"}), name="ssidlist") )
Scott Baker3a055582016-03-25 10:55:03 -0700222
223 return patterns
224
225 def list(self, request):
226 object_list = self.filter_queryset(self.get_queryset())
227
228 serializer = self.get_serializer(object_list, many=True)
229
Scott Bakerb311ef72016-03-28 15:07:36 -0700230 return Response(serializer.data)
Scott Baker3a055582016-03-25 10:55:03 -0700231
Scott Baker32ff03c2016-03-28 13:23:20 -0700232 def get_features(self, request, pk=None):
Scott Baker3a055582016-03-25 10:55:03 -0700233 subscriber = self.get_object()
Scott Bakerb311ef72016-03-28 15:07:36 -0700234 return Response(FeatureSerializer(subscriber.features).data)
Scott Baker3a055582016-03-25 10:55:03 -0700235
Scott Baker118ea232016-03-28 16:39:56 -0700236 def set_features(self, request, pk=None):
237 subscriber = self.get_object()
238 ser = FeatureSerializer(subscriber.features, data=request.data)
239 ser.is_valid(raise_exception = True)
240 subscriber.update_features(ser.validated_data)
241 subscriber.save()
242 return Response(FeatureSerializer(subscriber.features).data)
243
Scott Baker32ff03c2016-03-28 13:23:20 -0700244 def get_feature(self, request, pk=None, feature=None):
Scott Baker3a055582016-03-25 10:55:03 -0700245 subscriber = self.get_object()
Scott Bakerb311ef72016-03-28 15:07:36 -0700246 return Response({feature: FeatureSerializer(subscriber.features).data[feature]})
Scott Baker3a055582016-03-25 10:55:03 -0700247
Scott Baker32ff03c2016-03-28 13:23:20 -0700248 def set_feature(self, request, pk=None, feature=None):
Scott Baker3a055582016-03-25 10:55:03 -0700249 subscriber = self.get_object()
Scott Bakerb311ef72016-03-28 15:07:36 -0700250 if [feature] != request.data.keys():
251 raise serializers.ValidationError("feature %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
252 ser = FeatureSerializer(subscriber.features, data=request.data)
253 ser.is_valid(raise_exception = True)
254 subscriber.update_features(ser.validated_data)
Scott Baker118ea232016-03-28 16:39:56 -0700255 subscriber.save()
Scott Baker6b6e1ef2016-03-28 16:23:53 -0700256 return Response({feature: FeatureSerializer(subscriber.features).data[feature]})
Scott Baker3a055582016-03-25 10:55:03 -0700257
Scott Baker118ea232016-03-28 16:39:56 -0700258 def get_identities(self, request, pk=None):
Scott Baker3a055582016-03-25 10:55:03 -0700259 subscriber = self.get_object()
Scott Baker118ea232016-03-28 16:39:56 -0700260 return Response(IdentitySerializer(subscriber.identity).data)
261
262 def set_identities(self, request, pk=None):
263 subscriber = self.get_object()
264 ser = IdentitySerializer(subscriber.identity, data=request.data)
Scott Bakerb311ef72016-03-28 15:07:36 -0700265 ser.is_valid(raise_exception = True)
Scott Baker118ea232016-03-28 16:39:56 -0700266 subscriber.update_identity(ser.validated_data)
Scott Bakerb311ef72016-03-28 15:07:36 -0700267 subscriber.save()
Scott Baker118ea232016-03-28 16:39:56 -0700268 return Response(IdentitySerializer(subscriber.identity).data)
269
270 def get_identity(self, request, pk=None, identity=None):
271 subscriber = self.get_object()
272 return Response({identity: IdentitySerializer(subscriber.identity).data[identity]})
273
274 def set_identity(self, request, pk=None, identity=None):
275 subscriber = self.get_object()
276 if [identity] != request.data.keys():
277 raise serializers.ValidationError("identity %s does not match keys in request body (%s)" % (identity, ",".join(request.data.keys())))
278 ser = IdentitySerializer(subscriber.identity, data=request.data)
279 ser.is_valid(raise_exception = True)
280 subscriber.update_identity(ser.validated_data)
281 subscriber.save()
282 return Response({identity: IdentitySerializer(subscriber.identity).data[identity]})
Scott Baker3a055582016-03-25 10:55:03 -0700283
Scott Bakerf6720582016-05-05 15:02:19 -0700284 def get_devices(self, request, pk=None):
285 subscriber = self.get_object()
286 result = []
287 for device in subscriber.devices:
Scott Baker61e116d2016-05-05 16:34:53 -0700288 device = CordDevice(device, subscriber)
Scott Bakerf6720582016-05-05 15:02:19 -0700289 result.append(DeviceSerializer(device).data)
290 return Response(result)
291
292 def add_device(self, request, pk=None):
293 subscriber = self.get_object()
294 ser = DeviceSerializer(subscriber.devices, data=request.data)
295 ser.is_valid(raise_exception = True)
Scott Baker8ad4e392016-05-05 16:57:27 -0700296 newdevice = CordDevice(subscriber.create_device(**ser.validated_data), subscriber)
Scott Bakerf6720582016-05-05 15:02:19 -0700297 subscriber.save()
298 return Response(DeviceSerializer(newdevice).data)
299
300 def get_device(self, request, pk=None, mac=None):
301 subscriber = self.get_object()
302 device = subscriber.find_device(mac)
303 if not device:
304 return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
Scott Baker61e116d2016-05-05 16:34:53 -0700305 return Response(DeviceSerializer(CordDevice(device, subscriber)).data)
306
Scott Bakerc1ada2a2016-05-06 12:45:07 -0700307 def delete_device(self, request, pk=None, mac=None):
308 subscriber = self.get_object()
309 device = subscriber.find_device(mac)
310 if not device:
311 return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
312 subscriber.delete_device(mac)
313 subscriber.save()
314 return Response("Okay")
315
Scott Baker61e116d2016-05-05 16:34:53 -0700316 def get_device_feature(self, request, pk=None, mac=None, feature=None):
317 subscriber = self.get_object()
318 device = subscriber.find_device(mac)
319 if not device:
320 return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
321 return Response({feature: DeviceFeatureSerializer(CordDevice(device, subscriber).features).data[feature]})
322
323 def set_device_feature(self, request, pk=None, mac=None, feature=None):
324 subscriber = self.get_object()
325 device = subscriber.find_device(mac)
326 if not device:
327 return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
328 if [feature] != request.data.keys():
329 raise serializers.ValidationError("feature %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
330 device = CordDevice(device, subscriber)
331 ser = DeviceFeatureSerializer(device.features, data=request.data)
332 ser.is_valid(raise_exception = True)
333 device.update_features(ser.validated_data)
334 device.save()
335 subscriber.save()
Scott Bakercaf3a932016-05-05 17:32:56 -0700336 return Response({feature: DeviceFeatureSerializer(device.features).data[feature]})
Scott Bakerf6720582016-05-05 15:02:19 -0700337
Scott Baker94da9c12016-05-06 12:32:58 -0700338 def get_device_identity(self, request, pk=None, mac=None, identity=None):
339 subscriber = self.get_object()
340 device = subscriber.find_device(mac)
341 if not device:
342 return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
343 return Response({identity: DeviceIdentitySerializer(CordDevice(device, subscriber).identity).data[identity]})
344
345 def set_device_identity(self, request, pk=None, mac=None, identity=None):
346 subscriber = self.get_object()
347 device = subscriber.find_device(mac)
348 if not device:
349 return Response("Failed to find device %s" % mac, status=status.HTTP_404_NOT_FOUND)
350 if [identity] != request.data.keys():
351 raise serializers.ValidationError("identity %s does not match keys in request body (%s)" % (feature, ",".join(request.data.keys())))
352 device = CordDevice(device, subscriber)
353 ser = DeviceIdentitySerializer(device.identity, data=request.data)
354 ser.is_valid(raise_exception = True)
355 device.update_identity(ser.validated_data)
356 device.save()
357 subscriber.save()
358 return Response({identity: DeviceIdentitySerializer(device.identity).data[identity]})
359
Scott Baker272ec452016-03-31 16:30:00 -0700360 def account_num_detail(self, pk=None, account_num=None):
361 object_list = CordSubscriberNew.get_tenant_objects().all()
362 object_list = [x for x in object_list if x.service_specific_id == account_num]
363 if not object_list:
364 return Response("Failed to find account_num %s" % account_num, status=status.HTTP_404_NOT_FOUND)
365
366 return Response( object_list[0].id )
367
Scott Baker3a055582016-03-25 10:55:03 -0700368 def ssidlist(self, request):
Scott Baker32ff03c2016-03-28 13:23:20 -0700369 object_list = CordSubscriberNew.get_tenant_objects().all()
Scott Baker3a055582016-03-25 10:55:03 -0700370
371 ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list ]
372
373 return Response({"ssidmap": ssidmap})
374
375 def ssiddetail(self, pk=None, ssid=None):
Scott Baker32ff03c2016-03-28 13:23:20 -0700376 object_list = CordSubscriberNew.get_tenant_objects().all()
Scott Baker3a055582016-03-25 10:55:03 -0700377
378 ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list if str(x.service_specific_id)==str(ssid) ]
379
380 if len(ssidmap)==0:
381 raise XOSNotFound("didn't find ssid %s" % str(ssid))
382
383 return Response( ssidmap[0] )
384