Merge from OSM SO master
[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 RwProjectNsdYang as RwNsdYang,
25 ProjectVnfdYang as VnfdYang,
26 RwProjectVnfdYang as RwVnfdYang,
27 )
28
29
30 class OnboardError(Exception):
31 pass
32
33
34 class UpdateError(Exception):
35 pass
36
37
38 class DescriptorOnboarder(object):
39 """ This class is responsible for onboarding descriptors using Restconf"""
40 DESC_ENDPOINT_MAP = {
41 NsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: "nsd-catalog/nsd",
42 RwNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: "nsd-catalog/nsd",
43 VnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: "vnfd-catalog/vnfd",
44 RwVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: "vnfd-catalog/vnfd",
45 }
46
47 DESC_SERIALIZER_MAP = {
48 NsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: convert.NsdSerializer(),
49 RwNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd: convert.RwNsdSerializer(),
50 VnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: convert.VnfdSerializer(),
51 RwVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd: convert.RwVnfdSerializer(),
52 }
53
54 HEADERS = {"content-type": "application/vnd.yang.data+json"}
55 TIMEOUT_SECS = 60
56 AUTH = ('admin', 'admin')
57
58 def __init__(self, log, host="127.0.0.1", port=8008, use_ssl=False, ssl_cert=None, ssl_key=None):
59 self._log = log
60 self._host = host
61 self.port = port
62 self._use_ssl = use_ssl
63 self._ssl_cert = ssl_cert
64 self._ssl_key = ssl_key
65
66 self.timeout = DescriptorOnboarder.TIMEOUT_SECS
67
68 @classmethod
69 def _get_headers(cls, auth):
70 headers = cls.HEADERS.copy()
71 if auth is not None:
72 headers['authorization'] = auth
73
74 return headers
75
76 def _get_url(self, descriptor_msg, project=None):
77 if type(descriptor_msg) not in DescriptorOnboarder.DESC_SERIALIZER_MAP:
78 raise TypeError("Invalid descriptor message type")
79
80 if project is None:
81 project = DEFAULT_PROJECT
82
83 endpoint = DescriptorOnboarder.DESC_ENDPOINT_MAP[type(descriptor_msg)]
84 ep = "project/{}/{}".format(project, endpoint)
85
86 url = "{}://{}:{}/api/config/{}".format(
87 "https" if self._use_ssl else "http",
88 self._host,
89 self.port,
90 ep,
91 )
92
93 return url
94
95 def _make_request_args(self, descriptor_msg, auth=None, project=None):
96 if type(descriptor_msg) not in DescriptorOnboarder.DESC_SERIALIZER_MAP:
97 raise TypeError("Invalid descriptor message type")
98
99 serializer = DescriptorOnboarder.DESC_SERIALIZER_MAP[type(descriptor_msg)]
100 json_data = serializer.to_json_string(descriptor_msg, project_ns=True)
101 url = self._get_url(descriptor_msg, project=project)
102
103 request_args = dict(
104 url=url,
105 data=json_data,
106 headers=self._get_headers(auth),
107 auth=DescriptorOnboarder.AUTH,
108 verify=False,
109 cert=(self._ssl_cert, self._ssl_key) if self._use_ssl else None,
110 timeout=self.timeout,
111 )
112
113 return request_args
114
115 def update(self, descriptor_msg, auth=None, project=None):
116 """ Update the descriptor config
117
118 Arguments:
119 descriptor_msg - A descriptor proto-gi msg
120 auth - the authorization header
121
122 Raises:
123 UpdateError - The descriptor config update failed
124 """
125 request_args = self._make_request_args(descriptor_msg, auth)
126 try:
127 response = requests.put(**request_args)
128 response.raise_for_status()
129 except requests.exceptions.ConnectionError as e:
130 msg = "Could not connect to restconf endpoint: %s" % str(e)
131 self._log.error(msg)
132 raise UpdateError(msg) from e
133 except requests.exceptions.HTTPError as e:
134 msg = "PUT request to %s error: %s" % (request_args["url"], response.text)
135 self._log.error(msg)
136 raise UpdateError(msg) from e
137 except requests.exceptions.Timeout as e:
138 msg = "Timed out connecting to restconf endpoint: %s", str(e)
139 self._log.error(msg)
140 raise UpdateError(msg) from e
141
142 def onboard(self, descriptor_msg, auth=None, project=None):
143 """ Onboard the descriptor config
144
145 Arguments:
146 descriptor_msg - A descriptor proto-gi msg
147 auth - the authorization header
148
149 Raises:
150 OnboardError - The descriptor config update failed
151 """
152
153 request_args = self._make_request_args(descriptor_msg, auth, project)
154 try:
155 response = requests.post(**request_args)
156 response.raise_for_status()
157 except requests.exceptions.ConnectionError as e:
158 msg = "Could not connect to restconf endpoint: %s" % str(e)
159 self._log.error(msg)
160 self._log.exception(msg)
161 raise OnboardError(msg) from e
162 except requests.exceptions.HTTPError as e:
163 msg = "POST request to %s error: %s" % (request_args["url"], response.text)
164 self._log.error(msg)
165 self._log.exception(msg)
166 raise OnboardError(msg) from e
167 except requests.exceptions.Timeout as e:
168 msg = "Timed out connecting to restconf endpoint: %s", str(e)
169 self._log.error(msg)
170 self._log.exception(msg)
171 raise OnboardError(msg) from e
172