blob: 102e3e3ddffb314cacd6ed96c053e762c69f79e3 [file] [log] [blame]
Pingping Linf3e24a92016-09-19 21:35:16 +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 VPGWCService(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
37 app_label = "vpgwc"
38 verbose_name = "vPGWC 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 VPGWCComponent(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 = "VPGWC Service Component"
50
51 # The kind of the service is used on forms to differentiate this service
52 # from the other services.
53 KIND = VPGWC_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 = ("s5s8_pgw_ip", "s5s8_pgw_mac")
59
60 # default_attributes is used cleanly indicate what the default values for
61 # the fields are.
62 default_attributes = {"display_message": "New vPGWC Component", "s5s8_pgw_tag": "300"}
63 def __init__(self, *args, **kwargs):
64 mcord_services = VPGWCService.get_service_objects().all()
65 # When the tenant is created the default service in the form is set
66 # to be the first created HelloWorldServiceComplete
67 if mcord_services:
68 self._meta.get_field(
69 "provider_service").default = mcord_services[0].id
70 super(VPGWCComponent, self).__init__(*args, **kwargs)
71
72 def can_update(self, user):
73 #Allow creation of this model instances for non-admin users also
74 return True
75
76 def save(self, *args, **kwargs):
77 if not self.creator:
78 if not getattr(self, "caller", None):
79 # caller must be set when creating a monitoring channel since it creates a slice
80 raise XOSProgrammingError("ServiceComponents's self.caller was not set")
81 self.creator = self.caller
82 if not self.creator:
83 raise XOSProgrammingError("ServiceComponents's self.creator was not set")
84
85 super(VPGWCComponent, self).save(*args, **kwargs)
86 # This call needs to happen so that an instance is created for this
87 # tenant is created in the slice. One instance is created per tenant.
88 model_policy_mcord_servicecomponent(self.pk)
89
90 def save_instance(self, instance):
91 with transaction.atomic():
92 super(VPGWCComponent, self).save_instance(instance)
93 if instance.isolation in ["vm"]:
94 for ntype in vpgwc_net_types:
95 lan_network = self.get_lan_network(instance, ntype)
96 port = self.find_or_make_port(instance,lan_network)
97 if (ntype == "s5s8"):
98 port.set_parameter("s_tag", self.s5s8_pgw_tag)
99 port.set_parameter("neutron_port_name", "stag-%s" % self.s5s8_pgw_tag)
100 port.save()
101 else:
102 return True
103
104 def delete(self, *args, **kwargs):
105 # Delete the instance that was created for this tenant
106 self.cleanup_container()
107 super(VPGWCComponent, self).delete(*args, **kwargs)
108
109 def find_or_make_port(self, instance, network, **kwargs):
110 port = Port.objects.filter(instance=instance, network=network)
111 if port:
112 port = port[0]
113 print "port already exist", port[0]
114 else:
115 port = Port(instance=instance, network=network, **kwargs)
116 print "NETWORK", network, "MAKE_PORT", port
117 port.save()
118 return port
119
120 def get_lan_network(self, instance, ntype):
121 slice = self.provider_service.slices.all()[0]
122 lan_networks = [x for x in slice.networks.all() if ntype in x.name]
123 if not lan_networks:
124 raise XOSProgrammingError("No lan_network")
125 return lan_networks[0]
126
127 def manage_container(self):
128 from core.models import Instance, Flavor
129
130 if self.deleted:
131 return
132
133 # For container or container_vm isolation, use what TenantWithCotnainer
134 # provides us
135 slice = self.get_slice()
136 if slice.default_isolation in ["container_vm", "container"]:
137 super(VPGWCComponent,self).manage_container()
138 return
139
140 if not self.s5s8_pgw_tag:
141 raise XOSConfigurationError("S5S8_PGW_TAG is missed")
142
143 if self.instance:
144 # We're good.
145 return
146
147 instance = self.make_instance()
148 self.instance = instance
149 super(TenantWithContainer, self).save()
150
151 def get_slice(self):
152 if not self.provider_service.slices.count():
153 raise XOSConfigurationError("The service has no slices")
154 slice = self.provider_service.slices.all()[0]
155 return slice
156
157 def make_instance(self):
158 slice = self.provider_service.slices.all()[0]
159 flavors = Flavor.objects.filter(name=slice.default_flavor)
160# flavors = Flavor.objects.filter(name="m1.xlarge")
161 if not flavors:
162 raise XOSConfigurationError("No default flavor")
163 default_flavor = slice.default_flavor
164 slice = self.provider_service.slices.all()[0]
165 if slice.default_isolation == "container_vm":
166 (node, parent) = ContainerVmScheduler(slice).pick()
167 else:
168 (node, parent) = LeastLoadedNodeScheduler(slice).pick()
169 instance = Instance(slice = slice,
170 node = node,
171 image = self.image,
172 creator = self.creator,
173 deployment = node.site_deployment.deployment,
174 flavor = flavors[0],
175 isolation = slice.default_isolation,
176 parent = parent)
177 self.save_instance(instance)
178 return instance
179
180 def ip_to_mac(self, ip):
181 (a, b, c, d) = ip.split('.')
182 return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
183
184 # Getter for the message that will appear on the webpage
185 # By default it is "Hello World!"
186 @property
187 def display_message(self):
188 return self.get_attribute(
189 "display_message",
190 self.default_attributes['display_message'])
191
192 @display_message.setter
193 def display_message(self, value):
194 self.set_attribute("display_message", value)
195
196 @property
197 def s5s8_pgw_tag(self):
198 return self.get_attribute(
199 "s5s8_pgw_tag",
200 self.default_attributes['s5s8_pgw_tag'])
201
202 @s5s8_pgw_tag.setter
203 def s5s8_pgw_tag(self, value):
204 self.set_attribute("s5s8_pgw_tag", value)
205
206
207 @property
208 def addresses(self):
209 if (not self.id) or (not self.instance):
210 return {}
211
212 addresses = {}
213 for ns in self.instance.ports.all():
214 if "s5s8_pgw" in ns.network.name.lower():
215 addresses["s5s8_pgw"] = (ns.ip, ns.mac)
216 return addresses
217
218
219 @property
220 def s5s8_pgw_ip(self):
221 return self.addresses.get("s5s8_pgw", (None, None))[0]
222 @property
223 def s5s8_pgw_mac(self):
224 return self.addresses.get("s5s8_pgw", (None, None))[1]
225
226
227
228def model_policy_mcord_servicecomponent(pk):
229 # This section of code is atomic to prevent race conditions
230 with transaction.atomic():
231 # We find all of the tenants that are waiting to update
232 component = VPGWCComponent.objects.select_for_update().filter(pk=pk)
233 if not component:
234 return
235 # Since this code is atomic it is safe to always use the first tenant
236 component = component[0]
237 component.manage_container()