blob: f7eec6f77333a2b57546b5d9817fb94129f35145 [file] [log] [blame]
Matteo Scandolo79fe3e12017-08-08 13:05:25 -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
16
Scott Baker46831592016-06-20 17:32:04 -070017import os
18import base64
19from collections import defaultdict
Scott Baker71c20eb2017-03-14 21:35:18 -070020from synchronizers.new_base.syncstep import SyncStep, DeferredException
21from synchronizers.new_base.modelaccessor import *
Scott Baker46831592016-06-20 17:32:04 -070022from xos.logger import observer_logger as logger
Scott Baker46831592016-06-20 17:32:04 -070023import json
24
Scott Baker8fddcac2017-08-24 08:56:04 -070025class SyncAddressManagerServiceInstance(SyncStep):
26 provides=[AddressManagerServiceInstance]
27 observes = AddressManagerServiceInstance
Scott Baker46831592016-06-20 17:32:04 -070028 requested_interval=30
29 playbook='sync_host.yaml'
30
31 def get_fabric_onos_service(self):
Scott Baker8fddcac2017-08-24 08:56:04 -070032 # There will be a ServiceInstanceLink from the FabricService to the Fabric ONOS App
Scott Baker71c20eb2017-03-14 21:35:18 -070033 fs = FabricService.objects.first()
Scott Baker7462a142017-07-19 16:34:29 -070034 for link in fs.subscribed_links.all():
35 if link.provider_service_instance:
36 # cast from ServiceInstance to ONOSApp
Scott Baker8fddcac2017-08-24 08:56:04 -070037 service_instance = link.provider_service_instance.leaf_model
38 # cast from Service to ONOSService
39 return service_instance.owner.leaf_model
40
Scott Baker7462a142017-07-19 16:34:29 -070041 return None
Scott Baker46831592016-06-20 17:32:04 -070042
43 def get_node_tag(self, node, tagname):
Scott Baker8daf78d2017-03-15 11:39:44 -070044 tags = Tag.objects.filter(content_type=model_accessor.get_content_type_id(node),
45 object_id=node.id,
46 name=tagname)
Scott Baker71c20eb2017-03-14 21:35:18 -070047 if tags:
48 return tags[0].value
49 else:
Scott Baker46831592016-06-20 17:32:04 -070050 return None
51
Scott Baker71c20eb2017-03-14 21:35:18 -070052 def fetch_pending(self, deleted):
Scott Baker8474a742017-06-15 10:34:07 -070053 # If fetch_pending is being called for delete, then just execute the standard delete logic.
54 if deleted:
Scott Baker8fddcac2017-08-24 08:56:04 -070055 return super(SyncAddressManagerServiceInstance, self).fetch_pending(deleted)
Scott Baker8474a742017-06-15 10:34:07 -070056
Scott Baker71c20eb2017-03-14 21:35:18 -070057 fs = FabricService.objects.first()
58 if (not fs) or (not fs.autoconfig):
59 return None
60
61 # TODO: Why is this a nonstandard synchronizer query?
Scott Baker8fddcac2017-08-24 08:56:04 -070062 objs = AddressManagerServiceInstance.objects.all()
Scott Baker46831592016-06-20 17:32:04 -070063
Scott Bakeref17d0c2017-02-20 08:45:45 -080064 objs = list(objs)
65
Scott Baker8fddcac2017-08-24 08:56:04 -070066 # Check that each is a valid VSG tenant or instance
67 for address_si in objs:
68 sub = self.get_subscriber(address_si)
69 if sub:
70 if not sub.instance:
71 objs.remove(address_si)
Andy Baviera3c73732016-06-27 15:24:59 -040072 else:
Scott Baker8fddcac2017-08-24 08:56:04 -070073 # Maybe the Address is for an instance
Scott Baker71c20eb2017-03-14 21:35:18 -070074 # TODO: tenant_for_instance_id needs to be a real database field
Scott Baker8fddcac2017-08-24 08:56:04 -070075 instance_id = address_si.get_attribute("tenant_for_instance_id")
Andy Baviera3c73732016-06-27 15:24:59 -040076 if not instance_id:
Scott Baker8fddcac2017-08-24 08:56:04 -070077 objs.remove(address_si)
Andy Baviera3c73732016-06-27 15:24:59 -040078 else:
79 instance = Instance.objects.filter(id=instance_id)[0]
80 if not instance.instance_name:
Scott Baker8fddcac2017-08-24 08:56:04 -070081 objs.remove(address_si)
Andy Baviera3c73732016-06-27 15:24:59 -040082
Scott Baker46831592016-06-20 17:32:04 -070083 return objs
84
Scott Baker8fddcac2017-08-24 08:56:04 -070085 def get_subscriber(self, address_si):
86 links = address_si.provided_links.all()
Scott Baker7462a142017-07-19 16:34:29 -070087 for link in links:
88 if not link.subscriber_service_instance:
89 continue
Scott Baker8fddcac2017-08-24 08:56:04 -070090 # cast from ServiceInstance to VSGTEnant or similar
91 sub = link.subscriber_service_instance.leaf_model
92 # TODO: check here to make sure it's an appropriate type of ServiceInstance ?
93 return sub
Scott Baker7462a142017-07-19 16:34:29 -070094 return None
95
Scott Baker8fddcac2017-08-24 08:56:04 -070096 def map_sync_inputs(self, address_si):
Scott Baker46831592016-06-20 17:32:04 -070097
98 fos = self.get_fabric_onos_service()
99
Scott Baker7462a142017-07-19 16:34:29 -0700100 if not fos:
101 raise Exception("No fabric onos service")
102
Scott Baker46831592016-06-20 17:32:04 -0700103 name = None
104 instance = None
Scott Baker8fddcac2017-08-24 08:56:04 -0700105 # Address setup is kind of hacky right now, we'll
Scott Baker46831592016-06-20 17:32:04 -0700106 # need to revisit. The idea is:
107 # * Look up the instance corresponding to the address
108 # * Look up the node running the instance
109 # * Get the "location" tag, push to the fabric
Scott Baker7462a142017-07-19 16:34:29 -0700110
Scott Baker8fddcac2017-08-24 08:56:04 -0700111 sub = self.get_subscriber(address_si)
112 if sub:
113 instance = sub.instance
114 name = str(sub)
Scott Baker46831592016-06-20 17:32:04 -0700115 else:
Scott Baker8fddcac2017-08-24 08:56:04 -0700116 instance_id = address_si.get_attribute("tenant_for_instance_id")
Andy Baviera3c73732016-06-27 15:24:59 -0400117 instance = Instance.objects.filter(id=instance_id)[0]
118 name = str(instance)
Scott Baker46831592016-06-20 17:32:04 -0700119
120 node = instance.node
121 location = self.get_node_tag(node, "location")
122
Scott Baker71c20eb2017-03-14 21:35:18 -0700123 if not location:
Scott Baker8fddcac2017-08-24 08:56:04 -0700124 raise DeferredException("No location tag for node %s tenant %s -- skipping" % (str(node), str(address_si)))
Scott Baker71c20eb2017-03-14 21:35:18 -0700125
Andy Bavier82d89832016-06-28 15:31:06 -0400126 # Create JSON
127 data = {
Scott Baker8fddcac2017-08-24 08:56:04 -0700128 "%s/-1" % address_si.public_mac : {
Andy Bavier82d89832016-06-28 15:31:06 -0400129 "basic" : {
Scott Baker8fddcac2017-08-24 08:56:04 -0700130 "ips" : [ address_si.public_ip ],
Andy Bavier82d89832016-06-28 15:31:06 -0400131 "location" : location
132 }
133 }
134 }
135 # Stupid Ansible... leading space so it doesn't think it's a dict
136 rest_body = " " + json.dumps(data)
Andy Bavier92e3e002016-06-28 14:30:39 -0400137
Scott Baker46831592016-06-20 17:32:04 -0700138 # Is it a POST or DELETE?
139
Scott Baker46831592016-06-20 17:32:04 -0700140 fields = {
141 'rest_hostname': fos.rest_hostname,
142 'rest_port': fos.rest_port,
Scott Baker46831592016-06-20 17:32:04 -0700143 'rest_endpoint': "onos/v1/network/configuration/hosts",
Andy Bavier82d89832016-06-28 15:31:06 -0400144 'rest_body': rest_body,
Scott Baker46831592016-06-20 17:32:04 -0700145 'ansible_tag': '%s'%name, # name of ansible playbook
146 }
147 return fields
148
149 def map_sync_outputs(self, controller_image, res):
150 pass