blob: 62882434b69a6a4348bac3270098aa605ec6beda [file] [log] [blame]
Matteo Scandolo0b986e22018-06-04 14:07:33 -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
16import json
17import requests
18from requests.auth import HTTPBasicAuth
19from synchronizers.new_base.syncstep import SyncStep, DeferredException, model_accessor
20from synchronizers.new_base.modelaccessor import ONOSApp, ServiceInstance, ServiceInstanceAttribute
21
22from xosconfig import Config
23from multistructlog import create_logger
24
25from helpers import Helpers
26
27log = create_logger(Config().get('logging'))
28log.info("config file", file=Config().get_config_file())
29
30class SyncONOSApp(SyncStep):
31 provides = [ONOSApp]
32 observes = [ONOSApp, ServiceInstanceAttribute]
33
34 def get_service_instance_attribute(self, o):
35 # NOTE this method is defined in the core convenience methods for service_instances
36 svc = ServiceInstance.objects.get(id=o.id)
37 return svc.serviceinstanceattribute_dict
38
39 def check_app_dependencies(self, deps):
40 """
41 Check if all the dependencies required by this application are installed
42 :param deps: comma separated list of application names
43 :return: bool
44 """
45 for dep in [x.strip() for x in str(deps).split(',') if x is not ""]:
46 try:
47 app = ONOSApp.objects.get(app_id=dep)
48 if not app.backend_code == 1:
49 # backend_code == 1 means that the app has been pushed
50 return False
51 except IndexError, e:
52 return False
53 return True
54
55 def add_config(self, o):
56 log.info("Adding config %s" % o.name, model=o.tologdict())
57 # getting onos url and auth
58 onos_url = "%s:%s" % (Helpers.format_url(o.service_instance.leaf_model.owner.leaf_model.rest_hostname), o.service_instance.leaf_model.owner.leaf_model.rest_port)
59 onos_basic_auth = HTTPBasicAuth(o.service_instance.leaf_model.owner.leaf_model.rest_username, o.service_instance.leaf_model.owner.leaf_model.rest_password)
60
61 # push configs (if any)
62 url = o.name
63 if url[0] == "/":
64 # strip initial /
65 url = url[1:]
66
67 url = '%s/%s' % (onos_url, url)
68 value = json.loads(o.value)
69 request = requests.post(url, json=value, auth=onos_basic_auth)
70
71 if request.status_code != 200:
72 log.error("Request failed", response=request.text)
73 raise Exception("Failed to add config %s in ONOS: %s" % (url, request.text))
74
75 def activate_app(self, o, onos_url, onos_basic_auth):
76 log.info("Activating app %s" % o.app_id)
77 url = '%s/onos/v1/applications/%s/active' % (onos_url, o.app_id)
78 request = requests.post(url, auth=onos_basic_auth)
79
80 if request.status_code != 200:
81 log.error("Request failed", response=request.text)
82 raise Exception("Failed to add application %s to ONOS: %s" % (url, request.text))
83
84 url = '%s/onos/v1/applications/%s' % (onos_url, o.app_id)
85 request = requests.get(url, auth=onos_basic_auth)
86
87 if request.status_code != 200:
88 log.error("Request failed", response=request.text)
89 raise Exception("Failed to read application %s from ONOS: %s" % (url, request.text))
90 else:
91 o.version = request.json()["version"]
92
93 def check_app_installed(self, o, onos_url, onos_basic_auth):
94 url = '%s/onos/v1/applications/%s' % (onos_url, o.app_id)
95 request = requests.get(url, auth=onos_basic_auth)
96
97 if request.status_code == 200:
98 if "version" in request.json() and o.version == request.json()["version"]:
99 return True
100 else:
101 # uninstall the application
102 self.uninstall_app(o, onos_url, onos_basic_auth)
103 return False
104 if request.status_code == 404:
105 # app is not installed at all
106 return False
107 else:
108 log.error("Request failed", response=request.text)
109 raise Exception("Failed to read application %s from ONOS: %s" % (url, request.text))
110
111 def install_app(self, o, onos_url, onos_basic_auth):
112 log.info("Installing app from url %s" % o.url)
113
114 # check is the already installed app is the correct version (if it has no app_id is not installed)
115 is_installed = False
116 if o.app_id and o.app_id is not None:
117 is_installed = self.check_app_installed(o, onos_url, onos_basic_auth)
118
119 if is_installed:
120 # if the app is already installed we don't need to do anything
121 return
122
123 if not o.version or o.version is None:
124 # TODO move this validation in the model.py (if the url is there version must there and app_id must not)
125 raise Exception('You need to specify a version')
126 data = {
127 'activate': True,
128 'url': o.url
129 }
130 url = '%s/onos/v1/applications' % onos_url
131 request = requests.post(url, json=data, auth=onos_basic_auth)
132
133 if request.status_code != 200:
134 log.error("Request failed", response=request.text)
135 raise Exception("Failed to add application %s to ONOS: %s" % (url, request.text))
136
137 o.app_id = request.json()["name"]
138
139 url = '%s/onos/v1/applications/%s' % (onos_url, o.app_id)
140 request = requests.get(url, auth=onos_basic_auth)
141
142 if request.status_code != 200:
143 log.error("Request failed", response=request.text)
144 raise Exception("Failed to read application %s from ONOS: %s" % (url, request.text))
145 else:
146 if o.version != request.json()["version"]:
147 raise Exception("The version of %s you installed (%s) is not the same you requested (%s)" % (o.app_id, request.json()["version"], o.version))
148
149 def sync_record(self, o):
150 log.info("Sync'ing", model=o.tologdict())
151 if hasattr(o, 'service_instance'):
152 # this is a ServiceInstanceAttribute model just push the config
153 if 'ONOSApp' in o.service_instance.leaf_model.class_names:
154 return self.add_config(o)
155 return # if it's not an ONOSApp do nothing
156
157 if not self.check_app_dependencies(o.dependencies):
158 raise DeferredException('Deferring installation of ONOSApp with id %s as dependencies are not met' % o.id)
159
160 # getting onos url and auth
161 onos_url = "%s:%s" % (Helpers.format_url(o.owner.leaf_model.rest_hostname), o.owner.leaf_model.rest_port)
162 onos_basic_auth = HTTPBasicAuth(o.owner.leaf_model.rest_username, o.owner.leaf_model.rest_password)
163
164 # activate app (bundled in onos)
165 if not o.url or o.url is None:
166 self.activate_app(o, onos_url, onos_basic_auth)
167 # install an app from a remote source
168 if o.url and o.url is not None:
169 self.install_app(o, onos_url, onos_basic_auth)
170
171 def delete_config(self, o):
172 log.info("Deleting config %s" % o.name)
173 # getting onos url and auth
174 onos_app = o.service_instance.leaf_model
175 onos_url = "%s:%s" % (Helpers.format_url(onos_app.owner.leaf_model.rest_hostname), onos_app.owner.leaf_model.rest_port)
176 onos_basic_auth = HTTPBasicAuth(onos_app.owner.leaf_model.rest_username, onos_app.owner.leaf_model.rest_password)
177
178 url = o.name
179 if url[0] == "/":
180 # strip initial /
181 url = url[1:]
182
183 url = '%s/%s' % (onos_url, url)
184 request = requests.delete(url, auth=onos_basic_auth)
185
186 if request.status_code != 204:
187 log.error("Request failed", response=request.text)
188 raise Exception("Failed to remove config %s from ONOS: %s" % (url, request.text))
189
190 def uninstall_app(self,o, onos_url, onos_basic_auth):
191 log.info("Uninstalling app %s" % o.app_id)
192 url = '%s/onos/v1/applications/%s' % (onos_url, o.app_id)
193
194 request = requests.delete(url, auth=onos_basic_auth)
195
196 if request.status_code != 204:
197 log.error("Request failed", response=request.text)
198 raise Exception("Failed to delete application %s from ONOS: %s" % (url, request.text))
199
200 def deactivate_app(self, o, onos_url, onos_basic_auth):
201 log.info("Deactivating app %s" % o.app_id)
202 url = '%s/onos/v1/applications/%s/active' % (onos_url, o.app_id)
203
204 request = requests.delete(url, auth=onos_basic_auth)
205
206 if request.status_code != 204:
207 log.error("Request failed", response=request.text)
208 raise Exception("Failed to deactivate application %s from ONOS: %s" % (url, request.text))
209
210 def delete_record(self, o):
211
212 if hasattr(o, 'service_instance'):
213 # this is a ServiceInstanceAttribute model
214 if 'ONOSApp' in o.service_instance.leaf_model.class_names:
215 return self.delete_config(o)
216 return # if it's not related to an ONOSApp do nothing
217
218 # NOTE if it is an ONOSApp we don't care about the ServiceInstanceAttribute
219 # as the reaper will delete it
220
221 # getting onos url and auth
222 onos_url = "%s:%s" % (Helpers.format_url(o.owner.leaf_model.rest_hostname), o.owner.leaf_model.rest_port)
223 onos_basic_auth = HTTPBasicAuth(o.owner.leaf_model.rest_username, o.owner.leaf_model.rest_password)
224
225 # deactivate an app (bundled in onos)
226 if not o.url or o.url is None:
227 self.deactivate_app(o, onos_url, onos_basic_auth)
228 # uninstall an app from a remote source, only if it has been activated before
229 if o.url and o.url is not None:
230 self.uninstall_app(o, onos_url, onos_basic_auth)