blob: 65bffefd3664df8c832010add2257e04fcfa5f8f [file] [log] [blame]
Scott Bakerfa8fd292015-09-09 17:31:22 -07001from django.db import models
Tony Mack32010062015-09-13 22:50:39 +00002from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber
Scott Bakerfa8fd292015-09-09 17:31:22 -07003from 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
9import traceback
10from xos.exceptions import *
Scott Bakerddf8a942015-09-10 17:07:21 -070011from core.models import SlicePrivilege, SitePrivilege
12from sets import Set
Srikanth Vavilapalli1848ab32016-02-01 13:51:26 -050013from urlparse import urlparse
Scott Bakerfa8fd292015-09-09 17:31:22 -070014
15CEILOMETER_KIND = "ceilometer"
16
17class CeilometerService(Service):
18 KIND = CEILOMETER_KIND
19
20 class Meta:
21 app_label = "ceilometer"
22 verbose_name = "Ceilometer Service"
23 proxy = True
24
Srikanth Vavilapallia1bf88f2016-02-07 14:18:51 -050025 @property
26 def ceilometer_pub_sub_url(self):
27 return self.get_attribute("ceilometer_pub_sub_url", None)
28
29 @ceilometer_pub_sub_url.setter
30 def ceilometer_pub_sub_url(self, value):
31 self.set_attribute("ceilometer_pub_sub_url", value)
32
Scott Bakerfa8fd292015-09-09 17:31:22 -070033class MonitoringChannel(TenantWithContainer): # aka 'CeilometerTenant'
34 class Meta:
35 proxy = True
36
37 KIND = CEILOMETER_KIND
svavilap231903c2016-02-18 20:48:35 -050038 LOOK_FOR_IMAGES=[ #"trusty-server-multi-nic-docker", # CloudLab
Srikanth Vavilapalli204a5c42016-02-15 01:18:09 -050039 "trusty-server-multi-nic",
40 ]
41
Scott Bakerfa8fd292015-09-09 17:31:22 -070042
svavilapaf911082015-10-13 23:50:03 -040043 sync_attributes = ("private_ip", "private_mac",
44 "ceilometer_ip", "ceilometer_mac",
svavilapb4594032015-11-16 00:27:06 -060045 "nat_ip", "nat_mac", "ceilometer_port",)
svavilapaf911082015-10-13 23:50:03 -040046
Scott Bakerfa8fd292015-09-09 17:31:22 -070047 default_attributes = {}
48 def __init__(self, *args, **kwargs):
49 ceilometer_services = CeilometerService.get_service_objects().all()
50 if ceilometer_services:
51 self._meta.get_field("provider_service").default = ceilometer_services[0].id
52 super(MonitoringChannel, self).__init__(*args, **kwargs)
svavilapb4594032015-11-16 00:27:06 -060053 self.set_attribute("use_same_instance_for_multiple_tenants", True)
Scott Bakerfa8fd292015-09-09 17:31:22 -070054
svavilap14249982015-11-21 13:52:02 -060055 def can_update(self, user):
56 #Allow creation of this model instances for non-admin users also
57 return True
58
Scott Bakerfa8fd292015-09-09 17:31:22 -070059 def save(self, *args, **kwargs):
60 if not self.creator:
61 if not getattr(self, "caller", None):
Srikanth Vavilapallie9247d82015-10-28 23:52:29 -040062 # caller must be set when creating a monitoring channel since it creates a slice
Scott Bakerfa8fd292015-09-09 17:31:22 -070063 raise XOSProgrammingError("MonitoringChannel's self.caller was not set")
64 self.creator = self.caller
65 if not self.creator:
66 raise XOSProgrammingError("MonitoringChannel's self.creator was not set")
67
Srikanth Vavilapallie9247d82015-10-28 23:52:29 -040068 if self.pk is None:
69 #Allow only one monitoring channel per user
70 channel_count = sum ( [1 for channel in MonitoringChannel.objects.filter(kind=CEILOMETER_KIND) if (channel.creator == self.creator)] )
71 if channel_count > 0:
72 raise XOSValidationError("Already %s channels exist for user Can only create max 1 MonitoringChannel instance per user" % str(channel_count))
73
Scott Bakerfa8fd292015-09-09 17:31:22 -070074 super(MonitoringChannel, self).save(*args, **kwargs)
75 model_policy_monitoring_channel(self.pk)
76
77 def delete(self, *args, **kwargs):
Scott Baker588caf92015-09-09 17:57:51 -070078 self.cleanup_container()
Scott Bakerfa8fd292015-09-09 17:31:22 -070079 super(MonitoringChannel, self).delete(*args, **kwargs)
80
Scott Bakerddf8a942015-09-10 17:07:21 -070081 @property
Scott Bakerb37a99a2015-09-10 17:36:58 -070082 def addresses(self):
svavilapb4594032015-11-16 00:27:06 -060083 if (not self.id) or (not self.instance):
Scott Bakerb37a99a2015-09-10 17:36:58 -070084 return {}
85
86 addresses = {}
Tony Mack32010062015-09-13 22:50:39 +000087 for ns in self.instance.ports.all():
Scott Bakerb37a99a2015-09-10 17:36:58 -070088 if "private" in ns.network.name.lower():
89 addresses["private"] = (ns.ip, ns.mac)
90 elif "nat" in ns.network.name.lower():
91 addresses["nat"] = (ns.ip, ns.mac)
Scott Bakera9cf9c42015-09-10 17:46:47 -070092 elif "ceilometer_client_access" in ns.network.labels.lower():
93 addresses["ceilometer"] = (ns.ip, ns.mac)
Scott Bakerb37a99a2015-09-10 17:36:58 -070094 return addresses
95
96 @property
svavilapaf911082015-10-13 23:50:03 -040097 def nat_ip(self):
98 return self.addresses.get("nat", (None, None))[0]
99
100 @property
101 def nat_mac(self):
102 return self.addresses.get("nat", (None, None))[1]
103
104 @property
Scott Bakerb37a99a2015-09-10 17:36:58 -0700105 def private_ip(self):
106 return self.addresses.get("nat", (None, None))[0]
107
108 @property
svavilapaf911082015-10-13 23:50:03 -0400109 def private_mac(self):
110 return self.addresses.get("nat", (None, None))[1]
111
112 @property
Scott Bakera9cf9c42015-09-10 17:46:47 -0700113 def ceilometer_ip(self):
114 return self.addresses.get("ceilometer", (None, None))[0]
115
116 @property
svavilapaf911082015-10-13 23:50:03 -0400117 def ceilometer_mac(self):
118 return self.addresses.get("ceilometer", (None, None))[1]
119
120 @property
Scott Bakerddf8a942015-09-10 17:07:21 -0700121 def site_tenant_list(self):
122 tenant_ids = Set()
123 for sp in SitePrivilege.objects.filter(user=self.creator):
124 site = sp.site
125 for cs in site.controllersite.all():
126 if cs.tenant_id:
127 tenant_ids.add(cs.tenant_id)
128 return tenant_ids
129
130 @property
131 def slice_tenant_list(self):
132 tenant_ids = Set()
133 for sp in SlicePrivilege.objects.filter(user=self.creator):
134 slice = sp.slice
135 for cs in slice.controllerslices.all():
136 if cs.tenant_id:
137 tenant_ids.add(cs.tenant_id)
138 for slice in Slice.objects.filter(creator=self.creator):
139 for cs in slice.controllerslices.all():
140 if cs.tenant_id:
141 tenant_ids.add(cs.tenant_id)
Srikanth Vavilapallib74e2112015-12-01 18:24:29 -0600142 if self.creator.is_admin:
143 #TODO: Ceilometer publishes the SDN meters without associating to any tenant IDs.
144 #For now, ceilometer code is changed to pusblish all such meters with tenant
145 #id as "default_admin_tenant". Here add that default tenant as authroized tenant_id
146 #for all admin users.
147 tenant_ids.add("default_admin_tenant")
Scott Bakerddf8a942015-09-10 17:07:21 -0700148 return tenant_ids
149
150 @property
151 def tenant_list(self):
152 return self.slice_tenant_list | self.site_tenant_list
153
154 @property
155 def tenant_list_str(self):
156 return ", ".join(self.tenant_list)
157
Scott Bakerb37a99a2015-09-10 17:36:58 -0700158 @property
svavilapb4594032015-11-16 00:27:06 -0600159 def ceilometer_port(self):
160 # TODO: Find a better logic to choose unique ceilometer port number for each instance
161 if not self.id:
162 return None
163 return 8888+self.id
164
165 @property
Scott Bakerb37a99a2015-09-10 17:36:58 -0700166 def ceilometer_url(self):
Scott Bakera9cf9c42015-09-10 17:46:47 -0700167 if not self.ceilometer_ip:
Scott Bakerb37a99a2015-09-10 17:36:58 -0700168 return None
svavilapb4594032015-11-16 00:27:06 -0600169 return "http://" + self.private_ip + ":" + str(self.ceilometer_port) + "/"
Scott Bakerddf8a942015-09-10 17:07:21 -0700170
Scott Bakerfa8fd292015-09-09 17:31:22 -0700171def model_policy_monitoring_channel(pk):
172 # TODO: this should be made in to a real model_policy
173 with transaction.atomic():
174 mc = MonitoringChannel.objects.select_for_update().filter(pk=pk)
175 if not mc:
176 return
177 mc = mc[0]
178 mc.manage_container()
179
180
Srikanth Vavilapallice6b63b2016-01-27 18:29:00 -0500181SFLOW_KIND = "sflow"
Srikanth Vavilapalli0ddb11f2016-01-29 14:29:26 -0500182SFLOW_PORT = 6343
183SFLOW_API_PORT = 33333
Srikanth Vavilapallice6b63b2016-01-27 18:29:00 -0500184
185class SFlowService(Service):
186 KIND = SFLOW_KIND
187
188 class Meta:
Srikanth Vavilapalli0ddb11f2016-01-29 14:29:26 -0500189 app_label = "ceilometer"
Srikanth Vavilapallice6b63b2016-01-27 18:29:00 -0500190 verbose_name = "sFlow Collection Service"
191 proxy = True
192
Srikanth Vavilapalli0ddb11f2016-01-29 14:29:26 -0500193 default_attributes = {"sflow_port": SFLOW_PORT, "sflow_api_port": SFLOW_API_PORT}
Srikanth Vavilapallice6b63b2016-01-27 18:29:00 -0500194
195 sync_attributes = ("sflow_port", "sflow_api_port",)
196
197 @property
198 def sflow_port(self):
199 return self.get_attribute("sflow_port", self.default_attributes["sflow_port"])
200
201 @sflow_port.setter
202 def sflow_port(self, value):
203 self.set_attribute("sflow_port", value)
204
205 @property
206 def sflow_api_port(self):
207 return self.get_attribute("sflow_api_port", self.default_attributes["sflow_api_port"])
208
209 @sflow_api_port.setter
210 def sflow_api_port(self, value):
211 self.set_attribute("sflow_api_port", value)
212
213 def get_instance(self):
214 if self.slices.exists():
215 slice = self.slices.all()[0]
216 if slice.instances.exists():
217 return slice.instances.all()[0]
218
219 return None
220
221 @property
222 def sflow_api_url(self):
223 if not self.get_instance():
224 return None
225 return "http://" + self.get_instance().get_ssh_ip() + ":" + str(self.sflow_api_port) + "/"
226
227class SFlowTenant(Tenant):
228 class Meta:
229 proxy = True
230
231 KIND = SFLOW_KIND
232
233 sync_attributes = ("listening_endpoint", )
234
235 default_attributes = {}
236 def __init__(self, *args, **kwargs):
237 sflow_services = SFlowService.get_service_objects().all()
238 if sflow_services:
239 self._meta.get_field("provider_service").default = sflow_services[0].id
240 super(SFlowTenant, self).__init__(*args, **kwargs)
241
242 @property
243 def creator(self):
244 from core.models import User
245 if getattr(self, "cached_creator", None):
246 return self.cached_creator
247 creator_id=self.get_attribute("creator_id")
248 if not creator_id:
249 return None
250 users=User.objects.filter(id=creator_id)
251 if not users:
252 return None
253 user=users[0]
254 self.cached_creator = users[0]
255 return user
256
257 @creator.setter
258 def creator(self, value):
259 if value:
260 value = value.id
261 if (value != self.get_attribute("creator_id", None)):
262 self.cached_creator=None
263 self.set_attribute("creator_id", value)
264
265 @property
266 def listening_endpoint(self):
Srikanth Vavilapalli1848ab32016-02-01 13:51:26 -0500267 return self.get_attribute("listening_endpoint", None)
Srikanth Vavilapallice6b63b2016-01-27 18:29:00 -0500268
269 @listening_endpoint.setter
270 def listening_endpoint(self, value):
271 if urlparse(value).scheme != 'udp':
272 raise XOSProgrammingError("SFlowTenant: Only UDP listening endpoint URLs are accepted...valid syntax is: udp://ip:port")
Srikanth Vavilapalli1848ab32016-02-01 13:51:26 -0500273 self.set_attribute("listening_endpoint", value)
Srikanth Vavilapallice6b63b2016-01-27 18:29:00 -0500274
275 def save(self, *args, **kwargs):
276 if not self.creator:
277 if not getattr(self, "caller", None):
278 # caller must be set when creating a SFlow tenant since it creates a slice
279 raise XOSProgrammingError("SFlowTenant's self.caller was not set")
280 self.creator = self.caller
281 if not self.creator:
282 raise XOSProgrammingError("SFlowTenant's self.creator was not set")
283
284 if not self.listening_endpoint:
285 raise XOSProgrammingError("SFlowTenant's self.listening_endpoint was not set")
286
287 if self.pk is None:
288 #Allow only one sflow channel per user and listening_endpoint
289 channel_count = sum ( [1 for channel in SFlowTenant.objects.filter(kind=SFLOW_KIND) if ((channel.creator == self.creator) and (channel.listening_endpoint == self.listening_endpoint))] )
290 if channel_count > 0:
291 raise XOSValidationError("Already %s sflow channels exist for user Can only create max 1 tenant per user and listening endpoint" % str(channel_count))
292
293 super(SFlowTenant, self).save(*args, **kwargs)
294
295 def delete(self, *args, **kwargs):
296 super(MonitoringChannel, self).delete(*args, **kwargs)
297
298 @property
299 def authorized_resource_list(self):
300 return ['all']
301
302 @property
303 def authorized_resource_list_str(self):
304 return ", ".join(self.authorized_resource_list)
305