blob: cc52bc6eeef8ff674d8610581ba00184e7d2db0f [file] [log] [blame]
Pingping Lind28ab982016-08-29 18:42:52 +00001from django.db import models
Sapan Bhatia851e30c2017-05-19 23:10:52 +02002from core.models import Service, XOSBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, AddressPool, Port
3from core.models.xosbase import StrippedCharField
Pingping Lind28ab982016-08-29 18:42:52 +00004import os
5from django.db import models, transaction
6from django.forms.models import model_to_dict
7from django.db.models import Q
8from operator import itemgetter, attrgetter, methodcaller
9from core.models import Tag
10from core.models.service import LeastLoadedNodeScheduler
11import traceback
12from xos.exceptions import *
13from core.models import SlicePrivilege, SitePrivilege
14from sets import Set
15from xos.config import Config
16
17MCORD_KIND = "RAN" # This should be changed later I did it fo demo
18MCORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
19VBBU_KIND = "RAN"
20VSGW_KIND = "vSGW"
21VPGWC_KIND = "RAN"
22vbbu_net_types = ("s1u", "s1mme", "rru")
23vpgwc_net_types = ("s5s8")
24# The class to represent the service. Most of the service logic is given for us
25# in the Service class but, we have some configuration that is specific for
26# this example.
27class MCORDService(Service):
28 KIND = MCORD_KIND
29
30 class Meta:
31 # When the proxy field is set to True the model is represented as
32 # it's superclass in the database, but we can still change the python
33 # behavior. In this case HelloWorldServiceComplete is a Service in the
34 # database.
35 proxy = True
36 # The name used to find this service, all directories are named this
Pingping Lincff3a022016-09-19 21:29:54 +000037 app_label = "vbbu"
Pingping Lind28ab982016-08-29 18:42:52 +000038 verbose_name = "MCORD Service"
39
40# This is the class to represent the tenant. Most of the logic is given to use
41# in TenantWithContainer, however there is some configuration and logic that
42# we need to define for this example.
43class VBBUComponent(TenantWithContainer):
44
45 class Meta:
46 # Same as a above, HelloWorldTenantComplete is represented as a
47 # TenantWithContainer, but we change the python behavior.
48 proxy = True
49 verbose_name = "VBBU MCORD Service Component"
50
51 # The kind of the service is used on forms to differentiate this service
52 # from the other services.
53 KIND = VBBU_KIND
54
55 # Ansible requires that the sync_attributes field contain nat_ip and nat_mac
56 # these will be used to determine where to SSH to for ansible.
57 # Getters must be defined for every attribute specified here.
58 sync_attributes = ("s1u_ip", "s1u_mac",
59 "s1mme_ip", "s1mme_mac",
60 "rru_ip", "rru_mac")
61 # default_attributes is used cleanly indicate what the default values for
62 # the fields are.
63 default_attributes = {"display_message": "New vBBU Component", "s1u_tag": "901", "s1mme_tag": "900", "rru_tag": "999"}
64 def __init__(self, *args, **kwargs):
65 mcord_services = MCORDService.get_service_objects().all()
66 # When the tenant is created the default service in the form is set
67 # to be the first created HelloWorldServiceComplete
68 if mcord_services:
69 self._meta.get_field(
70 "provider_service").default = mcord_services[0].id
71 super(VBBUComponent, self).__init__(*args, **kwargs)
72
73 def can_update(self, user):
74 #Allow creation of this model instances for non-admin users also
75 return True
76
77 def save(self, *args, **kwargs):
78 if not self.creator:
79 if not getattr(self, "caller", None):
80 # caller must be set when creating a monitoring channel since it creates a slice
81 raise XOSProgrammingError("ServiceComponents's self.caller was not set")
82 self.creator = self.caller
83 if not self.creator:
84 raise XOSProgrammingError("ServiceComponents's self.creator was not set")
85
86 super(VBBUComponent, self).save(*args, **kwargs)
87 # This call needs to happen so that an instance is created for this
88 # tenant is created in the slice. One instance is created per tenant.
89 model_policy_mcord_servicecomponent(self.pk)
90
91 def save_instance(self, instance):
92 with transaction.atomic():
93 super(VBBUComponent, self).save_instance(instance)
94 if instance.isolation in ["vm"]:
95 for ntype in vbbu_net_types:
96 lan_network = self.get_lan_network(instance, ntype)
97 port = self.find_or_make_port(instance,lan_network)
98 if (ntype == "s1u"):
99 port.set_parameter("s_tag", self.s1u_tag)
100 port.set_parameter("neutron_port_name", "stag-%s" % self.s1u_tag)
101 port.save()
102 elif (ntype == "s1mme"):
103 port.set_parameter("s_tag", self.s1mme_tag)
104 port.set_parameter("neutron_port_name", "stag-%s" % self.s1mme_tag)
105 port.save()
106 elif (ntype == "rru"):
107 port.set_parameter("s_tag", self.rru_tag)
108 port.set_parameter("neutron_port_name", "stag-%s" % self.rru_tag)
109 port.save()
110
111 def delete(self, *args, **kwargs):
112 # Delete the instance that was created for this tenant
113 self.cleanup_container()
114 super(VBBUComponent, self).delete(*args, **kwargs)
115
116 def find_or_make_port(self, instance, network, **kwargs):
117 port = Port.objects.filter(instance=instance, network=network)
118 if port:
119 port = port[0]
120 print "port already exist", port[0]
121 else:
122 port = Port(instance=instance, network=network, **kwargs)
123 print "NETWORK", network, "MAKE_PORT", port
124 port.save()
125 return port
126
127 def get_lan_network(self, instance, ntype):
128 slice = self.provider_service.slices.all()[0]
129 lan_networks = [x for x in slice.networks.all() if ntype in x.name]
130 if not lan_networks:
131 raise XOSProgrammingError("No lan_network")
132 return lan_networks[0]
133
134 def manage_container(self):
135 from core.models import Instance, Flavor
136
137 if self.deleted:
138 return
139
140 # For container or container_vm isolation, use what TenantWithCotnainer
141 # provides us
142 slice = self.get_slice()
143 if slice.default_isolation in ["container_vm", "container"]:
144 super(VBBUComponent,self).manage_container()
145 return
146
147 if not self.s1u_tag:
148 raise XOSConfigurationError("S1U_TAG is missed")
149
150 if not self.s1mme_tag:
151 raise XOSConfigurationError("S1U_TAG is missed")
152
153 if not self.rru_tag:
154 raise XOSConfigurationError("S1U_TAG is missed")
155
156 if self.instance:
157 # We're good.
158 return
159
160 instance = self.make_instance()
161 self.instance = instance
162 super(TenantWithContainer, self).save()
163
164 def get_slice(self):
165 if not self.provider_service.slices.count():
166 raise XOSConfigurationError("The service has no slices")
167 slice = self.provider_service.slices.all()[0]
168 return slice
169
170 def make_instance(self):
171 slice = self.provider_service.slices.all()[0]
172 flavors = Flavor.objects.filter(name=slice.default_flavor)
173# flavors = Flavor.objects.filter(name="m1.xlarge")
174 if not flavors:
175 raise XOSConfigurationError("No default flavor")
176 default_flavor = slice.default_flavor
177 slice = self.provider_service.slices.all()[0]
178 if slice.default_isolation == "container_vm":
179 (node, parent) = ContainerVmScheduler(slice).pick()
180 else:
181 (node, parent) = LeastLoadedNodeScheduler(slice).pick()
182 instance = Instance(slice = slice,
183 node = node,
184 image = self.image,
185 creator = self.creator,
186 deployment = node.site_deployment.deployment,
187 flavor = flavors[0],
188 isolation = slice.default_isolation,
189 parent = parent)
190 self.save_instance(instance)
191 return instance
192
193 def ip_to_mac(self, ip):
194 (a, b, c, d) = ip.split('.')
195 return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
196
197 # Getter for the message that will appear on the webpage
198 # By default it is "Hello World!"
199 @property
200 def display_message(self):
201 return self.get_attribute(
202 "display_message",
203 self.default_attributes['display_message'])
204
205 @display_message.setter
206 def display_message(self, value):
207 self.set_attribute("display_message", value)
208
209 @property
210 def s1u_tag(self):
211 return self.get_attribute(
212 "s1u_tag",
213 self.default_attributes['s1u_tag'])
214
215 @s1u_tag.setter
216 def s1u_tag(self, value):
217 self.set_attribute("s1u_tag", value)
218
219 @property
220 def s1mme_tag(self):
221 return self.get_attribute(
222 "s1mme_tag",
223 self.default_attributes['s1mme_tag'])
224
225 @s1mme_tag.setter
226 def s1mme_tag(self, value):
227 self.set_attribute("s1mme_tag", value)
228
229 @property
230 def rru_tag(self):
231 return self.get_attribute(
232 "rru_tag",
233 self.default_attributes['rru_tag'])
234
235 @rru_tag.setter
236 def rru_tag(self, value):
237 self.set_attribute("rru_tag", value)
238
239
240 @property
241 def addresses(self):
242 if (not self.id) or (not self.instance):
243 return {}
244
245 addresses = {}
246 for ns in self.instance.ports.all():
247 if "s1u" in ns.network.name.lower():
248 addresses["s1u"] = (ns.ip, ns.mac)
249 elif "s1mme" in ns.network.name.lower():
250 addresses["s1mme"] = (ns.ip, ns.mac)
251 elif "rru" in ns.network.name.lower():
252 addresses["rru"] = (ns.ip, ns.mac)
253 return addresses
254
255
256 @property
257 def s1u_ip(self):
258 return self.addresses.get("s1u", (None, None))[0]
259 @property
260 def s1u_mac(self):
261 return self.addresses.get("s1u", (None, None))[1]
262 @property
263 def s1mme_ip(self):
264 return self.addresses.get("s1mme", (None, None))[0]
265 @property
266 def s1mme_mac(self):
267 return self.addresses.get("s1mme", (None, None))[1]
268 @property
269 def rru_ip(self):
270 return self.addresses.get("rru", (None, None))[0]
271 @property
272 def rru_mac(self):
273 return self.addresses.get("rru", (None, None))[1]
274
275
Pingping Lind28ab982016-08-29 18:42:52 +0000276def model_policy_mcord_servicecomponent(pk):
277 # This section of code is atomic to prevent race conditions
278 with transaction.atomic():
279 # We find all of the tenants that are waiting to update
280 component = VBBUComponent.objects.select_for_update().filter(pk=pk)
281 if not component:
282 return
283 # Since this code is atomic it is safe to always use the first tenant
284 component = component[0]
285 component.manage_container()