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.
34 from xml
.etree
import ElementTree
as XmlElementTree
37 from pyvcloud
import Http
38 from pyvcloud
.vcloudair
import VCA
39 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
import sessionType
, organizationType
, \
40 vAppType
, organizationListType
, vdcType
, catalogType
, queryRecordViewType
, \
41 networkType
, vcloudType
, taskType
, diskType
, vmsType
, vdcTemplateListType
, mediaType
42 from xml
.sax
.saxutils
import escape
44 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.admin
.vCloudEntities
import TaskType
45 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
.taskType
import TaskType
as GenericTask
46 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
.vAppType
import TaskType
as VappTask
47 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.admin
.vCloudEntities
import TasksInProgressType
56 DELETE_INSTANCE_RETRY
= 3
58 __author__
= "Mustafa Bayramov"
59 __date__
= "$26-Aug-2016 11:09:29$"
62 HTTP_Bad_Request
= 400
63 HTTP_Unauthorized
= 401
65 HTTP_Method_Not_Allowed
= 405
66 HTTP_Request_Timeout
= 408
68 HTTP_Not_Implemented
= 501
69 HTTP_Service_Unavailable
= 503
70 HTTP_Internal_Server_Error
= 500
72 # -1: "Could not be created",
78 # 5: "Waiting for user input",
80 # 7: "Unrecognized state",
82 # 9: "Inconsistent state",
83 # 10: "Children do not all have the same status",
84 # 11: "Upload initiated, OVF descriptor pending",
85 # 12: "Upload initiated, copying contents",
86 # 13: "Upload initiated , disk contents pending",
87 # 14: "Upload has been quarantined",
88 # 15: "Upload quarantine period has expired"
90 # mapping vCD status to MANO
91 vcdStatusCode2manoFormat
= {4: 'ACTIVE',
100 netStatus2manoFormat
= {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
101 'ERROR': 'ERROR', 'DELETED': 'DELETED'
105 class vimconnException(Exception):
106 '''Common and base class Exception for all vimconnector exceptions'''
108 def __init__(self
, message
, http_code
=HTTP_Bad_Request
):
109 Exception.__init
__(self
, message
)
110 self
.http_code
= http_code
113 class vimconnConnectionException(vimconnException
):
114 '''Connectivity error with the VIM'''
116 def __init__(self
, message
, http_code
=HTTP_Service_Unavailable
):
117 vimconnException
.__init
__(self
, message
, http_code
)
120 class vimconnUnexpectedResponse(vimconnException
):
121 '''Get an wrong response from VIM'''
123 def __init__(self
, message
, http_code
=HTTP_Service_Unavailable
):
124 vimconnException
.__init
__(self
, message
, http_code
)
127 class vimconnAuthException(vimconnException
):
128 '''Invalid credentials or authorization to perform this action over the VIM'''
130 def __init__(self
, message
, http_code
=HTTP_Unauthorized
):
131 vimconnException
.__init
__(self
, message
, http_code
)
134 class vimconnNotFoundException(vimconnException
):
135 '''The item is not found at VIM'''
137 def __init__(self
, message
, http_code
=HTTP_Not_Found
):
138 vimconnException
.__init
__(self
, message
, http_code
)
141 class vimconnConflictException(vimconnException
):
142 '''There is a conflict, e.g. more item found than one'''
144 def __init__(self
, message
, http_code
=HTTP_Conflict
):
145 vimconnException
.__init
__(self
, message
, http_code
)
148 class vimconnNotImplemented(vimconnException
):
149 '''The method is not implemented by the connected'''
151 def __init__(self
, message
, http_code
=HTTP_Not_Implemented
):
152 vimconnException
.__init
__(self
, message
, http_code
)
158 class vimconnector():
159 '''Vmware VIM Connector base class
162 def __init__(self
, uuid
, name
, tenant_id
, tenant_name
, url
, url_admin
=None, user
=None, passwd
=None,
163 log_level
="ERROR", config
={}):
170 self
.url_admin
= url_admin
171 self
.tenant_id
= tenant_id
172 self
.tenant_name
= tenant_name
176 self
.admin_password
= None
177 self
.admin_user
= None
179 self
.logger
= logging
.getLogger('openmano.vim.vmware')
182 self
.admin_user
= config
['admin_username']
183 self
.admin_password
= config
['admin_password']
185 raise vimconnException(message
="Error admin username or admin password is empty.")
187 self
.logger
= logging
.getLogger('mano.vim.vmware')
192 raise TypeError, 'url param can not be NoneType'
194 if not self
.url_admin
: # try to use normal url
195 self
.url_admin
= self
.url
197 self
.vcaversion
= '5.6'
199 logging
.debug("Calling constructor with following paramters")
200 logging
.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self
.id, self
.name
,
201 self
.tenant_id
, self
.tenant_name
))
202 logging
.debug("vcd url {} vcd username: {} vcd password: {}".format(self
.url
, self
.user
, self
.passwd
))
203 logging
.debug("vcd admin username {} vcd admin passowrd {}".format(self
.admin_user
, self
.admin_password
))
205 # initialize organization
206 if self
.user
is not None and self
.passwd
is not None:
209 def __getitem__(self
, index
):
210 if index
== 'tenant_id':
211 return self
.tenant_id
212 if index
== 'tenant_name':
213 return self
.tenant_name
216 elif index
== 'name':
218 elif index
== 'org_name':
220 elif index
== 'org_uuid':
222 elif index
== 'user':
224 elif index
== 'passwd':
228 elif index
== 'url_admin':
229 return self
.url_admin
230 elif index
== "config":
233 raise KeyError("Invalid key '%s'" % str(index
))
235 def __setitem__(self
, index
, value
):
236 if index
== 'tenant_id':
237 self
.tenant_id
= value
238 if index
== 'tenant_name':
239 self
.tenant_name
= value
242 # we use name = org #TODO later refactor
243 elif index
== 'name':
246 elif index
== 'org_name':
247 self
.org_name
= value
249 elif index
== 'org_uuid':
250 self
.org_name
= value
251 elif index
== 'user':
253 elif index
== 'passwd':
257 elif index
== 'url_admin':
258 self
.url_admin
= value
260 raise KeyError("Invalid key '%s'" % str(index
))
262 def connect_as_admin(self
):
263 """ Method connect as admin user to vCloud director.
266 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
269 self
.logger
.debug("Logging in to a vca {} as admin.".format(self
.name
))
271 service_type
= 'standalone'
273 vca_admin
= VCA(host
=self
.url
,
274 username
=self
.admin_user
,
275 service_type
=service_type
,
279 result
= vca_admin
.login(password
=self
.admin_password
, org
='System')
281 raise vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self
.admin_user
))
282 result
= vca_admin
.login(token
=vca_admin
.token
, org
='System', org_url
=vca_admin
.vcloud_session
.org_url
)
285 "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self
.admin_user
))
290 """ Method connect as normal user to vCloud director.
293 The return vca object that letter can be used to connect to vCloud director as admin for VDC
296 service_type
= 'standalone'
299 self
.logger
.debug("Logging in to a vca {} as {} to datacenter {}.".format(self
.name
, self
.user
, self
.name
))
300 vca
= VCA(host
=self
.url
,
302 service_type
=service_type
,
306 result
= vca
.login(password
=self
.passwd
, org
=self
.name
)
308 raise vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self
.user
))
309 result
= vca
.login(token
=vca
.token
, org
=self
.name
, org_url
=vca
.vcloud_session
.org_url
)
311 self
.logger
.info("Successfully logged to a vcloud direct org: {} as user: {}".format(self
.name
, self
.user
))
315 def init_org_uuid(self
):
316 """ Method available organization for a logged in tenant
319 The return vca object that letter can be used to connect to vcloud direct as admin
322 if self
.org_uuid
is None:
323 org_dict
= self
.get_org_list()
325 if org_dict
[org
] == self
.org_name
:
327 self
.logger
.debug("Setting organization uuid {}".format(self
.org_uuid
))
329 self
.logger
.debug("Failed initialize organization UUID for org {}".format(self
.org_name
))
330 self
.logger
.debug(traceback
.format_exc())
333 def new_tenant(self
, tenant_name
=None, tenant_description
=None):
335 Adds a new tenant to VIM with this name and description
338 :param tenant_description:
339 :return: returns the tenant identifier
341 vdc_task
= self
.create_vdc(vdc_name
=tenant_name
)
342 if vdc_task
is not None:
343 vdc_uuid
, value
= vdc_task
.popitem()
344 self
.logger
.info("Crated new vdc {} and uuid: {}".format(tenant_name
, vdc_uuid
))
347 raise vimconnException("Failed create tenant {}".format(tenant_name
))
349 def delete_tenant(self
, tenant_id
, ):
350 """Delete a tenant from VIM"""
351 'Returns the tenant identifier'
354 print(" ######## delete_tenant {} ".format(tenant_id
))
357 raise vimconnNotImplemented("Should have implemented this")
359 def get_tenant_list(self
, filter_dict
={}):
360 '''Obtain tenants of VIM
361 filter_dict can contain the following keys:
362 name: filter by tenant name
363 id: filter by tenant uuid/id
365 Returns the tenant list of dictionaries:
366 [{'name':'<name>, 'id':'<id>, ...}, ...]
370 org_dict
= self
.get_org(self
.org_uuid
)
371 vdcs_dict
= org_dict
['vdcs']
376 entry
= {'name': vdcs_dict
[k
], 'id': k
}
377 filtered_entry
= entry
.copy()
378 filtered_dict
= set(entry
.keys()) - set(filter_dict
)
379 for unwanted_key
in filtered_dict
: del entry
[unwanted_key
]
380 if filter_dict
== entry
:
381 vdclist
.append(filtered_entry
)
383 self
.logger
.debug("Error in get_tenant_list()")
384 self
.logger
.debug(traceback
.format_exc())
389 def new_network(self
, net_name
, net_type
, ip_profile
=None, shared
=False):
390 '''Adds a tenant network to VIM
392 net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
393 ip_profile is a dict containing the IP parameters of the network
395 Returns the network identifier'''
398 "new_network tenant {} net_type {} ip_profile {} shared {}".format(net_name
, net_type
, ip_profile
, shared
))
404 network_uuid
= self
.create_network(network_name
=net_name
, isshared
=isshared
)
405 if network_uuid
is not None:
408 raise vimconnUnexpectedResponse("Failed create a new network {}".format(net_name
))
410 def get_vcd_network_list(self
):
411 """ Method available organization for a logged in tenant
414 The return vca object that letter can be used to connect to vcloud direct as admin
417 self
.logger
.debug("get_vcd_network_list(): retrieving network list for vcd")
420 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
422 vdc
= vca
.get_vdc(self
.tenant_name
)
423 vdc_uuid
= vdc
.get_id().split(":")[3]
424 networks
= vca
.get_networks(vdc
.get_name())
427 for network
in networks
:
429 netid
= network
.get_id().split(":")
433 filter_dict
["name"] = network
.get_name()
434 filter_dict
["id"] = netid
[3]
435 filter_dict
["shared"] = network
.get_IsShared()
436 filter_dict
["tenant_id"] = vdc_uuid
437 if network
.get_status() == 1:
438 filter_dict
["admin_state_up"] = True
440 filter_dict
["admin_state_up"] = False
441 filter_dict
["status"] = "ACTIVE"
442 filter_dict
["type"] = "bridge"
443 network_list
.append(filter_dict
)
444 self
.logger
.debug("get_vcd_network_list adding entry {}".format(filter_dict
))
446 self
.logger
.debug("Error in get_vcd_network_list")
447 self
.logger
.debug(traceback
.format_exc())
450 self
.logger
.debug("get_vcd_network_list returning {}".format(network_list
))
453 def get_network_list(self
, filter_dict
={}):
454 '''Obtain tenant networks of VIM
456 name: network name OR/AND
457 id: network uuid OR/AND
458 shared: boolean OR/AND
459 tenant_id: tenant OR/AND
460 admin_state_up: boolean
463 [{key : value , key : value}]
465 Returns the network list of dictionaries:
466 [{<the fields at Filter_dict plus some VIM specific>}, ...]
472 raise vimconn
.vimconnConnectionException("self.connect() is failed")
474 vdc
= vca
.get_vdc(self
.tenant_name
)
475 vdcid
= vdc
.get_id().split(":")[3]
477 networks
= vca
.get_networks(vdc
.get_name())
481 for network
in networks
:
483 net_uuid
= network
.get_id().split(":")
484 if len(net_uuid
) != 4:
487 net_uuid
= net_uuid
[3]
489 self
.logger
.debug("Adding {} to a list vcd id {} network {}".format(net_uuid
,
492 filter_entry
["name"] = network
.get_name()
493 filter_entry
["id"] = net_uuid
494 filter_entry
["shared"] = network
.get_IsShared()
495 filter_entry
["tenant_id"] = vdcid
496 if network
.get_status() == 1:
497 filter_entry
["admin_state_up"] = True
499 filter_entry
["admin_state_up"] = False
500 filter_entry
["status"] = "ACTIVE"
501 filter_entry
["type"] = "bridge"
502 filtered_entry
= filter_entry
.copy()
504 # we remove all the key : value we dont' care and match only
506 filtered_dict
= set(filter_entry
.keys()) - set(filter_dict
)
507 for unwanted_key
in filtered_dict
: del filter_entry
[unwanted_key
]
508 if filter_dict
== filter_entry
:
509 network_list
.append(filtered_entry
)
511 self
.logger
.debug("Error in get_vcd_network_list")
512 self
.logger
.debug(traceback
.format_exc())
514 self
.logger
.debug("Returning {}".format(network_list
))
517 def get_network(self
, net_id
):
518 """Method bbtain network details of net_id VIM network
519 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
523 raise vimconn
.vimconnConnectionException("self.connect() is failed")
525 vdc
= vca
.get_vdc(self
.tenant_name
)
526 vdc_id
= vdc
.get_id().split(":")[3]
528 networks
= vca
.get_networks(vdc
.get_name())
532 for network
in networks
:
533 vdc_network_id
= network
.get_id().split(":")
534 if len(vdc_network_id
) == 4 and vdc_network_id
[3] == net_id
:
535 filter_dict
["name"] = network
.get_name()
536 filter_dict
["id"] = vdc_network_id
[3]
537 filter_dict
["shared"] = network
.get_IsShared()
538 filter_dict
["tenant_id"] = vdc_id
539 if network
.get_status() == 1:
540 filter_dict
["admin_state_up"] = True
542 filter_dict
["admin_state_up"] = False
543 filter_dict
["status"] = "ACTIVE"
544 filter_dict
["type"] = "bridge"
545 self
.logger
.debug("Returning {}".format(filter_dict
))
548 self
.logger
.debug("Error in get_network")
549 self
.logger
.debug(traceback
.format_exc())
553 def delete_network(self
, net_id
):
555 Method Deletes a tenant network from VIM, provide the network id.
557 Returns the network identifier or raise an exception
562 raise vimconn
.vimconnConnectionException("self.connect() for tenant {} is failed".format(self
.tenant_name
))
564 if self
.delete_network_action(net_id
):
567 raise vimconn
.vimconnNotFoundException("Network {} not found".format(net_id
))
569 def refresh_nets_status(self
, net_list
):
570 '''Get the status of the networks
571 Params: the list of network identifiers
572 Returns a dictionary with:
573 net_id: #VIM id of this network
574 status: #Mandatory. Text with one of:
575 # DELETED (not found at vim)
576 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
577 # OTHER (Vim reported other status not understood)
578 # ERROR (VIM indicates an ERROR status)
579 # ACTIVE, INACTIVE, DOWN (admin down),
580 # BUILD (on building process)
582 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
583 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
587 # for net in net_list:
592 # vim vimcon failed == ERROR
595 raise vimconn
.vimconnConnectionException("self.connect() is failed")
602 vcd_network
= self
.get_vcd_network(network_uuid
=net
)
603 if vcd_network
is not None:
604 if vcd_network
['status'] == 1:
610 errormsg
= 'network not found'
611 dict_entry
['net'] = {'status': status
, 'error_msg': errormsg
,
612 'vm_info': yaml
.safe_dump(vcd_network
)}
614 self
.logger
.debug("Error in refresh_nets_status")
615 self
.logger
.debug(traceback
.format_exc())
619 def get_flavor(flavor_id
):
620 """Obtain flavor details from the VIM
621 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
623 return flavorlist
[flavor_id
]
625 def new_flavor(self
, flavor_data
):
626 """Adds a tenant flavor to VIM
627 flavor_data contains a dictionary with information, keys:
629 ram: memory (cloud type) in MBytes
630 vpcus: cpus (cloud type)
631 extended: EPA parameters
632 - numas: #items requested in same NUMA
633 memory: number of 1G huge pages memory
634 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
635 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
636 - name: interface name
637 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
638 bandwidth: X Gbps; requested guarantee bandwidth
639 vpci: requested virtual PCI address
646 Returns the flavor identifier"""
648 # generate a new uuid put to internal dict and return it.
649 flavor_id
= uuid
.uuid4()
650 flavorlist
[str(flavor_id
)] = flavor_data
652 return str(flavor_id
)
654 def delete_flavor(self
, flavor_id
):
655 """Deletes a tenant flavor from VIM identify by its id
657 Returns the used id or raise an exception
660 # if key not present it will raise KeyError
661 # TODO check do I need raise any specific exception
662 flavorlist
.pop(flavor_id
, None)
665 def new_image(self
, image_dict
):
667 Adds a tenant image to VIM
669 200, image-id if the image is created
670 <0, message if there is an error
673 return self
.get_image_id_from_path(image_dict
['location'])
675 def delete_image(self
, image_id
):
676 '''Deletes a tenant image from VIM'''
677 '''Returns the HTTP response code and a message indicating details of the success or fail'''
679 print " ################################################################### "
680 print " delete_image contains {}".format(image_id
)
681 print " ################################################################### "
683 raise vimconnNotImplemented("Should have implemented this")
685 def catalog_exists(self
, catalog_name
, catalogs
):
686 for catalog
in catalogs
:
687 if catalog
.name
== catalog_name
:
691 def create_vimcatalog(self
, vca
, catalog_name
):
692 """Create Catalog entry in VIM"""
693 task
= vca
.create_catalog(catalog_name
, catalog_name
)
694 result
= vca
.block_until_completed(task
)
697 catalogs
= vca
.get_catalogs()
698 return self
.catalog_exists(catalog_name
, catalogs
)
700 def upload_ovf(self
, vca
, catalog_name
, item_name
, media_file_name
, description
='', display_progress
=False,
701 chunk_bytes
=128 * 1024):
703 Uploads a OVF file to a vCloud catalog
705 :param catalog_name: (str): The name of the catalog to upload the media.
706 :param item_name: (str): The name of the media file in the catalog.
707 :param media_file_name: (str): The name of the local media file to upload.
708 :return: (bool) True if the media file was successfully uploaded, false otherwise.
710 os
.path
.isfile(media_file_name
)
711 statinfo
= os
.stat(media_file_name
)
714 # find a catalog entry where we upload OVF.
715 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
717 # if VCD can parse OVF we upload VMDK file
718 for catalog
in vca
.get_catalogs():
719 if catalog_name
!= catalog
.name
:
721 link
= filter(lambda link
: link
.get_type() == "application/vnd.vmware.vcloud.media+xml" and
722 link
.get_rel() == 'add', catalog
.get_Link())
723 assert len(link
) == 1
725 <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>
726 """ % (escape(item_name
), escape(description
))
727 headers
= vca
.vcloud_session
.get_vcloud_headers()
728 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
729 response
= Http
.post(link
[0].get_href(), headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=self
.logger
)
730 if response
.status_code
== requests
.codes
.created
:
731 catalogItem
= XmlElementTree
.fromstring(response
.content
)
732 entity
= [child
for child
in catalogItem
if
733 child
.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
734 href
= entity
.get('href')
736 response
= Http
.get(href
, headers
=vca
.vcloud_session
.get_vcloud_headers(),
737 verify
=vca
.verify
, logger
=self
.logger
)
739 if response
.status_code
== requests
.codes
.ok
:
740 media
= mediaType
.parseString(response
.content
, True)
742 filter(lambda link
: link
.get_rel() == 'upload:default',
743 media
.get_Files().get_File()[0].get_Link())[
745 headers
= vca
.vcloud_session
.get_vcloud_headers()
746 headers
['Content-Type'] = 'Content-Type text/xml'
747 response
= Http
.put(link
.get_href(), data
=open(media_file_name
, 'rb'), headers
=headers
,
748 verify
=vca
.verify
, logger
=self
.logger
)
749 if response
.status_code
!= requests
.codes
.ok
:
751 "Failed create vApp template for catalog name {} and image {}".format(catalog_name
,
755 # TODO fix this with aync block
758 self
.logger
.debug("Failed create vApp template for catalog name {} and image {}".
759 format(catalog_name
, media_file_name
))
761 # uploading VMDK file
762 # check status of OVF upload
763 response
= Http
.get(template
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
,
765 if response
.status_code
== requests
.codes
.ok
:
766 media
= mediaType
.parseString(response
.content
, True)
768 filter(lambda link
: link
.get_rel() == 'upload:default',
769 media
.get_Files().get_File()[0].get_Link())[
772 # The OVF file and VMDK must be in a same directory
773 head
, tail
= os
.path
.split(media_file_name
)
774 filevmdk
= head
+ '/' + os
.path
.basename(link
.get_href())
776 os
.path
.isfile(filevmdk
)
777 statinfo
= os
.stat(filevmdk
)
779 # TODO debug output remove it
780 # print media.get_Files().get_File()[0].get_Link()[0].get_href()
781 # print media.get_Files().get_File()[1].get_Link()[0].get_href()
782 # print link.get_href()
784 # in case first element is pointer to OVF.
785 hrefvmdk
= link
.get_href().replace("descriptor.ovf", "Cirros-disk1.vmdk")
787 f
= open(filevmdk
, 'rb')
788 bytes_transferred
= 0
789 while bytes_transferred
< statinfo
.st_size
:
790 my_bytes
= f
.read(chunk_bytes
)
791 if len(my_bytes
) <= chunk_bytes
:
792 headers
= vca
.vcloud_session
.get_vcloud_headers()
793 headers
['Content-Range'] = 'bytes %s-%s/%s' % (
794 bytes_transferred
, len(my_bytes
) - 1, statinfo
.st_size
)
795 headers
['Content-Length'] = str(len(my_bytes
))
796 response
= Http
.put(hrefvmdk
,
801 if response
.status_code
== requests
.codes
.ok
:
802 bytes_transferred
+= len(my_bytes
)
803 self
.logger
.debug('transferred %s of %s bytes' % (str(bytes_transferred
),
804 str(statinfo
.st_size
)))
806 self
.logger
.debug('file upload failed with error: [%s] %s' % (response
.status_code
,
812 self
.logger
.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
813 format(catalog_name
, media_file_name
))
816 self
.logger
.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name
, media_file_name
))
819 def upload_vimimage(self
, vca
, catalog_name
, media_name
, medial_file_name
):
820 """Upload media file"""
821 # TODO add named parameters for readbility
822 return self
.upload_ovf(vca
, catalog_name
, media_name
.split(".")[0], medial_file_name
, medial_file_name
, True)
824 def get_catalogid(self
, catalog_name
, catalogs
):
825 for catalog
in catalogs
:
826 if catalog
.name
== catalog_name
:
827 catalog_id
= catalog
.get_id().split(":")
831 def get_catalogbyid(self
, catalog_id
, catalogs
):
832 for catalog
in catalogs
:
833 catalogid
= catalog
.get_id().split(":")[3]
834 if catalogid
== catalog_id
:
838 def get_image_id_from_path(self
, path
):
839 '''Get the image id from image path in the VIM database'''
841 0,"Image not found" if there are no images with that path
842 1,image-id if there is one image with that path
843 <0,message if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.)
848 raise vimconn
.vimconnConnectionException("self.connect() is failed")
850 self
.logger
.debug("get_image_id_from_path path {}".format(path
))
852 dirpath
, filename
= os
.path
.split(path
)
853 flname
, file_extension
= os
.path
.splitext(path
)
854 if file_extension
!= '.ovf':
855 self
.logger
.debug("Wrong file extension {}".format(file_extension
))
856 return -1, "Wrong container. vCloud director supports only OVF."
857 catalog_name
= os
.path
.splitext(filename
)[0]
859 self
.logger
.debug("File name {} Catalog Name {} file path {}".format(filename
, catalog_name
, path
))
860 self
.logger
.debug("Catalog name {}".format(catalog_name
))
862 catalogs
= vca
.get_catalogs()
863 if len(catalogs
) == 0:
864 self
.logger
.info("Creating new catalog entry {} in vcloud director".format(catalog_name
))
865 result
= self
.create_vimcatalog(vca
, catalog_name
)
867 return -1, "Failed create new catalog {} ".format(catalog_name
)
868 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
870 return -1, "Failed create vApp template for catalog {} ".format(catalog_name
)
871 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
873 for catalog
in catalogs
:
874 # search for existing catalog if we find same name we return ID
876 if catalog
.name
== catalog_name
:
877 self
.logger
.debug("Found existing catalog entry for {} catalog id {}".format(catalog_name
,
881 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
883 # if we didn't find existing catalog we create a new one.
884 self
.logger
.debug("Creating new catalog entry".format(catalog_name
))
885 result
= self
.create_vimcatalog(vca
, catalog_name
)
887 return -1, "Failed create new catalog {} ".format(catalog_name
)
888 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
890 return -1, "Failed create vApp template for catalog {} ".format(catalog_name
)
892 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
894 def get_vappid(self
, vdc
=None, vapp_name
=None):
895 """ Method takes vdc object and vApp name and returns vapp uuid or None
898 vca: Connector to VCA
900 vapp_name: is application vappp name identifier
903 The return vApp name otherwise None
906 """ Take vdc object and vApp name and returns vapp uuid or None
909 if vdc
is None or vapp_name
is None:
911 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
913 refs
= filter(lambda ref
: ref
.name
== vapp_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
914 vdc
.ResourceEntities
.ResourceEntity
)
916 return refs
[0].href
.split("vapp")[1][1:]
917 except Exception as e
:
918 self
.logger
.exception(e
)
922 def check_vapp(self
, vdc
, vapp_id
):
923 """ Take VDC object and vApp ID and return True if given ID in vCloud director
924 otherwise return False
927 """ Method Method returns vApp name from vCD and lookup done by vapp_id.
930 vca: Connector to VCA
932 vappid: vappid is application identifier
935 The return vApp name otherwise None
938 refs
= filter(lambda ref
:
939 ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
940 vdc
.ResourceEntities
.ResourceEntity
)
942 vappid
= ref
.href
.split("vapp")[1][1:]
943 # find vapp with respected vapp uuid
944 if vappid
== vapp_id
:
946 except Exception as e
:
947 self
.logger
.exception(e
)
951 def get_namebyvappid(self
, vca
, vdc
, vapp_id
):
952 """Method returns vApp name from vCD and lookup done by vapp_id.
955 vca: Connector to VCA
957 vapp_id: vappid is application identifier
960 The return vApp name otherwise None
964 refs
= filter(lambda ref
: ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
965 vdc
.ResourceEntities
.ResourceEntity
)
967 # we care only about UUID the rest doesn't matter
968 vappid
= ref
.href
.split("vapp")[1][1:]
969 if vappid
== vapp_id
:
970 response
= Http
.get(ref
.href
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
,
972 tree
= XmlElementTree
.fromstring(response
.content
)
973 return tree
.attrib
['name']
974 except Exception as e
:
975 self
.logger
.exception(e
)
979 def new_vminstance(self
, name
, description
, start
, image_id
, flavor_id
, net_list
, cloud_config
=None):
980 """Adds a VM instance to VIM
982 start: indicates if VM must start or boot in pause mode. Ignored
983 image_id,flavor_id: image and flavor uuid
984 net_list: list of interfaces, each one is a dictionary with:
986 net_id: network uuid to connect
987 vpci: virtual vcpi to assign
988 model: interface model, virtio, e2000, ...
990 use: 'data', 'bridge', 'mgmt'
991 type: 'virtual', 'PF', 'VF', 'VFnotShared'
992 vim_id: filled/added by this function
993 cloud_config: can be a text script to be passed directly to cloud-init,
994 or an object to inject users and ssh keys with format:
995 key-pairs: [] list of keys to install to the default user
996 users: [{ name, key-pairs: []}] list of users to add with their key-pair
997 #TODO ip, security groups
998 Returns >=0, the instance identifier
1002 self
.logger
.info("Creating new instance for entry".format(name
))
1003 self
.logger
.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
1004 format(description
, start
, image_id
, flavor_id
, net_list
, cloud_config
))
1005 vca
= self
.connect()
1007 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1009 # if vm already deployed we return existing uuid
1010 vapp_uuid
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
1011 if vapp_uuid
is not None:
1014 # we check for presence of VDC, Catalog entry and Flavor.
1015 vdc
= vca
.get_vdc(self
.tenant_name
)
1017 return -1, " Failed create vApp {}: (Failed reprieve VDC information)".format(name
)
1018 catalogs
= vca
.get_catalogs()
1019 if catalogs
is None:
1020 return -2, " Failed create vApp {}: (Failed reprieve Catalog information)".format(name
)
1021 flavor
= flavorlist
[flavor_id
]
1022 if catalogs
is None:
1023 return -3, " Failed create vApp {}: (Failed reprieve Flavor information)".format(name
)
1025 # image upload creates template name as catalog name space Template.
1026 templateName
= self
.get_catalogbyid(image_id
, catalogs
) + ' Template'
1031 # client must provide at least one entry in net_list if not we report error
1032 primary_net
= net_list
[0]
1033 if primary_net
is None:
1034 return -4, "Failed create vApp {}: (Network list is empty)".format(name
)
1036 primary_net_id
= primary_net
['net_id']
1037 primary_net_name
= self
.get_network_name_by_id(primary_net_id
)
1038 network_mode
= primary_net
['use']
1040 # use: 'data', 'bridge', 'mgmt'
1041 # create vApp. Set vcpu and ram based on flavor id.
1042 vapptask
= vca
.create_vapp(self
.tenant_name
, name
, templateName
,
1043 self
.get_catalogbyid(image_id
, catalogs
),
1044 network_name
=primary_net_name
,
1045 network_mode
='bridged',
1047 vm_cpus
=flavor
['vcpus'],
1048 vm_memory
=flavor
['ram'])
1050 if vapptask
is None or vapptask
is False:
1051 return -1, "create_vapp(): failed deploy vApp {}".format(name
)
1052 if type(vapptask
) is VappTask
:
1053 vca
.block_until_completed(vapptask
)
1055 # we should have now vapp in undeployed state.
1056 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), name
)
1058 return -1, "get_vapp(): failed retrieve vApp {}".format(name
)
1063 for net
in net_list
:
1064 # openmano uses network id in UUID format.
1065 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
1066 interface_net_id
= net
['net_id']
1067 interface_net_name
= self
.get_network_name_by_id(interface_net_id
)
1068 interface_network_mode
= net
['use']
1070 if primary_net_name
is not None:
1071 nets
= filter(lambda n
: n
.name
== interface_net_name
, vca
.get_networks(self
.tenant_name
))
1073 task
= vapp
.connect_to_network(nets
[0].name
, nets
[0].href
)
1074 if type(task
) is GenericTask
:
1075 vca
.block_until_completed(task
)
1076 # connect network to VM
1077 # TODO figure out mapping between openmano representation to vCloud director.
1078 # one idea use first nic as managment DHCP all remaining in bridge mode
1079 task
= vapp
.connect_vms(nets
[0].name
, connection_index
=nicIndex
,
1080 connections_primary_index
=nicIndex
,
1081 ip_allocation_mode
='DHCP')
1082 if type(task
) is GenericTask
:
1083 vca
.block_until_completed(task
)
1087 # it might be a case if specific mandatory entry in dict is empty
1088 self
.logger
.debug("Key error {}".format(KeyError.message
))
1090 # deploy and power on vm
1091 task
= vapp
.poweron()
1092 if type(task
) is TaskType
:
1093 vca
.block_until_completed(task
)
1094 deploytask
= vapp
.deploy(powerOn
='True')
1095 if type(task
) is TaskType
:
1096 vca
.block_until_completed(deploytask
)
1098 # check if vApp deployed and if that the case return vApp UUID otherwise -1
1099 vapp_uuid
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
1100 if vapp_uuid
is not None:
1103 return -1, " Failed create vApp {}".format(name
)
1107 ## based on current discussion
1111 # created: '2016-09-08T11:51:58'
1112 # description: simple-instance.linux1.1
1113 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
1114 # hostId: e836c036-74e7-11e6-b249-0800273e724c
1115 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
1120 def get_vminstance(self
, vim_vm_uuid
):
1121 '''Returns the VM instance information from VIM'''
1123 self
.logger
.debug("Client requesting vm instance {} ".format(vim_vm_uuid
))
1124 vca
= self
.connect()
1126 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1128 vdc
= vca
.get_vdc(self
.tenant_name
)
1130 return -1, "Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
)
1132 vm_name
= self
.get_namebyvappid(vca
, vdc
, vim_vm_uuid
)
1134 self
.logger
.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid
))
1135 return None, "Failed to get vApp name by UUID {}".format(vim_vm_uuid
)
1137 the_vapp
= vca
.get_vapp(vdc
, vm_name
)
1138 vm_info
= the_vapp
.get_vms_details()
1140 vm_dict
= {'description': vm_info
[0]['name'], 'status': vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()],
1141 'error_msg': vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()],
1142 'vim_info': yaml
.safe_dump(the_vapp
.get_vms_details()), 'interfaces': []}
1145 vm_app_networks
= the_vapp
.get_vms_network_info()
1149 org_network_dict
= self
.get_org(self
.org_uuid
)['networks']
1150 for vapp_network
in vm_app_networks
:
1151 for vm_network
in vapp_network
:
1152 if vm_network
['name'] == vm_name
:
1154 # interface['vim_info'] = yaml.safe_dump(vm_network)
1155 interface
["mac_address"] = vm_network
['mac']
1156 for net_uuid
in org_network_dict
:
1157 if org_network_dict
[net_uuid
] == vm_network
['network_name']:
1158 interface
["vim_net_id"] = net_uuid
1159 interface
["vim_interface_id"] = vm_network
['network_name']
1160 interface
['ip_address'] = vm_network
['ip']
1161 interfaces
.append(interface
)
1163 self
.logger
.debug("Error in respond {}".format(KeyError.message
))
1164 self
.logger
.debug(traceback
.format_exc())
1166 vm_dict
['interfaces'] = interfaces
1170 def delete_vminstance(self
, vm__vim_uuid
):
1171 """Method poweroff and remove VM instance from vcloud director network.
1174 vm__vim_uuid: VM UUID
1177 Returns the instance identifier
1180 self
.logger
.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid
))
1181 vca
= self
.connect()
1183 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1185 vdc
= vca
.get_vdc(self
.tenant_name
)
1187 self
.logger
.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
1189 raise vimconnException("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1192 vapp_name
= self
.get_namebyvappid(vca
, vdc
, vm__vim_uuid
)
1193 if vapp_name
is None:
1194 self
.logger
.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1195 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
)
1197 self
.logger
.info("Deleting vApp {} and UUID {}".format(vapp_name
, vm__vim_uuid
))
1199 # Delete vApp and wait for status change if task executed and vApp is None.
1200 # We successfully delete vApp from vCloud
1201 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
)
1202 # poweroff vapp / undeploy and delete
1203 power_off_task
= vapp
.poweroff()
1204 if type(power_off_task
) is GenericTask
:
1205 vca
.block_until_completed(power_off_task
)
1207 if not power_off_task
:
1208 self
.logger
.debug("delete_vminstance(): Failed power off VM uuid {} ".format(vm__vim_uuid
))
1211 if vapp
.me
.deployed
:
1212 undeploy_task
= vapp
.undeploy()
1213 if type(undeploy_task
) is GenericTask
:
1215 while retry
<= DELETE_INSTANCE_RETRY
:
1216 result
= vca
.block_until_completed(undeploy_task
)
1224 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
)
1225 if vapp
is not None:
1226 delete_task
= vapp
.delete()
1228 while retry
<= DELETE_INSTANCE_RETRY
:
1229 task
= vapp
.delete()
1230 if type(task
) is GenericTask
:
1231 vca
.block_until_completed(delete_task
)
1233 self
.loggger
.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid
))
1236 if vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
) is None:
1239 self
.logger
.debug(traceback
.format_exc())
1240 raise vimconnException("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1244 def refresh_vms_status(self
, vm_list
):
1245 """Get the status of the virtual machines and their interfaces/ports
1246 Params: the list of VM identifiers
1247 Returns a dictionary with:
1248 vm_id: #VIM id of this Virtual Machine
1249 status: #Mandatory. Text with one of:
1250 # DELETED (not found at vim)
1251 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1252 # OTHER (Vim reported other status not understood)
1253 # ERROR (VIM indicates an ERROR status)
1254 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
1255 # CREATING (on building process), ERROR
1256 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
1258 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1259 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1261 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1262 mac_address: #Text format XX:XX:XX:XX:XX:XX
1263 vim_net_id: #network id where this interface is connected
1264 vim_interface_id: #interface/port VIM id
1265 ip_address: #null, or text with IPv4, IPv6 address
1268 self
.logger
.debug("Client requesting refresh vm status for {} ".format(vm_list
))
1269 vca
= self
.connect()
1271 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1273 vdc
= vca
.get_vdc(self
.tenant_name
)
1275 raise vimconnException("Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1278 for vmuuid
in vm_list
:
1279 vmname
= self
.get_namebyvappid(vca
, vdc
, vmuuid
)
1280 if vmname
is not None:
1282 the_vapp
= vca
.get_vapp(vdc
, vmname
)
1283 vm_info
= the_vapp
.get_vms_details()
1284 vm_status
= vm_info
[0]['status']
1286 vm_dict
= {'status': None, 'error_msg': None, 'vim_info': None, 'interfaces': []}
1287 vm_dict
['status'] = vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()]
1288 vm_dict
['error_msg'] = vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()]
1289 vm_dict
['vim_info'] = yaml
.safe_dump(the_vapp
.get_vms_details())
1293 vm_app_networks
= the_vapp
.get_vms_network_info()
1294 for vapp_network
in vm_app_networks
:
1295 for vm_network
in vapp_network
:
1296 if vm_network
['name'] == vmname
:
1298 # interface['vim_info'] = yaml.safe_dump(vm_network)
1299 interface
["mac_address"] = vm_network
['mac']
1300 interface
["vim_net_id"] = self
.get_network_name_by_id(vm_network
['network_name'])
1301 interface
["vim_interface_id"] = vm_network
['network_name']
1302 interface
['ip_address'] = vm_network
['ip']
1303 vm_dict
["interfaces"].append(interface
)
1304 # add a vm to vm dict
1305 vms_dict
.setdefault(vmuuid
, vm_dict
)
1307 self
.logger
.debug("Error in respond {}".format(KeyError.message
))
1308 self
.logger
.debug(traceback
.format_exc())
1312 def action_vminstance(self
, vm__vim_uuid
=None, action_dict
=None):
1313 """Send and action over a VM instance from VIM
1314 Returns the vm_id if the action was successfully sent to the VIM"""
1316 self
.logger
.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid
, action_dict
))
1317 if vm__vim_uuid
is None or action_dict
is None:
1318 raise vimconnException("Invalid request. VM id or action is None.")
1320 vca
= self
.connect()
1322 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1324 vdc
= vca
.get_vdc(self
.tenant_name
)
1326 return -1, "Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
)
1328 vapp_name
= self
.get_namebyvappid(vca
, vdc
, vm__vim_uuid
)
1329 if vapp_name
is None:
1330 self
.logger
.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1331 raise vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1333 self
.logger
.info("Action_vminstance vApp {} and UUID {}".format(vapp_name
, vm__vim_uuid
))
1336 the_vapp
= vca
.get_vapp(vdc
, vapp_name
)
1337 # TODO fix all status
1338 if "start" in action_dict
:
1339 if action_dict
["start"] == "rebuild":
1340 the_vapp
.deploy(powerOn
=True)
1342 vm_info
= the_vapp
.get_vms_details()
1343 vm_status
= vm_info
[0]['status']
1344 if vm_status
== "Suspended":
1346 elif vm_status
.status
== "Powered off":
1348 elif "pause" in action_dict
:
1351 elif "resume" in action_dict
:
1354 elif "shutoff" in action_dict
or "shutdown" in action_dict
:
1356 elif "forceOff" in action_dict
:
1358 elif "terminate" in action_dict
:
1360 # elif "createImage" in action_dict:
1361 # server.create_image()
1367 def get_vminstance_console(self
, vm_id
, console_type
="vnc"):
1369 Get a console for the virtual machine
1371 vm_id: uuid of the VM
1372 console_type, can be:
1373 "novnc" (by default), "xvpvnc" for VNC types,
1374 "rdp-html5" for RDP types, "spice-html5" for SPICE types
1375 Returns dict with the console parameters:
1376 protocol: ssh, ftp, http, https, ...
1377 server: usually ip address
1378 port: the http, ssh, ... port
1379 suffix: extra text, e.g. the http path and query string
1381 raise vimconnNotImplemented("Should have implemented this")
1383 # NOT USED METHODS in current version
1385 def host_vim2gui(self
, host
, server_dict
):
1386 '''Transform host dictionary from VIM format to GUI format,
1387 and append to the server_dict
1389 raise vimconnNotImplemented("Should have implemented this")
1391 def get_hosts_info(self
):
1392 '''Get the information of deployed hosts
1393 Returns the hosts content'''
1394 raise vimconnNotImplemented("Should have implemented this")
1396 def get_hosts(self
, vim_tenant
):
1397 '''Get the hosts and deployed instances
1398 Returns the hosts content'''
1399 raise vimconnNotImplemented("Should have implemented this")
1401 def get_processor_rankings(self
):
1402 '''Get the processor rankings in the VIM database'''
1403 raise vimconnNotImplemented("Should have implemented this")
1405 def new_host(self
, host_data
):
1406 '''Adds a new host to VIM'''
1407 '''Returns status code of the VIM response'''
1408 raise vimconnNotImplemented("Should have implemented this")
1410 def new_external_port(self
, port_data
):
1411 '''Adds a external port to VIM'''
1412 '''Returns the port identifier'''
1413 raise vimconnNotImplemented("Should have implemented this")
1415 def new_external_network(self
, net_name
, net_type
):
1416 '''Adds a external network to VIM (shared)'''
1417 '''Returns the network identifier'''
1418 raise vimconnNotImplemented("Should have implemented this")
1420 def connect_port_network(self
, port_id
, network_id
, admin
=False):
1421 '''Connects a external port to a network'''
1422 '''Returns status code of the VIM response'''
1423 raise vimconnNotImplemented("Should have implemented this")
1425 def new_vminstancefromJSON(self
, vm_data
):
1426 '''Adds a VM instance to VIM'''
1427 '''Returns the instance identifier'''
1428 raise vimconnNotImplemented("Should have implemented this")
1430 def get_network_name_by_id(self
, network_name
=None):
1431 """Method gets vcloud director network named based on supplied uuid.
1434 network_name: network_id
1437 The return network name.
1440 vca
= self
.connect()
1442 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1444 if network_name
is None:
1448 org_network_dict
= self
.get_org(self
.org_uuid
)['networks']
1449 for net_uuid
in org_network_dict
:
1450 if org_network_dict
[net_uuid
] == network_name
:
1453 self
.logger
.debug("Exception in get_network_name_by_id")
1454 self
.logger
.debug(traceback
.format_exc())
1458 def list_org_action(self
):
1460 Method leverages vCloud director and query for available organization for particular user
1463 vca - is active VCA connection.
1464 vdc_name - is a vdc name that will be used to query vms action
1467 The return XML respond
1470 vca
= self
.connect()
1472 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1474 url_list
= [vca
.host
, '/api/org']
1475 vm_list_rest_call
= ''.join(url_list
)
1477 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1478 response
= Http
.get(url
=vm_list_rest_call
,
1479 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1482 if response
.status_code
== requests
.codes
.ok
:
1483 return response
.content
1487 def get_org_action(self
, org_uuid
=None):
1489 Method leverages vCloud director and retrieve available object fdr organization.
1492 vca - is active VCA connection.
1493 vdc_name - is a vdc name that will be used to query vms action
1496 The return XML respond
1499 vca
= self
.connect()
1501 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1503 if org_uuid
is None:
1506 url_list
= [vca
.host
, '/api/org/', org_uuid
]
1507 vm_list_rest_call
= ''.join(url_list
)
1509 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1510 response
= Http
.get(url
=vm_list_rest_call
,
1511 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1514 if response
.status_code
== requests
.codes
.ok
:
1515 return response
.content
1519 def get_org(self
, org_uuid
=None):
1521 Method retrieves available organization in vCloud Director
1524 vca - is active VCA connection.
1525 vdc_name - is a vdc name that will be used to query vms action
1528 The return dictionary and key for each entry vapp UUID
1533 vca
= self
.connect()
1535 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1537 if org_uuid
is None:
1540 content
= self
.get_org_action(org_uuid
=org_uuid
)
1545 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1546 for child
in vm_list_xmlroot
:
1547 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
1548 vdc_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1549 org_dict
['vdcs'] = vdc_list
1550 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
1551 network_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1552 org_dict
['networks'] = network_list
1553 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
1554 catalog_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1555 org_dict
['catalogs'] = catalog_list
1561 def get_org_list(self
):
1563 Method retrieves available organization in vCloud Director
1566 vca - is active VCA connection.
1569 The return dictionary and key for each entry VDC UUID
1573 vca
= self
.connect()
1575 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1577 content
= self
.list_org_action()
1579 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1580 for vm_xml
in vm_list_xmlroot
:
1581 if vm_xml
.tag
.split("}")[1] == 'Org':
1582 org_uuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1583 org_dict
[org_uuid
[0]] = vm_xml
.attrib
['name']
1589 def vms_view_action(self
, vdc_name
=None):
1590 """ Method leverages vCloud director vms query call
1593 vca - is active VCA connection.
1594 vdc_name - is a vdc name that will be used to query vms action
1597 The return XML respond
1599 vca
= self
.connect()
1600 if vdc_name
is None:
1603 url_list
= [vca
.host
, '/api/vms/query']
1604 vm_list_rest_call
= ''.join(url_list
)
1606 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1607 refs
= filter(lambda ref
: ref
.name
== vdc_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vdc+xml',
1608 vca
.vcloud_session
.organization
.Link
)
1610 response
= Http
.get(url
=vm_list_rest_call
,
1611 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1614 if response
.status_code
== requests
.codes
.ok
:
1615 return response
.content
1619 def get_vapp_list(self
, vdc_name
=None):
1621 Method retrieves vApp list deployed vCloud director and returns a dictionary
1622 contains a list of all vapp deployed for queried VDC.
1623 The key for a dictionary is vApp UUID
1627 vca - is active VCA connection.
1628 vdc_name - is a vdc name that will be used to query vms action
1631 The return dictionary and key for each entry vapp UUID
1635 if vdc_name
is None:
1638 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1640 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1641 for vm_xml
in vm_list_xmlroot
:
1642 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1643 if vm_xml
.attrib
['isVAppTemplate'] == 'true':
1644 rawuuid
= vm_xml
.attrib
['container'].split('/')[-1:]
1645 if 'vappTemplate-' in rawuuid
[0]:
1646 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1647 # vm and use raw UUID as key
1648 vapp_dict
[rawuuid
[0][13:]] = vm_xml
.attrib
1654 def get_vm_list(self
, vdc_name
=None):
1656 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1657 contains a list of all VM's deployed for queried VDC.
1658 The key for a dictionary is VM UUID
1662 vca - is active VCA connection.
1663 vdc_name - is a vdc name that will be used to query vms action
1666 The return dictionary and key for each entry vapp UUID
1670 if vdc_name
is None:
1673 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1675 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1676 for vm_xml
in vm_list_xmlroot
:
1677 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1678 if vm_xml
.attrib
['isVAppTemplate'] == 'false':
1679 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1680 if 'vm-' in rawuuid
[0]:
1681 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1682 # vm and use raw UUID as key
1683 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1689 def get_vapp(self
, vdc_name
=None, vapp_name
=None, isuuid
=False):
1691 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1692 contains a list of all VM's deployed for queried VDC.
1693 The key for a dictionary is VM UUID
1697 vca - is active VCA connection.
1698 vdc_name - is a vdc name that will be used to query vms action
1701 The return dictionary and key for each entry vapp UUID
1704 vca
= self
.connect()
1706 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1708 if vdc_name
is None:
1711 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1713 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1714 for vm_xml
in vm_list_xmlroot
:
1715 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1717 # lookup done by UUID
1718 if vapp_name
in vm_xml
.attrib
['container']:
1719 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1720 if 'vm-' in rawuuid
[0]:
1721 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1722 # vm and use raw UUID as key
1723 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1724 # lookup done by Name
1726 if vapp_name
in vm_xml
.attrib
['name']:
1727 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1728 if 'vm-' in rawuuid
[0]:
1729 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1730 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1731 # vm and use raw UUID as key
1737 def get_network_action(self
, network_uuid
=None):
1739 Method leverages vCloud director and query network based on network uuid
1742 vca - is active VCA connection.
1743 network_uuid - is a network uuid
1746 The return XML respond
1749 vca
= self
.connect()
1751 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1753 if network_uuid
is None:
1756 url_list
= [vca
.host
, '/api/network/', network_uuid
]
1757 vm_list_rest_call
= ''.join(url_list
)
1759 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1760 response
= Http
.get(url
=vm_list_rest_call
,
1761 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1764 if response
.status_code
== requests
.codes
.ok
:
1765 return response
.content
1769 def get_vcd_network(self
, network_uuid
=None):
1771 Method retrieves available network from vCloud Director
1774 network_uuid - is VCD network UUID
1776 Each element serialized as key : value pair
1778 Following keys available for access. network_configuration['Gateway'}
1782 <IsInherited>true</IsInherited>
1783 <Gateway>172.16.252.100</Gateway>
1784 <Netmask>255.255.255.0</Netmask>
1785 <Dns1>172.16.254.201</Dns1>
1786 <Dns2>172.16.254.202</Dns2>
1787 <DnsSuffix>vmwarelab.edu</DnsSuffix>
1788 <IsEnabled>true</IsEnabled>
1791 <StartAddress>172.16.252.1</StartAddress>
1792 <EndAddress>172.16.252.99</EndAddress>
1797 <FenceMode>bridged</FenceMode>
1800 The return dictionary and key for each entry vapp UUID
1803 network_configuration
= {}
1804 if network_uuid
is None:
1807 content
= self
.get_network_action(network_uuid
=network_uuid
)
1809 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1811 network_configuration
['status'] = vm_list_xmlroot
.get("status")
1812 network_configuration
['name'] = vm_list_xmlroot
.get("name")
1813 network_configuration
['uuid'] = vm_list_xmlroot
.get("id").split(":")[3]
1815 for child
in vm_list_xmlroot
:
1816 if child
.tag
.split("}")[1] == 'IsShared':
1817 network_configuration
['isShared'] = child
.text
.strip()
1818 if child
.tag
.split("}")[1] == 'Configuration':
1819 for configuration
in child
.iter():
1820 tagKey
= configuration
.tag
.split("}")[1].strip()
1822 network_configuration
[tagKey
] = configuration
.text
.strip()
1823 return network_configuration
1827 return network_configuration
1829 def delete_network_action(self
, network_uuid
=None):
1831 Method delete given network from vCloud director
1834 network_uuid - is a network uuid that client wish to delete
1837 The return None or XML respond or false
1840 vca
= self
.connect_as_admin()
1842 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1843 if network_uuid
is None:
1846 url_list
= [vca
.host
, '/api/admin/network/', network_uuid
]
1847 vm_list_rest_call
= ''.join(url_list
)
1849 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1850 response
= Http
.delete(url
=vm_list_rest_call
,
1851 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1855 if response
.status_code
== 202:
1860 def create_network(self
, network_name
=None, parent_network_uuid
=None, isshared
='true'):
1862 Method create network in vCloud director
1865 network_name - is network name to be created.
1866 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1867 It optional attribute. by default if no parent network indicate the first available will be used.
1870 The return network uuid or return None
1873 content
= self
.create_network_rest(network_name
=network_name
,
1874 parent_network_uuid
=parent_network_uuid
,
1877 self
.logger
.debug("Failed create network {}.".format(network_name
))
1881 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1882 vcd_uuid
= vm_list_xmlroot
.get('id').split(":")
1883 if len(vcd_uuid
) == 4:
1884 self
.logger
.info("Create new network name: {} uuid: {}".format(network_name
, vcd_uuid
[3]))
1887 self
.logger
.debug("Failed create network {}".format(network_name
))
1890 def create_network_rest(self
, network_name
=None, parent_network_uuid
=None, isshared
='true'):
1892 Method create network in vCloud director
1895 network_name - is network name to be created.
1896 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1897 It optional attribute. by default if no parent network indicate the first available will be used.
1900 The return network uuid or return None
1903 vca
= self
.connect_as_admin()
1905 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1906 if network_name
is None:
1909 url_list
= [vca
.host
, '/api/admin/vdc/', self
.tenant_id
]
1910 vm_list_rest_call
= ''.join(url_list
)
1911 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1912 response
= Http
.get(url
=vm_list_rest_call
,
1913 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1917 provider_network
= None
1918 available_networks
= None
1919 add_vdc_rest_url
= None
1921 if response
.status_code
!= requests
.codes
.ok
:
1922 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
1923 response
.status_code
))
1927 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
1928 for child
in vm_list_xmlroot
:
1929 if child
.tag
.split("}")[1] == 'ProviderVdcReference':
1930 provider_network
= child
.attrib
.get('href')
1931 # application/vnd.vmware.admin.providervdc+xml
1932 if child
.tag
.split("}")[1] == 'Link':
1933 if child
.attrib
.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
1934 and child
.attrib
.get('rel') == 'add':
1935 add_vdc_rest_url
= child
.attrib
.get('href')
1937 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
1938 self
.logger
.debug("Respond body {}".format(response
.content
))
1941 # find pvdc provided available network
1942 response
= Http
.get(url
=provider_network
,
1943 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1946 if response
.status_code
!= requests
.codes
.ok
:
1947 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
1948 response
.status_code
))
1951 # available_networks.split("/")[-1]
1953 if parent_network_uuid
is None:
1955 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
1956 for child
in vm_list_xmlroot
.iter():
1957 if child
.tag
.split("}")[1] == 'AvailableNetworks':
1958 for networks
in child
.iter():
1959 # application/vnd.vmware.admin.network+xml
1960 if networks
.attrib
.get('href') is not None:
1961 available_networks
= networks
.attrib
.get('href')
1966 # either use client provided UUID or search for a first available
1967 # if both are not defined we return none
1968 if parent_network_uuid
is not None:
1969 url_list
= [vca
.host
, '/api/admin/network/', parent_network_uuid
]
1970 add_vdc_rest_url
= ''.join(url_list
)
1972 # return response.content
1973 data
= """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
1974 <Description>Openmano created</Description>
1976 <ParentNetwork href="{1:s}"/>
1977 <FenceMode>{2:s}</FenceMode>
1979 <IsShared>{3:s}</IsShared>
1980 </OrgVdcNetwork> """.format(escape(network_name
), available_networks
, "bridged", isshared
)
1982 headers
= vca
.vcloud_session
.get_vcloud_headers()
1983 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
1984 response
= Http
.post(url
=add_vdc_rest_url
, headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=vca
.logger
)
1986 # if we all ok we respond with content otherwise by default None
1987 if response
.status_code
== 201:
1988 return response
.content
1991 def get_provider_rest(self
, vca
=None):
1993 Method gets provider vdc view from vcloud director
1996 network_name - is network name to be created.
1997 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1998 It optional attribute. by default if no parent network indicate the first available will be used.
2001 The return xml content of respond or None
2004 url_list
= [vca
.host
, '/api/admin']
2005 response
= Http
.get(url
=''.join(url_list
),
2006 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2010 if response
.status_code
== requests
.codes
.ok
:
2011 return response
.content
2014 def create_vdc(self
, vdc_name
=None):
2018 xml_content
= self
.create_vdc_from_tmpl_rest(vdc_name
=vdc_name
)
2019 if xml_content
is not None:
2022 task_resp_xmlroot
= XmlElementTree
.fromstring(xml_content
)
2023 for child
in task_resp_xmlroot
:
2024 if child
.tag
.split("}")[1] == 'Owner':
2025 vdc_id
= child
.attrib
.get('href').split("/")[-1]
2026 vdc_dict
[vdc_id
] = task_resp_xmlroot
.get('href')
2029 self
.logger
.debug("Respond body {}".format(xml_content
))
2033 def create_vdc_from_tmpl_rest(self
, vdc_name
=None):
2035 Method create vdc in vCloud director based on VDC template.
2036 it uses pre-defined template that must be named openmano
2039 vdc_name - name of a new vdc.
2042 The return xml content of respond or None
2045 self
.logger
.info("Creating new vdc {}".format(vdc_name
))
2046 print ("Creating new vdc {}".format(vdc_name
))
2048 vca
= self
.connect()
2050 raise vimconn
.vimconnConnectionException("self.connect() is failed")
2051 if vdc_name
is None:
2054 url_list
= [vca
.host
, '/api/vdcTemplates']
2055 vm_list_rest_call
= ''.join(url_list
)
2056 response
= Http
.get(url
=vm_list_rest_call
,
2057 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2061 # container url to a template
2062 vdc_template_ref
= None
2064 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2065 for child
in vm_list_xmlroot
:
2066 # application/vnd.vmware.admin.providervdc+xml
2067 # we need find a template from witch we instantiate VDC
2068 if child
.tag
.split("}")[1] == 'VdcTemplate':
2069 if child
.attrib
.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child
.attrib
.get(
2070 'name') == 'openmano':
2071 vdc_template_ref
= child
.attrib
.get('href')
2073 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2074 self
.logger
.debug("Respond body {}".format(response
.content
))
2077 # if we didn't found required pre defined template we return None
2078 if vdc_template_ref
is None:
2083 url_list
= [vca
.host
, '/api/org/', self
.org_uuid
, '/action/instantiate']
2084 vm_list_rest_call
= ''.join(url_list
)
2085 data
= """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2086 <Source href="{1:s}"></Source>
2087 <Description>opnemano</Description>
2088 </InstantiateVdcTemplateParams>""".format(vdc_name
, vdc_template_ref
)
2089 headers
= vca
.vcloud_session
.get_vcloud_headers()
2090 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
2091 response
= Http
.post(url
=vm_list_rest_call
, headers
=headers
, data
=data
, verify
=vca
.verify
,
2093 # if we all ok we respond with content otherwise by default None
2094 if response
.status_code
>= 200 and response
.status_code
< 300:
2095 return response
.content
2098 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2099 self
.logger
.debug("Respond body {}".format(response
.content
))
2103 def create_vdc_rest(self
, vdc_name
=None):
2105 Method create network in vCloud director
2108 network_name - is network name to be created.
2109 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2110 It optional attribute. by default if no parent network indicate the first available will be used.
2113 The return network uuid or return None
2116 self
.logger
.info("Creating new vdc {}".format(vdc_name
))
2117 print ("Creating new vdc {}".format(vdc_name
))
2119 vca
= self
.connect_as_admin()
2121 raise vimconn
.vimconnConnectionException("self.connect() is failed")
2122 if vdc_name
is None:
2125 url_list
= [vca
.host
, '/api/admin/org/', self
.org_uuid
]
2126 vm_list_rest_call
= ''.join(url_list
)
2127 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
2128 response
= Http
.get(url
=vm_list_rest_call
,
2129 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2133 provider_vdc_ref
= None
2134 add_vdc_rest_url
= None
2135 available_networks
= None
2137 if response
.status_code
!= requests
.codes
.ok
:
2138 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
2139 response
.status_code
))
2143 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2144 for child
in vm_list_xmlroot
:
2145 # application/vnd.vmware.admin.providervdc+xml
2146 if child
.tag
.split("}")[1] == 'Link':
2147 if child
.attrib
.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
2148 and child
.attrib
.get('rel') == 'add':
2149 add_vdc_rest_url
= child
.attrib
.get('href')
2151 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2152 self
.logger
.debug("Respond body {}".format(response
.content
))
2155 response
= self
.get_provider_rest(vca
=vca
)
2158 vm_list_xmlroot
= XmlElementTree
.fromstring(response
)
2159 for child
in vm_list_xmlroot
:
2160 if child
.tag
.split("}")[1] == 'ProviderVdcReferences':
2161 for sub_child
in child
:
2162 provider_vdc_ref
= sub_child
.attrib
.get('href')
2164 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2165 self
.logger
.debug("Respond body {}".format(response
))
2168 print "Add vdc {}".format(add_vdc_rest_url
)
2169 print "Provider ref {}".format(provider_vdc_ref
)
2170 if add_vdc_rest_url
is not None and provider_vdc_ref
is not None:
2171 data
= """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
2172 <AllocationModel>ReservationPool</AllocationModel>
2173 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
2174 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
2175 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
2176 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
2177 <ProviderVdcReference
2178 name="Main Provider"
2180 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name
),
2185 headers
= vca
.vcloud_session
.get_vcloud_headers()
2186 headers
['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
2187 response
= Http
.post(url
=add_vdc_rest_url
, headers
=headers
, data
=data
, verify
=vca
.verify
,
2190 print response
.status_code
2191 print response
.content
2192 # if we all ok we respond with content otherwise by default None
2193 if response
.status_code
== 201:
2194 return response
.content