Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 1 | # Copyright 2017-present Open Networking Foundation |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
| 15 | from synchronizers.new_base.modelaccessor import * |
Sapan Bhatia | 503ad90 | 2017-11-13 13:06:17 -0500 | [diff] [blame] | 16 | from synchronizers.new_base.model_policies.model_policy_tenantwithcontainer import Policy |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 17 | from synchronizers.new_base.exceptions import * |
| 18 | |
| 19 | from xosconfig import Config |
| 20 | from multistructlog import create_logger |
| 21 | |
| 22 | log = create_logger(Config().get('logging')) |
| 23 | blueprints = Config().get('blueprints') |
| 24 | |
Sapan Bhatia | 6eeb694 | 2017-11-27 00:27:56 -0500 | [diff] [blame] | 25 | |
Sapan Bhatia | 503ad90 | 2017-11-13 13:06:17 -0500 | [diff] [blame] | 26 | class VEPCServiceInstancePolicy(Policy): |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 27 | model_name = "VEPCServiceInstance" |
| 28 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 29 | def get_service_object(self, name): |
| 30 | """ return: First Service object """ |
| 31 | if any(map(lambda x: x in name, ["ServiceInstance", "Tenant"])): |
| 32 | name = name.replace("ServiceInstance", "Service") |
| 33 | name = name.replace("Tenant", "Service") |
Sapan Bhatia | 491a080 | 2017-11-22 19:37:28 -0500 | [diff] [blame] | 34 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 35 | service_obj = getattr(Slice().stub, name).objects.first() |
Sapan Bhatia | 503ad90 | 2017-11-13 13:06:17 -0500 | [diff] [blame] | 36 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 37 | if not service_obj: |
| 38 | raise Exception("No %s object existed." % name) |
Sapan Bhatia | 6eeb694 | 2017-11-27 00:27:56 -0500 | [diff] [blame] | 39 | |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 40 | return service_obj |
| 41 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 42 | def get_tenant_class(self, name): |
| 43 | """ |
| 44 | return: Tenant class |
| 45 | We need to claim new Tenant instance(object) by this class |
| 46 | """ |
| 47 | if not name.endswith("Service"): |
| 48 | raise Exception("Tenant object needs to find with Service name.") |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 49 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 50 | if hasattr(Slice().stub, name + "Instance"): |
| 51 | tenant_class = getattr(Slice().stub, name + "Instance") |
| 52 | elif hasattr(Slice().stub, name.replace("Service", "Tenant")): |
| 53 | tenant_class = getattr(Slice().stub, name.replace("Service", "Tenant")) |
| 54 | else: |
| 55 | raise Exception("No %s class existed." % name) |
| 56 | |
| 57 | return tenant_class |
| 58 | |
| 59 | def get_vendor_object(self, name): |
| 60 | postfixs = ["Service", "ServiceInstance", "Tenant"] |
| 61 | if not any(map(lambda x: name.endswith(x), postfixs)): |
| 62 | raise Exception("Vendor object need to find with Service or Tenant name.") |
| 63 | |
| 64 | for postfix in postfixs: |
| 65 | name = name.replace(postfix, "Vendor") |
| 66 | |
| 67 | vendor_obj = getattr(Slice().stub, name).objects.first() |
| 68 | |
| 69 | if not vendor_obj: |
| 70 | raise Exception("No %s object existed." % name) |
| 71 | |
| 72 | return vendor_obj |
| 73 | |
| 74 | def create_service_instance(self, service_obj, node_label=None): |
| 75 | tenant_class = self.get_tenant_class(service_obj.leaf_model_name) |
| 76 | vendor_obj = self.get_vendor_object(service_obj.leaf_model_name) |
| 77 | |
| 78 | vendor_name = "%s_vendor" % service_obj.name.lower() |
| 79 | name = "epc-%s-%d" % (tenant_class.__name__.lower(), self.obj.id) |
| 80 | |
| 81 | instance = tenant_class.objects.filter(owner=service_obj.id, name=name).first() |
| 82 | |
| 83 | if instance: |
| 84 | return instance |
| 85 | |
| 86 | instance = tenant_class(owner=service_obj, name=name) |
| 87 | instance.master_serviceinstance = self.obj |
| 88 | instance.__setattr__(vendor_name, vendor_obj) |
Sapan Bhatia | 11d0c9a | 2017-12-10 21:16:34 -0500 | [diff] [blame] | 89 | |
| 90 | if node_label: |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 91 | instance.node_label = "%s-%d" % (node_label, self.obj.id) |
Sapan Bhatia | 11d0c9a | 2017-12-10 21:16:34 -0500 | [diff] [blame] | 92 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 93 | # Assign custom parameter to child tenant |
| 94 | if name in ["vspgwc", "vspgwu"]: |
| 95 | instance.enodeb_ip_addr = self.obj.enodeb_ip_addr_s1u |
| 96 | instance.enodeb_mac_addr = self.obj.enodeb_mac_addr_s1u |
| 97 | instance.appserver_ip_addr = self.obj.appserver_ip_addr |
| 98 | instance.appserver_mac_addr = self.obj.appserver_mac_addr |
| 99 | elif name in ["vmme"]: |
| 100 | instance.enodeb_ip_addr = self.obj.enodeb_ip_addr_s1mme |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 101 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 102 | instance.no_sync = True |
| 103 | instance.no_policy = True |
| 104 | instance.invalidate_cache(vendor_name) |
Sapan Bhatia | 503ad90 | 2017-11-13 13:06:17 -0500 | [diff] [blame] | 105 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 106 | instance.save() |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 107 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 108 | log.info("Instance %s was created." % instance) |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 109 | |
Sapan Bhatia | 491a080 | 2017-11-22 19:37:28 -0500 | [diff] [blame] | 110 | return instance |
| 111 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 112 | def create_network(self, network): |
| 113 | name = network.get("name", "") |
| 114 | owner = network.get("owner", "") |
Andy Bavier | 52b5e0f | 2017-11-27 15:58:21 -0700 | [diff] [blame] | 115 | site_name = self.obj.site.login_base |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 116 | template_name = network.get("template", "public") |
| 117 | subnet = network.get("subnet", "") |
| 118 | permit_all_slices = network.get("permit_all_slices", False) |
Sapan Bhatia | 491a080 | 2017-11-22 19:37:28 -0500 | [diff] [blame] | 119 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 120 | # Get Network, If Network subnet mismatch, then update |
| 121 | # If Network existed, then early return. |
| 122 | network_obj = Network.objects.filter(name=name).first() |
| 123 | if network_obj: |
| 124 | if network_obj.subnet != subnet: |
| 125 | network_obj.subnet = subnet |
| 126 | network_obj.save() |
| 127 | return network_obj |
Andy Bavier | 8721f5e | 2018-01-02 14:36:23 -0700 | [diff] [blame] | 128 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 129 | # Get Network Template by assigned name. |
| 130 | template = NetworkTemplate.objects.filter(name=template_name).first() |
| 131 | if not template: |
| 132 | raise Exception("Template %s for network %s is not exist." % (template_name, name)) |
Andy Bavier | 8721f5e | 2018-01-02 14:36:23 -0700 | [diff] [blame] | 133 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 134 | # Get Network owner slice by assigned name. |
| 135 | slice_name = "%s_%s" % (site_name, owner) |
| 136 | owner_slice = Slice.objects.filter(name=slice_name).first() |
| 137 | if not owner_slice: |
| 138 | raise Exception("Owner Slice %s for network %s is not exist." % (owner, name)) |
Sapan Bhatia | 6eeb694 | 2017-11-27 00:27:56 -0500 | [diff] [blame] | 139 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 140 | # Create Network Instance and save. |
| 141 | network = Network(name=name, subnet=subnet, template=template, |
| 142 | permit_all_slices=permit_all_slices, owner=owner_slice) |
| 143 | network.save() |
Sapan Bhatia | 491a080 | 2017-11-22 19:37:28 -0500 | [diff] [blame] | 144 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 145 | log.info("Network %s was created." % network) |
Sapan Bhatia | 491a080 | 2017-11-22 19:37:28 -0500 | [diff] [blame] | 146 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 147 | return network |
Sapan Bhatia | 491a080 | 2017-11-22 19:37:28 -0500 | [diff] [blame] | 148 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 149 | def create_service_dependency(self, source, target): |
| 150 | """ |
| 151 | Create Service Dependency object for Connectivity between service |
| 152 | source: source service object |
| 153 | target: target service object |
| 154 | """ |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 155 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 156 | # Use Subscriber and Provider's ID to get Dependency |
| 157 | dependency = ServiceDependency.objects.filter( |
| 158 | subscriber_service_id=source.id, provider_service_id=target.id |
| 159 | ).first() |
Sapan Bhatia | 8af7b88 | 2017-12-08 15:46:07 -0500 | [diff] [blame] | 160 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 161 | if not dependency: |
| 162 | # If no dependency existed, then create dependency |
| 163 | dependency = ServiceDependency( |
| 164 | subscriber_service=source, provider_service=target |
| 165 | ) |
| 166 | dependency.save() |
Sapan Bhatia | 8af7b88 | 2017-12-08 15:46:07 -0500 | [diff] [blame] | 167 | |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 168 | log.info("Service dependency %s was created, %s->%s" % (dependency, source, target)) |
| 169 | |
| 170 | # Get subscriber and provider's Service Instance |
| 171 | source_tenant_class = self.get_tenant_class(source.leaf_model_name) |
| 172 | target_tenant_class = self.get_tenant_class(target.leaf_model_name) |
| 173 | source_tenants = source_tenant_class.objects.all() |
| 174 | target_tenants = target_tenant_class.objects.all() |
| 175 | |
| 176 | # Use cross product to create ServiceInstance Link |
| 177 | for source_tenant in source_tenants: |
| 178 | for target_tenant in target_tenants: |
| 179 | link = ServiceInstanceLink.objects.filter( |
| 180 | subscriber_service_instance_id=source_tenant.id, |
| 181 | provider_service_instance_id=target_tenant.id |
| 182 | ) |
| 183 | |
| 184 | if not link: |
| 185 | link = ServiceInstanceLink( |
| 186 | subscriber_service_instance=source_tenant, |
| 187 | provider_service_instance=target_tenant |
| 188 | ) |
| 189 | |
| 190 | link.save() |
| 191 | |
| 192 | log.info("Service instance link %s was created" % link) |
| 193 | |
| 194 | return dependency |
| 195 | |
| 196 | def assign_network_to_service(self, service, network): |
| 197 | service_slice = service.slices.first() |
| 198 | network_slice = NetworkSlice.objects.filter( |
| 199 | network=network.id, slice=service_slice.id |
| 200 | ) |
| 201 | |
| 202 | if not network_slice: |
| 203 | network_slice = NetworkSlice( |
| 204 | network=network, slice=service_slice |
| 205 | ) |
| 206 | network_slice.save() |
| 207 | |
| 208 | return network_slice |
| 209 | |
| 210 | def create_services_from_blueprint(self, blueprint): |
| 211 | dependencies = list() |
| 212 | instances = list() |
| 213 | |
| 214 | for network in blueprint["networks"]: |
| 215 | network_instance = self.create_network(network) |
| 216 | |
| 217 | for node in blueprint["graph"]: |
| 218 | # Get Service's Name, Network, Link attribute from blueprint node |
| 219 | # If value is not set, return empty data struct instead. |
| 220 | tenant_str = node.get("name", "") |
| 221 | networks = node.get("networks", list()) |
| 222 | links = node.get("links", list()) |
| 223 | node_label = node.get("node_label", None) |
| 224 | |
| 225 | # Get Service Class by Defined Service Instance Name |
| 226 | # service_obj: Service Object in XOS core |
| 227 | # tenant_obj: Tenant Object in XOS core |
| 228 | service_obj = self.get_service_object(tenant_str) |
| 229 | |
| 230 | for network in networks: |
| 231 | network_obj = Network.objects.filter(name=network).first() |
| 232 | self.assign_network_to_service(service_obj, network_obj) |
| 233 | |
| 234 | instance = self.create_service_instance(service_obj, node_label=node_label) |
| 235 | instances.append(instance) |
| 236 | |
| 237 | # Collect Service Dependencies relationship from links |
| 238 | for provider in links: |
| 239 | provider_str = provider.get("name", "") |
| 240 | provider_service_obj = self.get_service_object(provider_str) |
| 241 | dependencies.append((service_obj, provider_service_obj)) |
| 242 | |
| 243 | log.info("Dependency Pair: %s" % dependencies) |
| 244 | |
| 245 | # Create Service Dependency between subscriber and provider |
| 246 | for subscriber, provider in dependencies: |
| 247 | self.create_service_dependency(subscriber, provider) |
| 248 | |
| 249 | for instance in instances: |
| 250 | instance.no_policy = False |
| 251 | instance.no_sync = False |
| 252 | instance.save() |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 253 | |
Sapan Bhatia | 503ad90 | 2017-11-13 13:06:17 -0500 | [diff] [blame] | 254 | def handle_create(self, service_instance): |
| 255 | self.handle_update(service_instance) |
| 256 | |
Sapan Bhatia | 2810e03 | 2017-11-03 00:31:00 -0400 | [diff] [blame] | 257 | def handle_update(self, service_instance): |
Wei-Yu Chen | 3d6939a | 2018-06-22 16:44:08 +0800 | [diff] [blame^] | 258 | # Register EPC-Service's service_instance as self.obj |
| 259 | self.obj = service_instance |
| 260 | |
| 261 | blueprint_name = service_instance.blueprint |
| 262 | try: |
| 263 | blueprint = filter(lambda x: x["name"] == blueprint_name, blueprints)[0] |
| 264 | except StopIteration: |
| 265 | log.error("Chosen blueprint: %s not defined" % blueprint_name) |
| 266 | |
| 267 | self.create_services_from_blueprint(blueprint) |