blob: 00884cdb46c04a163b050c6a439a13faa24e515a [file] [log] [blame]
Pingping Lind28ab982016-08-29 18:42:52 +00001from django.db import models
2from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, AddressPool, Port
3from core.models.plcorebase import StrippedCharField
4import 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()