blob: dd6ace885f6ee76bc7b556e1619561760953ccac [file] [log] [blame]
Woojoong Kim033b2ce2017-10-10 10:09:06 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from synchronizers.new_base.modelaccessor import *
17from synchronizers.new_base.model_policies.model_policy_tenantwithcontainer import TenantWithContainerPolicy, LeastLoadedNodeScheduler
18from synchronizers.new_base.exceptions import *
19
20class VHSSTenantPolicy(TenantWithContainerPolicy):
21 model_name = "VHSSTenant"
Andy Bavier144b09a2018-02-12 16:15:22 -070022 constrain_by_service_instance = True
Woojoong Kim033b2ce2017-10-10 10:09:06 -070023
24 # Already defined in Super class
25 #def handle_create(self, service_instance):
26 # return self.handle_update(service_instance)
27
28 def handle_update(self, service_instance):
29 if (service_instance. link_deleted_count >0) and (not service_instance.provided_links.exists()):
30 self.logger.info("The last provided link has been deleted -- self-destructing.")
31 self.handle_delete(service_instance)
32 if VHSSTenant.objects.filter(id=service_instance.id).exists():
33 service_instance.delete()
34 else:
35 self.logger.info("Tenant %s is already deleted" % service_instance)
36 return
37
38 self.manage_container(service_instance)
39
40 def handle_delete(self, service_instance):
41 if service_instance.instance and (not service_instance.instance.deleted):
42 all_service_instances_this_instance = VHSSTenant.objects.filter(instance_id=service_instance.instance.id)
43 other_service_instances_this_instance = [x for x in all_service_instances_this_instance if x.id != service_instance.id]
44 if (not other_service_instances_this_instance):
45 self.logger.info("VHSSTenant Instance %s is now unused -- deleting" % service_instance.instance)
46 self.delete_instance(service_instance, service_instance.instance)
47 else:
48 self.logger.info("VHSSTenant Instance %s has %d other service instances attached" %
49 (service_instance.instance, len(other_service_instances_this_instance)))
50
51 def get_service(self, service_instance):
52 service_name = service_instance.owner.leaf_model_name
53 service_class = globals()[service_name]
54 return service_class.objects.get(id=service_instance.owner.id)
55
56 def find_instance_for_instance_tag(self, instance_tag):
57 tags = Tag.objects.filter(name="instance_tag", value=instance_tag)
58 if tags:
59 return tags[0].content_object
60 return None
61
62 def find_or_make_instance_for_instance_tag(self, service_instance):
63 instance_tag = self.get_instance_tag(service_instance)
64 instance = self.find_instance_for_instance_tag(instance_tag)
65 if instance:
66 if instance.no_sync:
67 # if no_sync is still set, then perhaps we failed while saving it and need to retry.
68 self.save_instance(service_instance, instance)
69 return instance
70
71 desired_image = self.get_image(service_instance)
72 desired_flavor = self.get_flavor(service_instance)
Andy Bavier144b09a2018-02-12 16:15:22 -070073 node_label = service_instance.node_label
74 constrain_by_service_instance = self.constrain_by_service_instance
Woojoong Kim033b2ce2017-10-10 10:09:06 -070075
76 slice = service_instance.owner.slices.first()
77
Andy Bavier144b09a2018-02-12 16:15:22 -070078 scheduler = LeastLoadedNodeScheduler(slice, label=node_label, constrain_by_service_instance=constrain_by_service_instance)
79 (node, parent) = scheduler.pick()
Woojoong Kim033b2ce2017-10-10 10:09:06 -070080
81 assert (slice is not None)
82 assert (node is not None)
83 assert (desired_image is not None)
84 assert (service_instance.creator is not None)
85 assert (node.site_deployment.deployment is not None)
86 assert (desired_image is not None)
87
88 instance = Instance(slice=slice,
89 node=node,
90 image=desired_image,
91 creator=service_instance.creator,
92 deployment=node.site_deployment.deployment,
93 flavor=desired_flavor,
94 isolation=slice.default_isolation,
95 parent=parent)
96
97 self.save_instance(service_instance, instance)
98
99 return instance
100
101 def manage_container(self, service_instance):
102 if service_instance.deleted:
103 return
104
105 if service_instance.instance:
106 # We're good.
107 return
108
109 instance = self.find_or_make_instance_for_instance_tag(service_instance)
110 service_instance.instance = instance
111 # TODO: possible for partial failure here?
112 service_instance.save()
113
114 def delete_instance(self, service_instance, instance):
115 # delete the `instance_tag` tags
116 tags = Tag.objects.filter(service_id=service_instance.owner.id, content_type=instance.self_content_type_id,
117 object_id=instance.id, name="instance_tag")
118 for tag in tags:
119 tag.delete()
120
121 instance.delete()
122
123 def save_instance(self, service_instance, instance):
124 instance.no_sync = True # prevent instance from being synced until we're done with it
125 super(VHSSTenantPolicy, self).save_instance(instance)
126
127 try:
128 if instance.isolation in ["container", "container_vm"]:
129 raise Exception("Not supported")
130
131 instance_tag = self.get_instance_tag(service_instance)
132 if instance_tag:
133 tags = Tag.objects.filter(name="instance_tag", value=instance_tag)
134 if not tags:
135 tag = Tag(service=service_instance.owner, content_type=instance.self_content_type_id,
136 object_id=instance.id, name="instance_tag", value=str(instance_tag))
137 tag.save()
138
139 instance.no_sync = False # allow the synchronizer to run now
140 super(VHSSTenantPolicy, self).save_instance(instance)
141 except:
142 # need to clean up any failures here
143 raise
144
145 def get_instance_tag(self, service_instance):
146 return '%d' % service_instance.id
147
148 def get_image(self, service_instance):
149 return service_instance.vhss_vendor.image
150
151 def get_flavor(self, service_vendor):
152 return service_vendor.vhss_vendor.flavor