blob: 943b205650b67b11677688cd1f542f7aa0e982f1 [file] [log] [blame]
Sapan Bhatia51a804c2017-05-03 17:24:37 +02001sync_attributes = ("wan_container_ip", "wan_container_mac", "wan_container_netbits",
2 "wan_container_gateway_ip", "wan_container_gateway_mac",
3 "wan_vm_ip", "wan_vm_mac")
4
5
6def __init__(self, *args, **kwargs):
7 super(VEGTenant, self).__init__(*args, **kwargs)
8 self.cached_vrouter=None
9
10@property
11def vrouter(self):
12 vrouter = self.get_newest_subscribed_tenant(VRouterTenant)
13 if not vrouter:
14 return None
15
16 # always return the same object when possible
17 if (self.cached_vrouter) and (self.cached_vrouter.id == vrouter.id):
18 return self.cached_vrouter
19
20 vrouter.caller = self.creator
21 self.cached_vrouter = vrouter
22 return vrouter
23
24@vrouter.setter
25def vrouter(self, value):
26 raise XOSConfigurationError("vEGTenant.vrouter setter is not implemented")
27
28@property
29def volt(self):
30 from services.volt.models import VOLTTenant
31 if not self.subscriber_tenant:
32 return None
33 volts = VOLTTenant.objects.filter(id=self.subscriber_tenant.id)
34 if not volts:
35 return None
36 return volts[0]
37
38@volt.setter
39def volt(self, value):
40 raise XOSConfigurationError("VEGTenant.volt setter is not implemented")
41
42@property
43def ssh_command(self):
44 if self.instance:
45 return self.instance.get_ssh_command()
46 else:
47 return "no-instance"
48
49def get_vrouter_field(self, name, default=None):
50 if self.vrouter:
51 return getattr(self.vrouter, name, default)
52 else:
53 return default
54
55@property
56def wan_container_ip(self):
57 return self.get_vrouter_field("public_ip", None)
58
59@property
60def wan_container_mac(self):
61 return self.get_vrouter_field("public_mac", None)
62
63@property
64def wan_container_netbits(self):
65 return self.get_vrouter_field("netbits", None)
66
67@property
68def wan_container_gateway_ip(self):
69 return self.get_vrouter_field("gateway_ip", None)
70
71@property
72def wan_container_gateway_mac(self):
73 return self.get_vrouter_field("gateway_mac", None)
74
75@property
76def wan_vm_ip(self):
77 tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
78 if tags:
79 tenant = VRouterTenant.objects.get(id=tags[0].value)
80 return tenant.public_ip
81 else:
82 raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
83
84@property
85def wan_vm_mac(self):
86 tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
87 if tags:
88 tenant = VRouterTenant.objects.get(id=tags[0].value)
89 return tenant.public_mac
90 else:
91 raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
92
93@property
94def is_synced(self):
95 return (self.enacted is not None) and (self.enacted >= self.updated)
96
97@is_synced.setter
98def is_synced(self, value):
99 pass
100
101def get_vrouter_service(self):
102 vrouterServices = VRouterService.get_service_objects().all()
103 if not vrouterServices:
104 raise XOSConfigurationError("No VROUTER Services available")
105 return vrouterServices[0]
106
107def manage_vrouter(self):
108 # Each vEG object owns exactly one vRouterTenant object
109
110 if self.deleted:
111 return
112
113 if self.vrouter is None:
114 vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_veg", subscriber_tenant = self)
115 vrouter.caller = self.creator
116 vrouter.save()
117
118def cleanup_vrouter(self):
119 if self.vrouter:
120 # print "XXX cleanup vrouter", self.vrouter
121 self.vrouter.delete()
122
123def cleanup_orphans(self):
124 # ensure vEG only has one vRouter
125 cur_vrouter = self.vrouter
126 for vrouter in list(self.get_subscribed_tenants(VRouterTenant)):
127 if (not cur_vrouter) or (vrouter.id != cur_vrouter.id):
128 # print "XXX clean up orphaned vrouter", vrouter
129 vrouter.delete()
130
131 if self.orig_instance_id and (self.orig_instance_id != self.get_attribute("instance_id")):
132 instances=Instance.objects.filter(id=self.orig_instance_id)
133 if instances:
134 # print "XXX clean up orphaned instance", instances[0]
135 instances[0].delete()
136
137def get_slice(self):
138 if not self.provider_service.slices.count():
139 print self, "dio porco"
140 raise XOSConfigurationError("The service has no slices")
141 slice = self.provider_service.slices.all()[0]
142 return slice
143
144def get_veg_service(self):
145 return VEGService.get_service_objects().get(id=self.provider_service.id)
146
147def find_instance_for_s_tag(self, s_tag):
148 #s_tags = STagBlock.objects.find(s_s_tag)
149 #if s_tags:
150 # return s_tags[0].instance
151
152 tags = Tag.objects.filter(name="s_tag", value=s_tag)
153 if tags:
154 return tags[0].content_object
155
156 return None
157
158def find_or_make_instance_for_s_tag(self, s_tag):
159 instance = self.find_instance_for_s_tag(self.volt.s_tag)
160 if instance:
161 return instance
162
163 flavors = Flavor.objects.filter(name="m1.small")
164 if not flavors:
165 raise XOSConfigurationError("No m1.small flavor")
166
167 slice = self.provider_service.slices.all()[0]
168
169 if slice.default_isolation == "container_vm":
170 (node, parent) = ContainerVmScheduler(slice).pick()
171 else:
172 (node, parent) = LeastLoadedNodeScheduler(slice, label=self.get_veg_service().node_label).pick()
173
174 instance = Instance(slice = slice,
175 node = node,
176 image = self.image,
177 creator = self.creator,
178 deployment = node.site_deployment.deployment,
179 flavor = flavors[0],
180 isolation = slice.default_isolation,
181 parent = parent)
182
183 self.save_instance(instance)
184
185 return instance
186
187def manage_container(self):
188 from core.models import Instance, Flavor
189
190 if self.deleted:
191 return
192
193 # For container or container_vm isolation, use what TenantWithCotnainer
194 # provides us
195 slice = self.get_slice()
196 if slice.default_isolation in ["container_vm", "container"]:
197 super(VEGTenant,self).manage_container()
198 return
199
200 if not self.volt:
201 raise XOSConfigurationError("This vEG container has no volt")
202
203 if self.instance:
204 # We're good.
205 return
206
207 instance = self.find_or_make_instance_for_s_tag(self.volt.s_tag)
208 self.instance = instance
209 super(TenantWithContainer, self).save()
210
211def cleanup_container(self):
212 if self.get_slice().default_isolation in ["container_vm", "container"]:
213 super(VEGTenant,self).cleanup_container()
214
215 # To-do: cleanup unused instances
216 pass
217
218def find_or_make_port(self, instance, network, **kwargs):
219 port = Port.objects.filter(instance=instance, network=network)
220 if port:
221 port = port[0]
222 else:
223 port = Port(instance=instance, network=network, **kwargs)
224 port.save()
225 return port
226
227def get_lan_network(self, instance):
228 slice = self.provider_service.slices.all()[0]
229 # there should only be one network private network, and its template should not be the management template
230 lan_networks = [x for x in slice.networks.all() if x.template.visibility == "private" and (not "management" in x.template.name)]
231 if len(lan_networks) > 1:
232 raise XOSProgrammingError("The vEG slice should only have one non-management private network")
233 if not lan_networks:
234 raise XOSProgrammingError("No lan_network")
235 return lan_networks[0]
236
237def save_instance(self, instance):
238 with transaction.atomic():
239 instance.volumes = "/etc/dnsmasq.d,/etc/ufw"
240 super(VEGTenant, self).save_instance(instance)
241
242 if instance.isolation in ["container", "container_vm"]:
243 lan_network = self.get_lan_network(instance)
244 port = self.find_or_make_port(instance, lan_network, ip="192.168.0.1", port_id="unmanaged")
245 port.set_parameter("c_tag", self.volt.c_tag)
246 port.set_parameter("s_tag", self.volt.s_tag)
247 port.set_parameter("device", "eth1")
248 port.set_parameter("bridge", "br-lan")
249
250 wan_networks = [x for x in instance.slice.networks.all() if "wan" in x.name]
251 if not wan_networks:
252 raise XOSProgrammingError("No wan_network")
253 port = self.find_or_make_port(instance, wan_networks[0])
254 port.set_parameter("next_hop", value="10.0.1.253") # FIX ME
255 port.set_parameter("device", "eth0")
256
257 if instance.isolation in ["vm"]:
258 lan_network = self.get_lan_network(instance)
259 port = self.find_or_make_port(instance, lan_network)
260 port.set_parameter("c_tag", self.volt.c_tag)
261 port.set_parameter("s_tag", self.volt.s_tag)
262 port.set_parameter("neutron_port_name", "stag-%s" % self.volt.s_tag)
263 port.save()
264
265 # tag the instance with the s-tag, so we can easily find the
266 # instance later
267 if self.volt and self.volt.s_tag:
268 tags = Tag.objects.filter(name="s_tag", value=self.volt.s_tag)
269 if not tags:
270 tag = Tag(service=self.provider_service, content_object=instance, name="s_tag", value=self.volt.s_tag)
271 tag.save()
272
273 # VTN-CORD needs a WAN address for the VM, so that the VM can
274 # be configured.
275 tags = Tag.select_by_content_object(instance).filter(name="vm_vrouter_tenant")
276
277 if not tags:
278 vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_veg", subscriber_service=self.provider_service)
279 vrouter.set_attribute("tenant_for_instance_id", instance.id)
280 vrouter.save()
281 tag = Tag(service=self.provider_service, content_object=instance, name="vm_vrouter_tenant",value="%d" % vrouter.id)
282 tag.save()
283
284def save(self, *args, **kwargs):
285 if not self.creator:
286 if not getattr(self, "caller", None):
287 # caller must be set when creating a vEG since it creates a slice
288 raise XOSProgrammingError("VEGTenant's self.caller was not set")
289 self.creator = self.caller
290 if not self.creator:
291 raise XOSProgrammingError("VEGTenant's self.creator was not set")
292
293 super(VEGTenant, self).save(*args, **kwargs)
294 model_policy_veg(self.pk)
295
296def delete(self, *args, **kwargs):
297 self.cleanup_vrouter()
298 self.cleanup_container()
299 super(VEGTenant, self).delete(*args, **kwargs)
300