Fixes bug #57
[osm/RO.git] / vimconn.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
22 ##
23
24 '''
25 vimconn implement an Abstract class for the vim connector plugins
26 with the definition of the method to be implemented.
27 '''
28 __author__="Alfonso Tierno"
29 __date__ ="$16-oct-2015 11:09:29$"
30
31 import logging
32
33 #Error variables
34 HTTP_Bad_Request = 400
35 HTTP_Unauthorized = 401
36 HTTP_Not_Found = 404
37 HTTP_Method_Not_Allowed = 405
38 HTTP_Request_Timeout = 408
39 HTTP_Conflict = 409
40 HTTP_Not_Implemented = 501
41 HTTP_Service_Unavailable = 503
42 HTTP_Internal_Server_Error = 500
43
44 class vimconnException(Exception):
45 '''Common and base class Exception for all vimconnector exceptions'''
46 def __init__(self, message, http_code=HTTP_Bad_Request):
47 Exception.__init__(self, message)
48 self.http_code = http_code
49
50 class vimconnConnectionException(vimconnException):
51 '''Connectivity error with the VIM'''
52 def __init__(self, message, http_code=HTTP_Service_Unavailable):
53 vimconnException.__init__(self, message, http_code)
54
55 class vimconnUnexpectedResponse(vimconnException):
56 '''Get an wrong response from VIM'''
57 def __init__(self, message, http_code=HTTP_Service_Unavailable):
58 vimconnException.__init__(self, message, http_code)
59
60 class vimconnAuthException(vimconnException):
61 '''Invalid credentials or authorization to perform this action over the VIM'''
62 def __init__(self, message, http_code=HTTP_Unauthorized):
63 vimconnException.__init__(self, message, http_code)
64
65 class vimconnNotFoundException(vimconnException):
66 '''The item is not found at VIM'''
67 def __init__(self, message, http_code=HTTP_Not_Found):
68 vimconnException.__init__(self, message, http_code)
69
70 class vimconnConflictException(vimconnException):
71 '''There is a conflict, e.g. more item found than one'''
72 def __init__(self, message, http_code=HTTP_Conflict):
73 vimconnException.__init__(self, message, http_code)
74
75 class vimconnNotImplemented(vimconnException):
76 '''The method is not implemented by the connected'''
77 def __init__(self, message, http_code=HTTP_Not_Implemented):
78 vimconnException.__init__(self, message, http_code)
79
80 class vimconnector():
81 '''Abstract base class for all the VIM connector plugins
82 These plugins must implement a vimconnector class derived from this
83 and all these methods
84 '''
85 def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level="ERROR", config={}):
86 self.id = uuid
87 self.name = name
88 self.url = url
89 self.url_admin = url_admin
90 self.tenant_id = tenant_id
91 self.tenant_name = tenant_name
92 self.user = user
93 self.passwd = passwd
94 self.config = config
95 self.logger = logging.getLogger('openmano.vim')
96 self.logger.setLevel( getattr(logging, log_level) )
97 if not self.url_admin: #try to use normal url
98 self.url_admin = self.url
99
100 def __getitem__(self,index):
101 if index=='tenant_id':
102 return self.tenant_id
103 if index=='tenant_name':
104 return self.tenant_name
105 elif index=='id':
106 return self.id
107 elif index=='name':
108 return self.name
109 elif index=='user':
110 return self.user
111 elif index=='passwd':
112 return self.passwd
113 elif index=='url':
114 return self.url
115 elif index=='url_admin':
116 return self.url_admin
117 elif index=="config":
118 return self.config
119 else:
120 raise KeyError("Invalid key '%s'" %str(index))
121
122 def __setitem__(self,index, value):
123 if index=='tenant_id':
124 self.tenant_id = value
125 if index=='tenant_name':
126 self.tenant_name = value
127 elif index=='id':
128 self.id = value
129 elif index=='name':
130 self.name = value
131 elif index=='user':
132 self.user = value
133 elif index=='passwd':
134 self.passwd = value
135 elif index=='url':
136 self.url = value
137 elif index=='url_admin':
138 self.url_admin = value
139 else:
140 raise KeyError("Invalid key '%s'" %str(index))
141
142 def new_tenant(self,tenant_name,tenant_description):
143 '''Adds a new tenant to VIM with this name and description,
144 returns the tenant identifier'''
145 raise vimconnNotImplemented( "Should have implemented this" )
146
147 def delete_tenant(self,tenant_id,):
148 '''Delete a tenant from VIM'''
149 '''Returns the tenant identifier'''
150 raise vimconnNotImplemented( "Should have implemented this" )
151
152 def get_tenant_list(self, filter_dict={}):
153 '''Obtain tenants of VIM
154 filter_dict can contain the following keys:
155 name: filter by tenant name
156 id: filter by tenant uuid/id
157 <other VIM specific>
158 Returns the tenant list of dictionaries:
159 [{'name':'<name>, 'id':'<id>, ...}, ...]
160 '''
161 raise vimconnNotImplemented( "Should have implemented this" )
162
163 def new_network(self,net_name, net_type, ip_profile=None, shared=False):
164 '''Adds a tenant network to VIM
165 net_name is the name
166 net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
167 ip_profile is a dict containing the IP parameters of the network
168 shared is a boolean
169 Returns the network identifier'''
170 raise vimconnNotImplemented( "Should have implemented this" )
171
172 def get_network_list(self, filter_dict={}):
173 '''Obtain tenant networks of VIM
174 Filter_dict can be:
175 name: network name
176 id: network uuid
177 shared: boolean
178 tenant_id: tenant
179 admin_state_up: boolean
180 status: 'ACTIVE'
181 Returns the network list of dictionaries:
182 [{<the fields at Filter_dict plus some VIM specific>}, ...]
183 List can be empty
184 '''
185 raise vimconnNotImplemented( "Should have implemented this" )
186
187 def get_network(self, net_id):
188 '''Obtain network details of net_id VIM network'
189 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]'''
190 raise vimconnNotImplemented( "Should have implemented this" )
191
192 def delete_network(self, net_id):
193 '''Deletes a tenant network from VIM, provide the network id.
194 Returns the network identifier or raise an exception'''
195 raise vimconnNotImplemented( "Should have implemented this" )
196
197 def refresh_nets_status(self, net_list):
198 '''Get the status of the networks
199 Params: the list of network identifiers
200 Returns a dictionary with:
201 net_id: #VIM id of this network
202 status: #Mandatory. Text with one of:
203 # DELETED (not found at vim)
204 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
205 # OTHER (Vim reported other status not understood)
206 # ERROR (VIM indicates an ERROR status)
207 # ACTIVE, INACTIVE, DOWN (admin down),
208 # BUILD (on building process)
209 #
210 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
211 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
212
213 '''
214 raise vimconnNotImplemented( "Should have implemented this" )
215
216 def get_flavor(self, flavor_id):
217 '''Obtain flavor details from the VIM
218 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
219 '''
220 raise vimconnNotImplemented( "Should have implemented this" )
221
222 def new_flavor(self, flavor_data):
223 '''Adds a tenant flavor to VIM
224 flavor_data contains a dictionary with information, keys:
225 name: flavor name
226 ram: memory (cloud type) in MBytes
227 vpcus: cpus (cloud type)
228 extended: EPA parameters
229 - numas: #items requested in same NUMA
230 memory: number of 1G huge pages memory
231 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
232 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
233 - name: interface name
234 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
235 bandwidth: X Gbps; requested guarantee bandwidth
236 vpci: requested virtual PCI address
237 disk: disk size
238 is_public:
239
240
241
242 #TODO to concrete
243 Returns the flavor identifier'''
244 raise vimconnNotImplemented( "Should have implemented this" )
245
246 def delete_flavor(self, flavor_id):
247 '''Deletes a tenant flavor from VIM identify by its id
248 Returns the used id or raise an exception'''
249 raise vimconnNotImplemented( "Should have implemented this" )
250
251 def new_image(self,image_dict):
252 '''
253 Adds a tenant image to VIM
254 Returns:
255 200, image-id if the image is created
256 <0, message if there is an error
257 '''
258 raise vimconnNotImplemented( "Should have implemented this" )
259
260 def delete_image(self, image_id):
261 '''Deletes a tenant image from VIM'''
262 '''Returns the HTTP response code and a message indicating details of the success or fail'''
263 raise vimconnNotImplemented( "Should have implemented this" )
264
265 def get_image_id_from_path(self, path):
266 '''Get the image id from image path in the VIM database'''
267 '''Returns:
268 0,"Image not found" if there are no images with that path
269 1,image-id if there is one image with that path
270 <0,message if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.)
271 '''
272 raise vimconnNotImplemented( "Should have implemented this" )
273
274 def new_vminstance(self,name,description,start,image_id,flavor_id,net_list,cloud_config=None):
275 '''Adds a VM instance to VIM
276 Params:
277 start: indicates if VM must start or boot in pause mode. Ignored
278 image_id,flavor_id: image and flavor uuid
279 net_list: list of interfaces, each one is a dictionary with:
280 name:
281 net_id: network uuid to connect
282 vpci: virtual vcpi to assign
283 model: interface model, virtio, e2000, ...
284 mac_address:
285 use: 'data', 'bridge', 'mgmt'
286 type: 'virtual', 'PF', 'VF', 'VFnotShared'
287 vim_id: filled/added by this function
288 cloud_config: can be a text script to be passed directly to cloud-init,
289 or an object to inject users and ssh keys with format:
290 key-pairs: [] list of keys to install to the default user
291 users: [{ name, key-pairs: []}] list of users to add with their key-pair
292 #TODO ip, security groups
293 Returns >=0, the instance identifier
294 <0, error_text
295 '''
296 raise vimconnNotImplemented( "Should have implemented this" )
297
298 def get_vminstance(self,vm_id):
299 '''Returns the VM instance information from VIM'''
300 raise vimconnNotImplemented( "Should have implemented this" )
301
302 def delete_vminstance(self, vm_id):
303 '''Removes a VM instance from VIM'''
304 '''Returns the instance identifier'''
305 raise vimconnNotImplemented( "Should have implemented this" )
306
307 def refresh_vms_status(self, vm_list):
308 '''Get the status of the virtual machines and their interfaces/ports
309 Params: the list of VM identifiers
310 Returns a dictionary with:
311 vm_id: #VIM id of this Virtual Machine
312 status: #Mandatory. Text with one of:
313 # DELETED (not found at vim)
314 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
315 # OTHER (Vim reported other status not understood)
316 # ERROR (VIM indicates an ERROR status)
317 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
318 # CREATING (on building process), ERROR
319 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
320 #
321 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
322 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
323 interfaces:
324 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
325 mac_address: #Text format XX:XX:XX:XX:XX:XX
326 vim_net_id: #network id where this interface is connected
327 vim_interface_id: #interface/port VIM id
328 ip_address: #null, or text with IPv4, IPv6 address
329 '''
330 raise vimconnNotImplemented( "Should have implemented this" )
331
332 def action_vminstance(self, vm_id, action_dict):
333 '''Send and action over a VM instance from VIM
334 Returns the vm_id if the action was successfully sent to the VIM'''
335 raise vimconnNotImplemented( "Should have implemented this" )
336
337 def get_vminstance_console(self,vm_id, console_type="vnc"):
338 '''
339 Get a console for the virtual machine
340 Params:
341 vm_id: uuid of the VM
342 console_type, can be:
343 "novnc" (by default), "xvpvnc" for VNC types,
344 "rdp-html5" for RDP types, "spice-html5" for SPICE types
345 Returns dict with the console parameters:
346 protocol: ssh, ftp, http, https, ...
347 server: usually ip address
348 port: the http, ssh, ... port
349 suffix: extra text, e.g. the http path and query string
350 '''
351 raise vimconnNotImplemented( "Should have implemented this" )
352
353 #NOT USED METHODS in current version
354
355 def host_vim2gui(self, host, server_dict):
356 '''Transform host dictionary from VIM format to GUI format,
357 and append to the server_dict
358 '''
359 raise vimconnNotImplemented( "Should have implemented this" )
360
361 def get_hosts_info(self):
362 '''Get the information of deployed hosts
363 Returns the hosts content'''
364 raise vimconnNotImplemented( "Should have implemented this" )
365
366 def get_hosts(self, vim_tenant):
367 '''Get the hosts and deployed instances
368 Returns the hosts content'''
369 raise vimconnNotImplemented( "Should have implemented this" )
370
371 def get_processor_rankings(self):
372 '''Get the processor rankings in the VIM database'''
373 raise vimconnNotImplemented( "Should have implemented this" )
374
375 def new_host(self, host_data):
376 '''Adds a new host to VIM'''
377 '''Returns status code of the VIM response'''
378 raise vimconnNotImplemented( "Should have implemented this" )
379
380 def new_external_port(self, port_data):
381 '''Adds a external port to VIM'''
382 '''Returns the port identifier'''
383 raise vimconnNotImplemented( "Should have implemented this" )
384
385 def new_external_network(self,net_name,net_type):
386 '''Adds a external network to VIM (shared)'''
387 '''Returns the network identifier'''
388 raise vimconnNotImplemented( "Should have implemented this" )
389
390 def connect_port_network(self, port_id, network_id, admin=False):
391 '''Connects a external port to a network'''
392 '''Returns status code of the VIM response'''
393 raise vimconnNotImplemented( "Should have implemented this" )
394
395 def new_vminstancefromJSON(self, vm_data):
396 '''Adds a VM instance to VIM'''
397 '''Returns the instance identifier'''
398 raise vimconnNotImplemented( "Should have implemented this" )
399