Support of network slices
[osm/osmclient.git] / osmclient / sol005 / nsi.py
1 # Copyright 2018 Telefonica
2 #
3 # All Rights Reserved.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # 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, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16
17 """
18 OSM NSI (Network Slice Instance) API handling
19 """
20
21 from osmclient.common import utils
22 from osmclient.common.exceptions import ClientException
23 from osmclient.common.exceptions import NotFound
24 import yaml
25 import json
26
27
28 class Nsi(object):
29
30 def __init__(self, http=None, client=None):
31 self._http = http
32 self._client = client
33 self._apiName = '/nsilcm'
34 self._apiVersion = '/v1'
35 self._apiResource = '/netslice_instances_content'
36 self._apiBase = '{}{}{}'.format(self._apiName,
37 self._apiVersion, self._apiResource)
38
39 def list(self, filter=None):
40 """Returns a list of NSI
41 """
42 filter_string = ''
43 if filter:
44 filter_string = '?{}'.format(filter)
45 resp = self._http.get_cmd('{}{}'.format(self._apiBase,filter_string))
46 if resp:
47 return resp
48 return list()
49
50 def get(self, name):
51 """Returns an NSI based on name or id
52 """
53 if utils.validate_uuid4(name):
54 for nsi in self.list():
55 if name == nsi['_id']:
56 return nsi
57 else:
58 for nsi in self.list():
59 if name == nsi['name']:
60 return nsi
61 raise NotFound("nsi {} not found".format(name))
62
63 def get_individual(self, name):
64 nsi_id = name
65 if not utils.validate_uuid4(name):
66 for nsi in self.list():
67 if name == nsi['name']:
68 nsi_id = nsi['_id']
69 break
70 resp = self._http.get_cmd('{}/{}'.format(self._apiBase, nsi_id))
71 #resp = self._http.get_cmd('{}/{}/nsd_content'.format(self._apiBase, nsi_id))
72 #print yaml.safe_dump(resp)
73 if resp:
74 return resp
75 raise NotFound("nsi {} not found".format(name))
76
77 def delete(self, name, force=False):
78 nsi = self.get(name)
79 querystring = ''
80 if force:
81 querystring = '?FORCE=True'
82 http_code, resp = self._http.delete_cmd('{}/{}{}'.format(self._apiBase,
83 nsi['_id'], querystring))
84 #print 'HTTP CODE: {}'.format(http_code)
85 #print 'RESP: {}'.format(resp)
86 if http_code == 202:
87 print('Deletion in progress')
88 elif http_code == 204:
89 print('Deleted')
90 else:
91 msg = ""
92 if resp:
93 try:
94 msg = json.loads(resp)
95 except ValueError:
96 msg = resp
97 raise ClientException("failed to delete nsi {} - {}".format(name, msg))
98
99 def create(self, nst_name, nsi_name, account, config=None,
100 ssh_keys=None, description='default description',
101 admin_status='ENABLED'):
102
103 nst = self._client.nst.get(nst_name)
104
105 vim_account_id = {}
106
107 def get_vim_account_id(vim_account):
108 if vim_account_id.get(vim_account):
109 return vim_account_id[vim_account]
110
111 vim = self._client.vim.get(vim_account)
112 if vim is None:
113 raise NotFound("cannot find vim account '{}'".format(vim_account))
114 vim_account_id[vim_account] = vim['_id']
115 return vim['_id']
116
117 nsi = {}
118 nsi['nstId'] = nst['_id']
119 nsi['nsiName'] = nsi_name
120 nsi['nsiDescription'] = description
121 nsi['vimAccountId'] = get_vim_account_id(account)
122 #nsi['userdata'] = {}
123 #nsi['userdata']['key1']='value1'
124 #nsi['userdata']['key2']='value2'
125
126 if ssh_keys is not None:
127 # ssh_keys is comma separate list
128 # ssh_keys_format = []
129 # for key in ssh_keys.split(','):
130 # ssh_keys_format.append({'key-pair-ref': key})
131 #
132 # ns['ssh-authorized-key'] = ssh_keys_format
133 nsi['ssh_keys'] = []
134 for pubkeyfile in ssh_keys.split(','):
135 with open(pubkeyfile, 'r') as f:
136 nsi['ssh_keys'].append(f.read())
137 if config:
138 nsi_config = yaml.load(config)
139 if "netslice-vld" in nsi_config:
140 for vld in nsi_config["netslice-vld"]:
141 if vld.get("vim-network-name"):
142 if isinstance(vld["vim-network-name"], dict):
143 vim_network_name_dict = {}
144 for vim_account, vim_net in list(vld["vim-network-name"].items()):
145 vim_network_name_dict[get_vim_account_id(vim_account)] = vim_net
146 vld["vim-network-name"] = vim_network_name_dict
147 nsi["netslice-vld"] = nsi_config["netslice-vld"]
148 if "netslice-subnet" in nsi_config:
149 for nssubnet in nsi_config["netslice-subnet"]:
150 if "vld" in nssubnet:
151 for vld in nssubnet["vld"]:
152 if vld.get("vim-network-name"):
153 if isinstance(vld["vim-network-name"], dict):
154 vim_network_name_dict = {}
155 for vim_account, vim_net in list(vld["vim-network-name"].items()):
156 vim_network_name_dict[get_vim_account_id(vim_account)] = vim_net
157 vld["vim-network-name"] = vim_network_name_dict
158 if "vnf" in nssubnet:
159 for vnf in nsi_config["vnf"]:
160 if vnf.get("vim_account"):
161 vnf["vimAccountId"] = get_vim_account_id(vnf.pop("vim_account"))
162 nsi["netslice-subnet"] = nsi_config["netslice-subnet"]
163
164 #print yaml.safe_dump(nsi)
165 try:
166 self._apiResource = '/netslice_instances_content'
167 self._apiBase = '{}{}{}'.format(self._apiName,
168 self._apiVersion, self._apiResource)
169 headers = self._client._headers
170 headers['Content-Type'] = 'application/yaml'
171 http_header = ['{}: {}'.format(key,val)
172 for (key,val) in list(headers.items())]
173 self._http.set_http_header(http_header)
174 http_code, resp = self._http.post_cmd(endpoint=self._apiBase,
175 postfields_dict=nsi)
176 #print 'HTTP CODE: {}'.format(http_code)
177 #print 'RESP: {}'.format(resp)
178 if http_code in (200, 201, 202, 204):
179 if resp:
180 resp = json.loads(resp)
181 if not resp or 'id' not in resp:
182 raise ClientException('unexpected response from server - {} '.format(
183 resp))
184 print(resp['id'])
185 else:
186 msg = ""
187 if resp:
188 try:
189 msg = json.loads(resp)
190 except ValueError:
191 msg = resp
192 raise ClientException(msg)
193 except ClientException as exc:
194 message="failed to create nsi: {} nst: {}\nerror:\n{}".format(
195 nsi_name,
196 nst_name,
197 exc.message)
198 raise ClientException(message)
199
200 def list_op(self, name, filter=None):
201 """Returns the list of operations of a NSI
202 """
203 nsi = self.get(name)
204 try:
205 self._apiResource = '/nsi_lcm_op_occs'
206 self._apiBase = '{}{}{}'.format(self._apiName,
207 self._apiVersion, self._apiResource)
208 filter_string = ''
209 if filter:
210 filter_string = '&{}'.format(filter)
211 http_code, resp = self._http.get2_cmd('{}?nsiInstanceId={}'.format(
212 self._apiBase, nsi['_id'],
213 filter_string) )
214 #print 'HTTP CODE: {}'.format(http_code)
215 #print 'RESP: {}'.format(resp)
216 if http_code == 200:
217 if resp:
218 resp = json.loads(resp)
219 return resp
220 else:
221 raise ClientException('unexpected response from server')
222 else:
223 msg = ""
224 if resp:
225 try:
226 resp = json.loads(resp)
227 msg = resp['detail']
228 except ValueError:
229 msg = resp
230 raise ClientException(msg)
231 except ClientException as exc:
232 message="failed to get operation list of NSI {}:\nerror:\n{}".format(
233 name,
234 exc.message)
235 raise ClientException(message)
236
237 def get_op(self, operationId):
238 """Returns the status of an operation
239 """
240 try:
241 self._apiResource = '/nsi_lcm_op_occs'
242 self._apiBase = '{}{}{}'.format(self._apiName,
243 self._apiVersion, self._apiResource)
244 http_code, resp = self._http.get2_cmd('{}/{}'.format(self._apiBase, operationId))
245 #print 'HTTP CODE: {}'.format(http_code)
246 #print 'RESP: {}'.format(resp)
247 if http_code == 200:
248 if resp:
249 resp = json.loads(resp)
250 return resp
251 else:
252 raise ClientException('unexpected response from server')
253 else:
254 msg = ""
255 if resp:
256 try:
257 resp = json.loads(resp)
258 msg = resp['detail']
259 except ValueError:
260 msg = resp
261 raise ClientException(msg)
262 except ClientException as exc:
263 message="failed to get status of operation {}:\nerror:\n{}".format(
264 operationId,
265 exc.message)
266 raise ClientException(message)
267
268 def exec_op(self, name, op_name, op_data=None):
269 """Executes an operation on a NSI
270 """
271 nsi = self.get(name)
272 try:
273 self._apiResource = '/netslice_instances'
274 self._apiBase = '{}{}{}'.format(self._apiName,
275 self._apiVersion, self._apiResource)
276 endpoint = '{}/{}/{}'.format(self._apiBase, nsi['_id'], op_name)
277 #print 'OP_NAME: {}'.format(op_name)
278 #print 'OP_DATA: {}'.format(json.dumps(op_data))
279 http_code, resp = self._http.post_cmd(endpoint=endpoint, postfields_dict=op_data)
280 #print 'HTTP CODE: {}'.format(http_code)
281 #print 'RESP: {}'.format(resp)
282 if http_code in (200, 201, 202, 204):
283 if resp:
284 resp = json.loads(resp)
285 if not resp or 'id' not in resp:
286 raise ClientException('unexpected response from server - {}'.format(
287 resp))
288 print(resp['id'])
289 else:
290 msg = ""
291 if resp:
292 try:
293 msg = json.loads(resp)
294 except ValueError:
295 msg = resp
296 raise ClientException(msg)
297 except ClientException as exc:
298 message="failed to exec operation {}:\nerror:\n{}".format(
299 name,
300 exc.message)
301 raise ClientException(message)
302