1 # -*- coding: utf-8 -*-
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
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
12 # http://www.apache.org/licenses/LICENSE-2.0
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
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
25 vimconn_vmware implementation an Abstract class in order to interact with VMware vCloud Director.
32 from xml
.etree
import ElementTree
as ET
34 from pyvcloud
import Http
35 from pyvcloud
.vcloudair
import VCA
36 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
import sessionType
, organizationType
, \
37 vAppType
, organizationListType
, vdcType
, catalogType
, queryRecordViewType
, \
38 networkType
, vcloudType
, taskType
, diskType
, vmsType
, vdcTemplateListType
, mediaType
39 from xml
.sax
.saxutils
import escape
49 __author__
="Mustafa Bayramov"
50 __date__
="$26-Aug-2016 11:09:29$"
54 HTTP_Bad_Request
= 400
55 HTTP_Unauthorized
= 401
57 HTTP_Method_Not_Allowed
= 405
58 HTTP_Request_Timeout
= 408
60 HTTP_Not_Implemented
= 501
61 HTTP_Service_Unavailable
= 503
62 HTTP_Internal_Server_Error
= 500
64 class vimconnException(Exception):
65 '''Common and base class Exception for all vimconnector exceptions'''
66 def __init__(self
, message
, http_code
=HTTP_Bad_Request
):
67 Exception.__init
__(self
, message
)
68 self
.http_code
= http_code
70 class vimconnConnectionException(vimconnException
):
71 '''Connectivity error with the VIM'''
72 def __init__(self
, message
, http_code
=HTTP_Service_Unavailable
):
73 vimconnException
.__init
__(self
, message
, http_code
)
75 class vimconnUnexpectedResponse(vimconnException
):
76 '''Get an wrong response from VIM'''
77 def __init__(self
, message
, http_code
=HTTP_Service_Unavailable
):
78 vimconnException
.__init
__(self
, message
, http_code
)
80 class vimconnAuthException(vimconnException
):
81 '''Invalid credentials or authorization to perform this action over the VIM'''
82 def __init__(self
, message
, http_code
=HTTP_Unauthorized
):
83 vimconnException
.__init
__(self
, message
, http_code
)
85 class vimconnNotFoundException(vimconnException
):
86 '''The item is not found at VIM'''
87 def __init__(self
, message
, http_code
=HTTP_Not_Found
):
88 vimconnException
.__init
__(self
, message
, http_code
)
90 class vimconnConflictException(vimconnException
):
91 '''There is a conflict, e.g. more item found than one'''
92 def __init__(self
, message
, http_code
=HTTP_Conflict
):
93 vimconnException
.__init
__(self
, message
, http_code
)
95 class vimconnNotImplemented(vimconnException
):
96 '''The method is not implemented by the connected'''
97 def __init__(self
, message
, http_code
=HTTP_Not_Implemented
):
98 vimconnException
.__init
__(self
, message
, http_code
)
103 class vimconnector():
104 '''Vmware VIM Connector base class
106 def __init__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
=None, user
=None, passwd
=None, log_level
="ERROR", config
={}):
110 self
.url_admin
= url_admin
111 self
.tenant_id
= tenant_id
112 self
.tenant_name
= tenant_name
116 self
.logger
= logging
.getLogger('openmano.vim.vmware')
118 # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
119 # ch = logging.StreamHandler()
120 # ch.setLevel(log_level)
121 # ch.setFormatter(formatter)
122 # self.logger.addHandler(ch)
123 # self.logger.setLevel( getattr(logging, log_level))
125 # self.logger = logging.getLogger('mano.vim.vmware')
127 self
.logger
.debug("Vmware tenant from VIM filter: '%s'", user
)
128 self
.logger
.debug("Vmware tenant from VIM filter: '%s'", passwd
)
131 raise TypeError, 'url param can not be NoneType'
133 if not self
.url_admin
: #try to use normal url
134 self
.url_admin
= self
.url
136 self
.vcaversion
= '5.6'
138 print "Calling constructor with following paramters"
139 print " UUID: {} ".format(uuid
)
140 print " name: {} ".format(name
)
141 print " tenant_id: {} ".format(tenant_id
)
142 print " tenant_name: {} ".format(tenant_name
)
143 print " url: {} ".format(url
)
144 print " url_admin: {} ".format(url_admin
)
145 print " user: {} ".format(user
)
146 print " passwd: {} ".format(passwd
)
147 print " debug: {} ".format(log_level
)
149 def __getitem__(self
,index
):
150 if index
=='tenant_id':
151 return self
.tenant_id
152 if index
=='tenant_name':
153 return self
.tenant_name
160 elif index
=='passwd':
164 elif index
=='url_admin':
165 return self
.url_admin
166 elif index
=="config":
169 raise KeyError("Invalid key '%s'" %str
(index
))
171 def __setitem__(self
,index
, value
):
172 if index
=='tenant_id':
173 self
.tenant_id
= value
174 if index
=='tenant_name':
175 self
.tenant_name
= value
182 elif index
=='passwd':
186 elif index
=='url_admin':
187 self
.url_admin
= value
189 raise KeyError("Invalid key '%s'" %str
(index
))
193 service_type
= 'standalone'
196 self
.logger
.debug("Logging in to a VCA '%s'", self
.name
)
198 vca
= VCA(host
=self
.url
, username
=self
.user
, service_type
=service_type
, version
=version
, verify
=False, log
=True)
199 result
= vca
.login(password
=self
.passwd
, org
=self
.name
)
201 raise KeyError("Can't connect to a vCloud director.")
202 result
= vca
.login(token
=vca
.token
, org
=self
.name
, org_url
=vca
.vcloud_session
.org_url
)
204 self
.logger
.debug("Successfully logged to a VCA '%s'", self
.name
)
206 # vca = VCA(host='172.16.254.206', username=self.user, service_type='standalone', version='5.6', verify=False, log=True)
207 # vca.login(password=self.passwd, org=self.name)
208 # vca.login(token=vca.token, org=self.name, org_url=vca.vcloud_session.org_url)
211 # result = vca.login(token=vca.token, org=self.name, org_url=vca.vcloud_session.org_url)
213 # raise KeyError("Can't connect to a vcloud director")
215 # print "Logged to VCA via existing token"
217 # print "Logged to VCA"
222 def new_tenant(self
,tenant_name
,tenant_description
):
223 '''Adds a new tenant to VIM with this name and description,
224 returns the tenant identifier'''
225 raise vimconnNotImplemented( "Should have implemented this" )
227 def delete_tenant(self
,tenant_id
,):
228 '''Delete a tenant from VIM'''
229 '''Returns the tenant identifier'''
230 raise vimconnNotImplemented( "Should have implemented this" )
232 def get_tenant_list(self
, filter_dict
={}):
233 '''Obtain tenants of VIM
234 filter_dict can contain the following keys:
235 name: filter by tenant name
236 id: filter by tenant uuid/id
238 Returns the tenant list of dictionaries:
239 [{'name':'<name>, 'id':'<id>, ...}, ...]
241 raise vimconnNotImplemented( "Should have implemented this" )
243 def new_network(self
,net_name
, net_type
, ip_profile
=None, shared
=False):
244 '''Adds a tenant network to VIM
246 net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
247 ip_profile is a dict containing the IP parameters of the network
249 Returns the network identifier'''
251 self
.logger
.debug("Vmware tenant from VIM filter: '%s'", net_name
)
252 self
.logger
.debug("Vmware tenant from VIM filter: '%s'", net_type
)
253 self
.logger
.debug("Vmware tenant from VIM filter: '%s'", ip_profile
)
254 self
.logger
.debug("Vmware tenant from VIM filter: '%s'", shared
)
256 raise vimconnNotImplemented( "Should have implemented this" )
258 def get_network_list(self
, filter_dict
={}):
259 '''Obtain tenant networks of VIM
265 admin_state_up: boolean
267 Returns the network list of dictionaries:
268 [{<the fields at Filter_dict plus some VIM specific>}, ...]
274 raise vimconn
.vimconnConnectionException("self.connect() is failed")
276 vdc
= vca
.get_vdc(self
.tenant_name
)
277 vdcid
= vdc
.get_id().split(":")
279 networks
= vca
.get_networks(vdc
.get_name())
281 for network
in networks
:
283 netid
= network
.get_id().split(":")
284 self
.logger
.debug ("Adding {} to a list".format(netid
[3]))
285 self
.logger
.debug ("VDC ID {} to a list".format(vdcid
[3]))
286 self
.logger
.debug ("Network {} to a list".format(network
.get_name()))
288 filter_dict
["name"] = network
.get_name()
289 filter_dict
["id"] = netid
[3]
290 filter_dict
["shared"] = network
.get_IsShared()
291 filter_dict
["tenant_id"] = vdcid
[3]
292 if network
.get_status() == 1:
293 filter_dict
["admin_state_up"] = True
295 filter_dict
["admin_state_up"] = False
296 filter_dict
["status"] = "ACTIVE"
297 filter_dict
["type"] = "bridge"
298 network_list
.append(filter_dict
)
300 self
.logger
.debug("Returning {}".format(network_list
))
303 def get_network(self
, net_id
):
304 '''Obtain network details of net_id VIM network'
305 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]'''
306 raise vimconnNotImplemented( "Should have implemented this" )
308 def delete_network(self
, net_id
):
309 '''Deletes a tenant network from VIM, provide the network id.
310 Returns the network identifier or raise an exception'''
311 raise vimconnNotImplemented( "Should have implemented this" )
313 def refresh_nets_status(self
, net_list
):
314 '''Get the status of the networks
315 Params: the list of network identifiers
316 Returns a dictionary with:
317 net_id: #VIM id of this network
318 status: #Mandatory. Text with one of:
319 # DELETED (not found at vim)
320 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
321 # OTHER (Vim reported other status not understood)
322 # ERROR (VIM indicates an ERROR status)
323 # ACTIVE, INACTIVE, DOWN (admin down),
324 # BUILD (on building process)
326 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
327 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
330 raise vimconnNotImplemented( "Should have implemented this" )
332 def get_flavor(self
, flavor_id
):
333 '''Obtain flavor details from the VIM
334 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
337 print " get_flavor contains {}".format(flavor_id
)
341 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
343 def new_flavor(self
, flavor_data
):
344 '''Adds a tenant flavor to VIM
345 flavor_data contains a dictionary with information, keys:
347 ram: memory (cloud type) in MBytes
348 vpcus: cpus (cloud type)
349 extended: EPA parameters
350 - numas: #items requested in same NUMA
351 memory: number of 1G huge pages memory
352 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
353 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
354 - name: interface name
355 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
356 bandwidth: X Gbps; requested guarantee bandwidth
357 vpci: requested virtual PCI address
364 Returns the flavor identifier'''
366 flavor_uuid
= uuid
.uuid4()
367 flavorlist
[flavor_uuid
] = flavor_data
369 print " new_flavor contains {}".format(flavor_data
)
370 print " flavor list contains {}".format(flavorlist
)
374 def delete_flavor(self
, flavor_id
):
375 '''Deletes a tenant flavor from VIM identify by its id
376 Returns the used id or raise an exception'''
377 raise vimconnNotImplemented( "Should have implemented this" )
379 def new_image(self
,image_dict
):
381 Adds a tenant image to VIM
383 200, image-id if the image is created
384 <0, message if there is an error
387 print " ################################################################### "
388 print " new_image contains {}".format(image_dict
)
389 print " ################################################################### "
392 def delete_image(self
, image_id
):
393 '''Deletes a tenant image from VIM'''
394 '''Returns the HTTP response code and a message indicating details of the success or fail'''
396 print " ################################################################### "
397 print " delete_image contains {}".format(image_id
)
398 print " ################################################################### "
400 raise vimconnNotImplemented( "Should have implemented this" )
402 def catalog_exists(self
, catalog_name
, catalogs
):
403 for catalog
in catalogs
:
404 if catalog
.name
== catalog_name
:
408 def create_vimcatalog(self
, vca
, catalog_name
):
409 """Create Catalog entry in VIM"""
410 task
= vca
.create_catalog(catalog_name
, catalog_name
)
411 result
= vca
.block_until_completed(task
)
414 catalogs
= vca
.get_catalogs()
415 return self
.catalog_exists(catalog_name
, catalogs
)
418 def upload_ovf(self
, vca
, catalog_name
, item_name
, media_file_name
, description
='', display_progress
=False,
419 chunk_bytes
=128 * 1024):
421 Uploads a OVF file to a vCloud catalog
423 :param catalog_name: (str): The name of the catalog to upload the media.
424 :param item_name: (str): The name of the media file in the catalog.
425 :param media_file_name: (str): The name of the local media file to upload.
426 :return: (bool) True if the media file was successfully uploaded, false otherwise.
428 os
.path
.isfile(media_file_name
)
429 statinfo
= os
.stat(media_file_name
)
432 # find a catalog entry where we upload OVF.
433 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
435 # if VCD can parse OVF we upload VMDK file
436 for catalog
in vca
.get_catalogs():
437 if catalog_name
!= catalog
.name
:
439 link
= filter(lambda link
: link
.get_type() == "application/vnd.vmware.vcloud.media+xml" and
440 link
.get_rel() == 'add', catalog
.get_Link())
441 assert len(link
) == 1
443 <UploadVAppTemplateParams name="%s Template" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
444 """ % (escape(item_name
), escape(description
))
445 headers
= vca
.vcloud_session
.get_vcloud_headers()
446 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
447 response
= Http
.post(link
[0].get_href(), headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=self
.logger
)
448 if response
.status_code
== requests
.codes
.created
:
449 catalogItem
= ET
.fromstring(response
.content
)
450 entity
= [child
for child
in catalogItem
if
451 child
.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
452 href
= entity
.get('href')
454 response
= Http
.get(href
, headers
=vca
.vcloud_session
.get_vcloud_headers(),
455 verify
=vca
.verify
, logger
=self
.logger
)
457 if response
.status_code
== requests
.codes
.ok
:
458 media
= mediaType
.parseString(response
.content
, True)
459 link
= filter(lambda link
: link
.get_rel() == 'upload:default', media
.get_Files().get_File()[0].get_Link())[0]
460 headers
= vca
.vcloud_session
.get_vcloud_headers()
461 headers
['Content-Type'] = 'Content-Type text/xml'
462 response
= Http
.put(link
.get_href(), data
=open(media_file_name
, 'rb'), headers
=headers
, verify
=vca
.verify
,logger
=self
.logger
)
463 if response
.status_code
!= requests
.codes
.ok
:
464 self
.logger
.debug("Failed create vApp template for catalog name {} and image {}".format(catalog_name
, media_file_name
))
469 self
.logger
.debug("Failed create vApp template for catalog name {} and image {}".
470 format(catalog_name
, media_file_name
))
472 # uploading VMDK file
473 # check status of OVF upload
474 response
= Http
.get(template
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
, logger
=self
.logger
)
475 if response
.status_code
== requests
.codes
.ok
:
476 media
= mediaType
.parseString(response
.content
, True)
477 link
= filter(lambda link
: link
.get_rel() == 'upload:default', media
.get_Files().get_File()[0].get_Link())[0]
479 # The OVF file and VMDK must be in a same directory
480 head
, tail
= os
.path
.split(media_file_name
)
481 filevmdk
= head
+ '/' + os
.path
.basename(link
.get_href())
483 os
.path
.isfile(filevmdk
)
484 statinfo
= os
.stat(filevmdk
)
486 # TODO debug output remove it
487 #print media.get_Files().get_File()[0].get_Link()[0].get_href()
488 #print media.get_Files().get_File()[1].get_Link()[0].get_href()
489 #print link.get_href()
491 # in case first element is pointer to OVF.
492 hrefvmdk
= link
.get_href().replace("descriptor.ovf","Cirros-disk1.vmdk")
494 f
= open(filevmdk
, 'rb')
495 bytes_transferred
= 0
496 while bytes_transferred
< statinfo
.st_size
:
497 my_bytes
= f
.read(chunk_bytes
)
498 if len(my_bytes
) <= chunk_bytes
:
499 headers
= vca
.vcloud_session
.get_vcloud_headers()
500 headers
['Content-Range'] = 'bytes %s-%s/%s' % (bytes_transferred
, len(my_bytes
) - 1, statinfo
.st_size
)
501 headers
['Content-Length'] = str(len(my_bytes
))
502 response
= Http
.put(hrefvmdk
, headers
=headers
, data
=my_bytes
, verify
=vca
.verify
,logger
=None)
503 if response
.status_code
== requests
.codes
.ok
:
504 bytes_transferred
+= len(my_bytes
)
505 self
.logger
.debug('transferred %s of %s bytes' % (str(bytes_transferred
),
506 str(statinfo
.st_size
)))
508 self
.logger
.debug('file upload failed with error: [%s] %s' % (response
.status_code
,
514 self
.logger
.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
515 format(catalog_name
, media_file_name
))
518 self
.logger
.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name
, media_file_name
))
521 def upload_vimimage(self
,vca
, catalog_name
, media_name
, medial_file_name
):
522 """Upload media file"""
523 return self
.upload_ovf(vca
, catalog_name
, media_name
.split(".")[0], medial_file_name
, medial_file_name
, True)
525 def get_catalogid(self
, catalog_name
, catalogs
):
526 for catalog
in catalogs
:
527 if catalog
.name
== catalog_name
:
529 catalog_id
= catalog
.get_id().split(":")
533 def get_catalogbyid(self
, catalog_id
, catalogs
):
534 for catalog
in catalogs
:
535 catalogid
= catalog
.get_id().split(":")[3]
536 if catalogid
== catalog_id
:
540 def get_image_id_from_path(self
, path
):
541 '''Get the image id from image path in the VIM database'''
543 0,"Image not found" if there are no images with that path
544 1,image-id if there is one image with that path
545 <0,message if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.)
550 raise vimconn
.vimconnConnectionException("self.connect() is failed")
552 self
.logger
.debug("get_image_id_from_path path {}".format(path
))
554 dirpath
, filename
= os
.path
.split(path
)
555 flname
, file_extension
= os
.path
.splitext(path
)
556 if file_extension
!= '.ovf':
557 self
.logger
.debug("Wrong file extension {}".format(file_extension
))
558 return -1, "Wrong container. vCloud director supports only OVF."
559 catalog_name
= os
.path
.splitext(filename
)[0]
561 self
.logger
.debug("File name {} Catalog Name {} file path {}".format(filename
, catalog_name
, path
))
562 self
.logger
.debug("Catalog name {}".format(catalog_name
))
564 catalogs
= vca
.get_catalogs()
565 if len(catalogs
) == 0:
566 self
.logger
.info("Creating new catalog entry {} in vcloud director".format(catalog_name
))
567 result
= self
.create_vimcatalog(vca
, catalog_name
)
569 return -1, "Failed create new catalog {} ".format(catalog_name
)
570 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
572 return -1, "Failed create vApp template for catalog {} ".format(catalog_name
)
573 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
575 for catalog
in catalogs
:
576 # search for existing catalog if we find same name we return ID
578 if catalog
.name
== catalog_name
:
579 self
.logger
.debug("Found existing catalog entry for {} catalog id {}".format(catalog_name
, self
.get_catalogid(catalog_name
, catalogs
)))
580 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
582 # if we didn't find existing catalog we create a new one.
583 self
.logger
.debug("Creating new catalog entry".format(catalog_name
))
584 result
= self
.create_vimcatalog(vca
, catalog_name
)
586 return -1, "Failed create new catalog {} ".format(catalog_name
)
587 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
589 return -1, "Failed create vApp template for catalog {} ".format(catalog_name
)
591 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
593 def get_vappid(self
, vdc
, vapp_name
):
594 """ Take vdc object and vApp name and returns vapp uuid or None
596 #UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
599 refs
= filter(lambda ref
: ref
.name
== vapp_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
600 vdc
.ResourceEntities
.ResourceEntity
)
603 return refs
[0].href
.split("vapp")[1][1:]
608 def get_vappbyid(self
, vdc
, vapp_id
):
609 refs
= filter(lambda ref
: ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
610 vdc
.ResourceEntities
.ResourceEntity
)
615 return refs
[0].href
.split("vapp")[1][1:]
617 def new_vminstance(self
,name
,description
,start
,image_id
,flavor_id
,net_list
,cloud_config
=None):
618 """Adds a VM instance to VIM
620 start: indicates if VM must start or boot in pause mode. Ignored
621 image_id,flavor_id: image and flavor uuid
622 net_list: list of interfaces, each one is a dictionary with:
624 net_id: network uuid to connect
625 vpci: virtual vcpi to assign
626 model: interface model, virtio, e2000, ...
628 use: 'data', 'bridge', 'mgmt'
629 type: 'virtual', 'PF', 'VF', 'VFnotShared'
630 vim_id: filled/added by this function
631 cloud_config: can be a text script to be passed directly to cloud-init,
632 or an object to inject users and ssh keys with format:
633 key-pairs: [] list of keys to install to the default user
634 users: [{ name, key-pairs: []}] list of users to add with their key-pair
635 #TODO ip, security groups
636 Returns >=0, the instance identifier
640 self
.logger
.info("Creating new instance for entry".format(name
))
641 self
.logger
.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
642 format(description
, start
, image_id
, flavor_id
, net_list
, cloud_config
))
645 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
647 # TODO following attribute need be featched from flavor / OVF file must contain same data.
648 # task = self.vca.create_vapp(vdc_name, vapp_name, template, catalog,
654 catalogs
= vca
.get_catalogs()
655 #image upload creates template name as catalog name space Template.
656 templateName
= self
.get_catalogbyid(image_id
, catalogs
) + ' Template'
657 task
= vca
.create_vapp(self
.tenant_name
, name
, templateName
, self
.get_catalogbyid(image_id
,catalogs
), vm_name
=name
)
659 return -1, " Failed deploy vApp {}".format(name
)
661 result
= vca
.block_until_completed(task
)
663 vappID
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
665 return -1, " Failed featch UUID for vApp {}".format(name
)
669 return -1, " Failed create vApp {}".format(name
)
671 def get_vminstance(self
,vm_id
):
672 '''Returns the VM instance information from VIM'''
676 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
679 raise vimconnNotImplemented( "Should have implemented this" )
681 def delete_vminstance(self
, vm_id
):
682 '''Removes a VM instance from VIM'''
683 '''Returns the instance identifier'''
685 print " ###### {} ".format(vm_id
)
689 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
691 thevdc
= vca
.get_vdc(self
.tenant_name
)
692 self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
697 def refresh_vms_status(self
, vm_list
):
698 '''Get the status of the virtual machines and their interfaces/ports
699 Params: the list of VM identifiers
700 Returns a dictionary with:
701 vm_id: #VIM id of this Virtual Machine
702 status: #Mandatory. Text with one of:
703 # DELETED (not found at vim)
704 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
705 # OTHER (Vim reported other status not understood)
706 # ERROR (VIM indicates an ERROR status)
707 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
708 # CREATING (on building process), ERROR
709 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
711 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
712 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
714 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
715 mac_address: #Text format XX:XX:XX:XX:XX:XX
716 vim_net_id: #network id where this interface is connected
717 vim_interface_id: #interface/port VIM id
718 ip_address: #null, or text with IPv4, IPv6 address
720 raise vimconnNotImplemented( "Should have implemented this" )
722 def action_vminstance(self
, vm_id
, action_dict
):
723 '''Send and action over a VM instance from VIM
724 Returns the vm_id if the action was successfully sent to the VIM'''
725 raise vimconnNotImplemented( "Should have implemented this" )
727 def get_vminstance_console(self
,vm_id
, console_type
="vnc"):
729 Get a console for the virtual machine
731 vm_id: uuid of the VM
732 console_type, can be:
733 "novnc" (by default), "xvpvnc" for VNC types,
734 "rdp-html5" for RDP types, "spice-html5" for SPICE types
735 Returns dict with the console parameters:
736 protocol: ssh, ftp, http, https, ...
737 server: usually ip address
738 port: the http, ssh, ... port
739 suffix: extra text, e.g. the http path and query string
741 raise vimconnNotImplemented( "Should have implemented this" )
743 #NOT USED METHODS in current version
745 def host_vim2gui(self
, host
, server_dict
):
746 '''Transform host dictionary from VIM format to GUI format,
747 and append to the server_dict
749 raise vimconnNotImplemented( "Should have implemented this" )
751 def get_hosts_info(self
):
752 '''Get the information of deployed hosts
753 Returns the hosts content'''
754 raise vimconnNotImplemented( "Should have implemented this" )
756 def get_hosts(self
, vim_tenant
):
757 '''Get the hosts and deployed instances
758 Returns the hosts content'''
759 raise vimconnNotImplemented( "Should have implemented this" )
761 def get_processor_rankings(self
):
762 '''Get the processor rankings in the VIM database'''
763 raise vimconnNotImplemented( "Should have implemented this" )
765 def new_host(self
, host_data
):
766 '''Adds a new host to VIM'''
767 '''Returns status code of the VIM response'''
768 raise vimconnNotImplemented( "Should have implemented this" )
770 def new_external_port(self
, port_data
):
771 '''Adds a external port to VIM'''
772 '''Returns the port identifier'''
773 raise vimconnNotImplemented( "Should have implemented this" )
775 def new_external_network(self
,net_name
,net_type
):
776 '''Adds a external network to VIM (shared)'''
777 '''Returns the network identifier'''
778 raise vimconnNotImplemented( "Should have implemented this" )
780 def connect_port_network(self
, port_id
, network_id
, admin
=False):
781 '''Connects a external port to a network'''
782 '''Returns status code of the VIM response'''
783 raise vimconnNotImplemented( "Should have implemented this" )
785 def new_vminstancefromJSON(self
, vm_data
):
786 '''Adds a VM instance to VIM'''
787 '''Returns the instance identifier'''
788 raise vimconnNotImplemented( "Should have implemented this" )