Matteo Scandolo | a86e0a1 | 2017-08-08 13:05:27 -0700 | [diff] [blame] | 1 | |
| 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 | |
| 16 | |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 17 | import os |
| 18 | import socket |
| 19 | import sys |
| 20 | import base64 |
| 21 | import time |
Scott Baker | 5809ed4 | 2017-03-07 10:45:00 -0800 | [diff] [blame] | 22 | from synchronizers.new_base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible |
| 23 | from synchronizers.new_base.modelaccessor import * |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 24 | from xos.logger import Logger, logging |
| 25 | |
| 26 | # hpclibrary will be in steps/.. |
| 27 | parentdir = os.path.join(os.path.dirname(__file__),"..") |
| 28 | sys.path.insert(0,parentdir) |
| 29 | |
| 30 | logger = Logger(level=logging.INFO) |
| 31 | |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 32 | class SyncVTRTenant(SyncInstanceUsingAnsible): |
| 33 | provides=[VTRTenant] |
| 34 | observes=VTRTenant |
| 35 | requested_interval=0 |
| 36 | template_name = "sync_vtrtenant.yaml" |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 37 | |
| 38 | def __init__(self, *args, **kwargs): |
| 39 | super(SyncVTRTenant, self).__init__(*args, **kwargs) |
| 40 | |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 41 | def get_vtr_service(self, o): |
Scott Baker | c7958a9 | 2017-07-18 11:07:00 -0700 | [diff] [blame] | 42 | if not o.owner: |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 43 | return None |
| 44 | |
Scott Baker | c7958a9 | 2017-07-18 11:07:00 -0700 | [diff] [blame] | 45 | # cast from Service to VTRService |
| 46 | vtrs = VTRService.objects.filter(id=o.owner.id) |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 47 | if not vtrs: |
| 48 | return None |
| 49 | |
| 50 | return vtrs[0] |
| 51 | |
Scott Baker | 5db44a9 | 2017-03-06 17:27:52 -0800 | [diff] [blame] | 52 | def get_target(self, o): |
| 53 | target = o.target |
| 54 | if target: |
Scott Baker | 3bbf1e9 | 2017-03-07 12:06:06 -0800 | [diff] [blame] | 55 | model_name = getattr(target, "model_name", target.__class__.__name__) |
Scott Baker | c7958a9 | 2017-07-18 11:07:00 -0700 | [diff] [blame] | 56 | if model_name in ["ServiceInstance", "CordSubscriberRoot"]: |
| 57 | # cast from ServiceInstance to CordSubscriberRoot |
| 58 | csrs = CordSubscriberRoot.objects.filter(id=target.id) |
| 59 | if csrs: |
| 60 | return csrs[0] |
Scott Baker | 5db44a9 | 2017-03-06 17:27:52 -0800 | [diff] [blame] | 61 | return None |
| 62 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 63 | def gather_information(self, service_instance): |
| 64 | """ gather_information: inspect a service chain for information that will be useful to the VTN service, and |
| 65 | try to do it in a service-agnostic way. We know what we're looking for (instances, ip addresses, etc) but |
| 66 | not necessarily where we will find it. |
| 67 | """ |
| 68 | |
| 69 | if not service_instance: |
| 70 | return {} |
| 71 | |
| 72 | # extract useful information from the service_instance |
| 73 | info = {} |
| 74 | for link in service_instance.subscribed_links.all(): |
| 75 | provider_si = link.provider_service_instance.leaf_model |
| 76 | for k in ["instance", "wan_vm_ip", "wan_container_ip", "s_tag", "c_tag", "container_name"]: |
| 77 | if hasattr(provider_si, k): |
| 78 | info[k] = getattr(provider_si, k) |
| 79 | |
| 80 | # now, recurse to check the children |
| 81 | for link in service_instance.subscribed_links.all(): |
| 82 | child_info = self.gather_information(link.provider_service_instance) |
| 83 | |
| 84 | # prefer values we got from a parent to values we got from a child |
| 85 | for (k,v) in child_info.items(): |
| 86 | if not k in info: |
| 87 | info[k] = v |
| 88 | |
| 89 | return info |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 90 | |
| 91 | def get_instance(self, o): |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 92 | """ get_instance: Called by the SyncInstanceUsingAnslbe sync step. """ |
| 93 | return self.gather_information(self.get_target(o)).get("instance") |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 94 | |
| 95 | def get_key_name(self, instance): |
Scott Baker | 5809ed4 | 2017-03-07 10:45:00 -0800 | [diff] [blame] | 96 | if instance.slice and instance.slice.service and instance.slice.service.private_key_fn: |
| 97 | # Assume the service has shared its key with VTR. |
| 98 | # Look for the instance's service key name in VTR's key directory. |
| 99 | service_keyfn = instance.slice.service.private_key_fn |
| 100 | return os.path.join("/opt/xos/services/vtr/keys", os.path.basename(service_keyfn)) |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 101 | else: |
| 102 | raise Exception("VTR doesn't know how to get the private key for this instance") |
| 103 | |
| 104 | def get_extra_attributes(self, o): |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 105 | target = self.get_target(o) |
| 106 | target_info = self.gather_information(target) |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 107 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 108 | instance = target_info.get("instance") |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 109 | if not instance: |
| 110 | raise Exception("No instance") |
| 111 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 112 | # For container scope, we need to figure out the container name. There are three ways we can do this: |
| 113 | # 1) The service_instance can provide a `container_name` attribute |
| 114 | # 2) The service_instance can provide `container_prefix`, `s_tag`, and `c_tag` attributes. |
| 115 | # 3) The service_instance can provide `s_tag` and `c_tag` and we'll assume a default prefix of `vsg` |
| 116 | container_name = target_info.get("container_name") |
| 117 | if not container_name: |
| 118 | if (not target_info.get("s_tag")) or (not target_info.get("c_tag")): |
| 119 | raise Exception("No s_tag or no c_tag") |
Scott Baker | 5db44a9 | 2017-03-06 17:27:52 -0800 | [diff] [blame] | 120 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 121 | container_name = "%s-%s-%s" % (target_info.get("container_prefix", "vsg"), target_info["s_tag"], target_info["c_tag"]) |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 122 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 123 | fields = {"isolation": instance.isolation, |
| 124 | "container_name": container_name, |
| 125 | "result_fn": "%s-vtrserviceinstance-%s" % (o.test, str(o.id)), |
| 126 | "resultcode_fn": "code-%s-vtrserviceinstance-%s" % (o.test, str(o.id)) } |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 127 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 128 | # copy in values that we learned from inspecting the service chain |
| 129 | for k in ["s_tag", "c_tag", "wan_vm_ip", "wan_container_ip"]: |
| 130 | if target_info.get(k): |
| 131 | fields[k] = target_info[k] |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 132 | |
Scott Baker | 80cfb40 | 2017-09-25 15:21:48 -0700 | [diff] [blame^] | 133 | for attribute_name in ["scope", "test", "argument"]: |
| 134 | fields[attribute_name] = getattr(o, attribute_name) |
Scott Baker | 171d35e | 2016-06-20 17:36:29 -0700 | [diff] [blame] | 135 | |
| 136 | return fields |
| 137 | |
| 138 | def sync_fields(self, o, fields): |
| 139 | # the super causes the playbook to be run |
| 140 | |
| 141 | super(SyncVTRTenant, self).sync_fields(o, fields) |
| 142 | |
| 143 | def run_playbook(self, o, fields): |
| 144 | o.result = "" |
| 145 | |
| 146 | result_fn = os.path.join("/opt/xos/synchronizers/vtr/result", fields["result_fn"]) |
| 147 | if os.path.exists(result_fn): |
| 148 | os.remove(result_fn) |
| 149 | |
| 150 | resultcode_fn = os.path.join("/opt/xos/synchronizers/vtr/result", fields["resultcode_fn"]) |
| 151 | if os.path.exists(resultcode_fn): |
| 152 | os.remove(resultcode_fn) |
| 153 | |
| 154 | super(SyncVTRTenant, self).run_playbook(o, fields) |
| 155 | |
| 156 | if os.path.exists(result_fn): |
| 157 | o.result = open(result_fn).read() |
| 158 | |
| 159 | if os.path.exists(resultcode_fn): |
| 160 | o.result_code = open(resultcode_fn).read() |
| 161 | |
| 162 | |
| 163 | def delete_record(self, m): |
| 164 | pass |