blob: be5d76a24cbbe8b5b85e7e2119d1ec250a953680 [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
25class SyncVRouterTenant(SyncStep):
26 provides=[VRouterTenant]
27 observes = VRouterTenant
28 requested_interval=30
29 playbook='sync_host.yaml'
30
31 def get_fabric_onos_service(self):
Scott Baker71c20eb2017-03-14 21:35:18 -070032 fs = FabricService.objects.first()
Scott Baker7462a142017-07-19 16:34:29 -070033 for link in fs.subscribed_links.all():
34 if link.provider_service_instance:
35 # cast from ServiceInstance to ONOSApp
36 apps = ONOSApp.objects.filter(id=link.provider_service_instance.id)
37 if apps:
38 # cast from Service to ONOSService
39 onos = ONOSService.objects.get(id=apps[0].owner.id)
40 return onos
41 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:
55 return super(SyncVRouterTenant, self).fetch_pending(deleted)
56
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 Baker8474a742017-06-15 10:34:07 -070062 objs = VRouterTenant.objects.all()
Scott Baker46831592016-06-20 17:32:04 -070063
Scott Bakeref17d0c2017-02-20 08:45:45 -080064 objs = list(objs)
65
Andy Baviera3c73732016-06-27 15:24:59 -040066 # Check that each is a valid vCPE tenant or instance
67 for vroutertenant in objs:
Scott Baker7462a142017-07-19 16:34:29 -070068 # TODO: hardcoded service dependency
69 vsg = self.get_vsg_subscriber(vroutertenant)
70 if vsg:
71 if not vsg.instance:
Andy Baviera3c73732016-06-27 15:24:59 -040072 objs.remove(vroutertenant)
73 else:
74 # Maybe the VRouterTenant is for an instance
Scott Baker71c20eb2017-03-14 21:35:18 -070075 # TODO: tenant_for_instance_id needs to be a real database field
Andy Baviera3c73732016-06-27 15:24:59 -040076 instance_id = vroutertenant.get_attribute("tenant_for_instance_id")
77 if not instance_id:
78 objs.remove(vroutertenant)
79 else:
80 instance = Instance.objects.filter(id=instance_id)[0]
81 if not instance.instance_name:
82 objs.remove(vroutertenant)
83
Scott Baker46831592016-06-20 17:32:04 -070084 return objs
85
Scott Baker7462a142017-07-19 16:34:29 -070086 def get_vsg_subscriber(self, vroutertenant):
87 links = vroutertenant.provided_links.all()
88 for link in links:
89 if not link.subscriber_service_instance:
90 continue
91 # cast from ServiceInstance to VSGTEnant
92 vsgs = VSGTenant.objects.filter(id=link.subscriber_service_instance.id)
93 if vsgs:
94 return vsgs[0]
95 return None
96
Scott Baker46831592016-06-20 17:32:04 -070097 def map_sync_inputs(self, vroutertenant):
98
99 fos = self.get_fabric_onos_service()
100
Scott Baker7462a142017-07-19 16:34:29 -0700101 if not fos:
102 raise Exception("No fabric onos service")
103
Scott Baker46831592016-06-20 17:32:04 -0700104 name = None
105 instance = None
106 # VRouterTenant setup is kind of hacky right now, we'll
107 # need to revisit. The idea is:
108 # * Look up the instance corresponding to the address
109 # * Look up the node running the instance
110 # * Get the "location" tag, push to the fabric
Scott Baker7462a142017-07-19 16:34:29 -0700111
112 # TODO: hardcoded service dependency
113 vsg = self.get_vsg_subscriber(vroutertenant)
114 if vsg:
Scott Baker71c20eb2017-03-14 21:35:18 -0700115 instance = vsg.instance
Scott Baker7462a142017-07-19 16:34:29 -0700116 name = str(vsg)
Scott Baker46831592016-06-20 17:32:04 -0700117 else:
Scott Baker46831592016-06-20 17:32:04 -0700118 instance_id = vroutertenant.get_attribute("tenant_for_instance_id")
Andy Baviera3c73732016-06-27 15:24:59 -0400119 instance = Instance.objects.filter(id=instance_id)[0]
120 name = str(instance)
Scott Baker46831592016-06-20 17:32:04 -0700121
122 node = instance.node
123 location = self.get_node_tag(node, "location")
124
Scott Baker71c20eb2017-03-14 21:35:18 -0700125 if not location:
126 raise DeferredException("No location tag for node %s tenant %s -- skipping" % (str(node), str(vroutertenant)))
127
Andy Bavier82d89832016-06-28 15:31:06 -0400128 # Create JSON
129 data = {
130 "%s/-1" % vroutertenant.public_mac : {
131 "basic" : {
132 "ips" : [ vroutertenant.public_ip ],
133 "location" : location
134 }
135 }
136 }
137 # Stupid Ansible... leading space so it doesn't think it's a dict
138 rest_body = " " + json.dumps(data)
Andy Bavier92e3e002016-06-28 14:30:39 -0400139
Scott Baker46831592016-06-20 17:32:04 -0700140 # Is it a POST or DELETE?
141
Scott Baker46831592016-06-20 17:32:04 -0700142 fields = {
143 'rest_hostname': fos.rest_hostname,
144 'rest_port': fos.rest_port,
Scott Baker46831592016-06-20 17:32:04 -0700145 'rest_endpoint': "onos/v1/network/configuration/hosts",
Andy Bavier82d89832016-06-28 15:31:06 -0400146 'rest_body': rest_body,
Scott Baker46831592016-06-20 17:32:04 -0700147 'ansible_tag': '%s'%name, # name of ansible playbook
148 }
149 return fields
150
151 def map_sync_outputs(self, controller_image, res):
152 pass