54c3e2a3d531dc2a69755a7165c24d54166be83f
[osm/SO.git] / rwlaunchpad / plugins / rwlaunchpadtasklet / rift / tasklets / rwlaunchpad / onboard.py
1
2 #
3 # Copyright 2016 RIFT.IO Inc
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import requests
19
20 from rift.mano.utils.project import DEFAULT_PROJECT
21 from rift.package import convert
22 from gi.repository import (
23 ProjectNsdYang as NsdYang,
24 RwNsdYang as RwNsdYang,
25 RwProjectNsdYang as RwProjectNsdYang,
26 ProjectVnfdYang as VnfdYang,
27 RwVnfdYang as RwVnfdYang,
28 RwProjectVnfdYang as RwProjectVnfdYang,
29 )
30
31
32 class OnboardError(Exception):
33 pass
34
35
36 class UpdateError(Exception):
37 pass
38
39
40 class DescriptorOnboarder(object):
41 """ This class is responsible for onboarding descriptors using Restconf"""
42 DESC_ENDPOINT_MAP = {
43 NsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: "nsd-catalog/nsd",
44 RwNsdYang.YangData_Nsd_NsdCatalog_Nsd: "nsd-catalog/nsd",
45 RwProjectNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: "nsd-catalog/nsd",
46 VnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: "vnfd-catalog/vnfd",
47 RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: "vnfd-catalog/vnfd",
48 RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd: "vnfd-catalog/vnfd"
49 }
50
51 DESC_SERIALIZER_MAP = {
52 NsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: convert.NsdSerializer(),
53 RwNsdYang.YangData_Nsd_NsdCatalog_Nsd: convert.RwNsdSerializer(),
54 RwProjectNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: convert.RwNsdSerializer(),
55 VnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: convert.VnfdSerializer(),
56 RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: convert.RwVnfdSerializer(),
57 RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd: convert.RwVnfdSerializer()
58 }
59
60 HEADERS = {"content-type": "application/vnd.yang.data+json"}
61 TIMEOUT_SECS = 60
62 AUTH = ('admin', 'admin')
63
64 def __init__(self, log, host="127.0.0.1", port=8008, use_ssl=False, ssl_cert=None, ssl_key=None):
65 self._log = log
66 self._host = host
67 self.port = port
68 self._use_ssl = use_ssl
69 self._ssl_cert = ssl_cert
70 self._ssl_key = ssl_key
71
72 self.timeout = DescriptorOnboarder.TIMEOUT_SECS
73
74 @classmethod
75 def _get_headers(cls):
76 headers = cls.HEADERS.copy()
77
78 return headers
79
80 def _get_url(self, descriptor_msg, project=None):
81 if type(descriptor_msg) not in DescriptorOnboarder.DESC_SERIALIZER_MAP:
82 raise TypeError("Invalid descriptor message type")
83
84 if project is None:
85 project = DEFAULT_PROJECT
86
87 endpoint = DescriptorOnboarder.DESC_ENDPOINT_MAP[type(descriptor_msg)]
88 ep = "project/{}/{}".format(project, endpoint)
89
90 url = "{}://{}:{}/api/config/{}".format(
91 "https" if self._use_ssl else "http",
92 self._host,
93 self.port,
94 ep,
95 )
96
97 return url
98
99 def _make_request_args(self, descriptor_msg, auth=None, project=None):
100 if type(descriptor_msg) not in DescriptorOnboarder.DESC_SERIALIZER_MAP:
101 raise TypeError("Invalid descriptor message type")
102
103 serializer = DescriptorOnboarder.DESC_SERIALIZER_MAP[type(descriptor_msg)]
104 json_data = serializer.to_json_string(descriptor_msg, project_ns=True)
105 url = self._get_url(descriptor_msg, project=project)
106
107 request_args = dict(
108 url=url,
109 data=json_data,
110 headers=self._get_headers(),
111 auth=DescriptorOnboarder.AUTH if auth is None else auth,
112 verify=False,
113 cert=(self._ssl_cert, self._ssl_key) if self._use_ssl else None,
114 timeout=self.timeout,
115 )
116
117 return request_args
118
119 def update(self, descriptor_msg, auth=None, project=None):
120 """ Update the descriptor config
121
122 Arguments:
123 descriptor_msg - A descriptor proto-gi msg
124 auth - the authorization header
125
126 Raises:
127 UpdateError - The descriptor config update failed
128 """
129 request_args = self._make_request_args(descriptor_msg, auth)
130 try:
131 response = requests.put(**request_args)
132 response.raise_for_status()
133 except requests.exceptions.ConnectionError as e:
134 msg = "Could not connect to restconf endpoint: %s" % str(e)
135 self._log.error(msg)
136 raise UpdateError(msg) from e
137 except requests.exceptions.HTTPError as e:
138 msg = "PUT request to %s error: %s" % (request_args["url"], response.text)
139 self._log.error(msg)
140 raise UpdateError(msg) from e
141 except requests.exceptions.Timeout as e:
142 msg = "Timed out connecting to restconf endpoint: %s", str(e)
143 self._log.error(msg)
144 raise UpdateError(msg) from e
145
146 def onboard(self, descriptor_msg, auth=None, project=None):
147 """ Onboard the descriptor config
148
149 Arguments:
150 descriptor_msg - A descriptor proto-gi msg
151 auth - the authorization header
152
153 Raises:
154 OnboardError - The descriptor config update failed
155 """
156
157 request_args = self._make_request_args(descriptor_msg, auth, project)
158 try:
159 response = requests.post(**request_args)
160 response.raise_for_status()
161 except requests.exceptions.ConnectionError as e:
162 msg = "Could not connect to restconf endpoint: %s" % str(e)
163 self._log.error(msg)
164 self._log.exception(msg)
165 raise OnboardError(msg) from e
166 except requests.exceptions.HTTPError as e:
167 msg = "POST request to %s error: %s" % (request_args["url"], response.text)
168 self._log.error(msg)
169 self._log.exception(msg)
170 raise OnboardError(msg) from e
171 except requests.exceptions.Timeout as e:
172 msg = "Timed out connecting to restconf endpoint: %s", str(e)
173 self._log.error(msg)
174 self._log.exception(msg)
175 raise OnboardError(msg) from e
176
177 def get_updated_descriptor(self, descriptor_msg, project_name, auth=None):
178 """ Get updated descriptor file
179
180 Arguments:
181 descriptor_msg - A descriptor proto-gi msg
182 auth - the authorization header
183
184 Raises:
185 OnboardError - The descriptor retrieval failed
186 """
187
188 if type(descriptor_msg) not in DescriptorOnboarder.DESC_SERIALIZER_MAP:
189 raise TypeError("Invalid descriptor message type")
190
191 endpoint = DescriptorOnboarder.DESC_ENDPOINT_MAP[type(descriptor_msg)]
192
193 url = "{}://{}:{}/api/config/project/{}/{}/{}".format(
194 "https" if self._use_ssl else "http",
195 self._host,
196 self.port,
197 project_name,
198 endpoint,
199 descriptor_msg.id
200 )
201
202 hdrs = self._get_headers()
203 hdrs.update({'Accept': 'application/json'})
204 request_args = dict(
205 url=url,
206 headers=hdrs,
207 auth=DescriptorOnboarder.AUTH,
208 verify=False,
209 cert=(self._ssl_cert, self._ssl_key) if self._use_ssl else None,
210 timeout=self.timeout,
211 )
212
213 response = None
214 try:
215 response = requests.get(**request_args)
216 response.raise_for_status()
217 except requests.exceptions.ConnectionError as e:
218 msg = "Could not connect to restconf endpoint: %s" % str(e)
219 self._log.error(msg)
220 raise OnboardError(msg) from e
221 except requests.exceptions.HTTPError as e:
222 msg = "GET request to %s error: %s" % (request_args["url"], response.text)
223 self._log.error(msg)
224 raise OnboardError(msg) from e
225 except requests.exceptions.Timeout as e:
226 msg = "Timed out connecting to restconf endpoint: %s", str(e)
227 self._log.error(msg)
228 raise OnboardError(msg) from e
229
230 return response.json()
231