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.
35 from xml
.etree
import ElementTree
as XmlElementTree
38 from pyvcloud
import Http
39 from pyvcloud
.vcloudair
import VCA
40 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
import sessionType
, organizationType
, \
41 vAppType
, organizationListType
, vdcType
, catalogType
, queryRecordViewType
, \
42 networkType
, vcloudType
, taskType
, diskType
, vmsType
, vdcTemplateListType
, mediaType
43 from xml
.sax
.saxutils
import escape
45 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.admin
.vCloudEntities
import TaskType
46 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
.taskType
import TaskType
as GenericTask
47 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
.vAppType
import TaskType
as VappTask
48 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.admin
.vCloudEntities
import TasksInProgressType
57 # global variable for vcd connector type
58 STANDALONE
= 'standalone'
60 # global variable for number of retry
61 DELETE_INSTANCE_RETRY
= 3
65 __author__
= "Mustafa Bayramov"
66 __date__
= "$26-Aug-2016 11:09:29$"
68 # -1: "Could not be created",
74 # 5: "Waiting for user input",
76 # 7: "Unrecognized state",
78 # 9: "Inconsistent state",
79 # 10: "Children do not all have the same status",
80 # 11: "Upload initiated, OVF descriptor pending",
81 # 12: "Upload initiated, copying contents",
82 # 13: "Upload initiated , disk contents pending",
83 # 14: "Upload has been quarantined",
84 # 15: "Upload quarantine period has expired"
86 # mapping vCD status to MANO
87 vcdStatusCode2manoFormat
= {4: 'ACTIVE',
96 netStatus2manoFormat
= {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
97 'ERROR': 'ERROR', 'DELETED': 'DELETED'
100 # dict used to store flavor in memory
104 class vimconnector(vimconn
.vimconnector
):
105 def __init__(self
, uuid
=None, name
=None, tenant_id
=None, tenant_name
=None,
106 url
=None, url_admin
=None, user
=None, passwd
=None, log_level
="ERROR", config
={}):
107 vimconn
.vimconnector
.__init
__(self
, uuid
, name
, tenant_id
, tenant_name
, url
,
108 url_admin
, user
, passwd
, log_level
, config
)
113 self
.url_admin
= url_admin
114 self
.tenant_id
= tenant_id
115 self
.tenant_name
= tenant_name
119 self
.admin_password
= None
120 self
.admin_user
= None
122 self
.logger
= logging
.getLogger('openmano.vim.vmware')
123 self
.logger
.setLevel(10)
126 self
.admin_user
= config
['admin_username']
127 self
.admin_password
= config
['admin_password']
129 raise vimconn
.vimconnException(message
="Error admin username or admin password is empty.")
131 self
.logger
= logging
.getLogger('mano.vim.vmware')
136 raise TypeError, 'url param can not be NoneType'
138 if not self
.url_admin
: # try to use normal url
139 self
.url_admin
= self
.url
141 logging
.debug("Calling constructor with following paramters")
142 logging
.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self
.id, self
.name
,
143 self
.tenant_id
, self
.tenant_name
))
144 logging
.debug("vcd url {} vcd username: {} vcd password: {}".format(self
.url
, self
.user
, self
.passwd
))
145 logging
.debug("vcd admin username {} vcd admin passowrd {}".format(self
.admin_user
, self
.admin_password
))
147 # initialize organization
148 if self
.user
is not None and self
.passwd
is not None and self
.url
:
149 self
.init_organization()
151 def __getitem__(self
, index
):
152 if index
== 'tenant_id':
153 return self
.tenant_id
154 if index
== 'tenant_name':
155 return self
.tenant_name
158 elif index
== 'name':
160 elif index
== 'org_name':
162 elif index
== 'org_uuid':
164 elif index
== 'user':
166 elif index
== 'passwd':
170 elif index
== 'url_admin':
171 return self
.url_admin
172 elif index
== "config":
175 raise KeyError("Invalid key '%s'" % str(index
))
177 def __setitem__(self
, index
, value
):
178 if index
== 'tenant_id':
179 self
.tenant_id
= value
180 if index
== 'tenant_name':
181 self
.tenant_name
= value
184 # we use name = org #TODO later refactor
185 elif index
== 'name':
188 elif index
== 'org_name':
189 self
.org_name
= value
191 elif index
== 'org_uuid':
192 self
.org_name
= value
193 elif index
== 'user':
195 elif index
== 'passwd':
199 elif index
== 'url_admin':
200 self
.url_admin
= value
202 raise KeyError("Invalid key '%s'" % str(index
))
204 def connect_as_admin(self
):
205 """ Method connect as admin user to vCloud director.
208 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
211 self
.logger
.debug("Logging in to a vca {} as admin.".format(self
.name
))
212 service_type
= STANDALONE
214 vca_admin
= VCA(host
=self
.url
,
215 username
=self
.admin_user
,
216 service_type
=STANDALONE
,
220 result
= vca_admin
.login(password
=self
.admin_password
, org
='System')
222 raise vimconn
.vimconnConnectionException(
223 "Can't connect to a vCloud director as: {}".format(self
.admin_user
))
224 result
= vca_admin
.login(token
=vca_admin
.token
, org
='System', org_url
=vca_admin
.vcloud_session
.org_url
)
227 "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self
.admin_user
))
232 """ Method connect as normal user to vCloud director.
235 The return vca object that letter can be used to connect to vCloud director as admin for VDC
238 service_type
= 'standalone'
241 self
.logger
.debug("Logging in to a vca {} as {} to datacenter {}.".format(self
.name
, self
.user
, self
.name
))
242 vca
= VCA(host
=self
.url
,
244 service_type
=STANDALONE
,
248 result
= vca
.login(password
=self
.passwd
, org
=self
.name
)
250 raise vimconn
.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self
.user
))
251 result
= vca
.login(token
=vca
.token
, org
=self
.name
, org_url
=vca
.vcloud_session
.org_url
)
253 self
.logger
.info("Successfully logged to a vcloud direct org: {} as user: {}".format(self
.name
, self
.user
))
257 def init_organization(self
):
258 """ Method initialize organization UUID and VDC parameters.
260 At bare minimum client must provide organization name that present in vCloud director and VDC.
262 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
263 The Org - UUID will be initialized at the run time if data center present in vCloud director.
266 The return vca object that letter can be used to connect to vcloud direct as admin
269 if self
.org_uuid
is None:
270 org_dict
= self
.get_org_list()
272 # we set org UUID at the init phase but we can do it only when we have valid credential.
273 if org_dict
[org
] == self
.org_name
:
275 self
.logger
.debug("Setting organization UUID {}".format(self
.org_uuid
))
279 raise vimconn
.vimconnException("Vcloud director organization {} not found".format(self
.org_name
))
281 # if well good we require for org details
282 org_details_dict
= self
.get_org(org_uuid
=self
.org_uuid
)
284 # we have two case if we want to initialize VDC ID or VDC name at run time
285 # tenant_name provided but no tenant id
286 print ("Setting vdc from name {} {} {} {}".format(self
.tenant_id
, self
.tenant_name
,
287 org_details_dict
.has_key('vdcs'), org_details_dict
))
288 if self
.tenant_id
is None and self
.tenant_name
is not None and org_details_dict
.has_key('vdcs'):
289 print ("Setting vdc from name")
290 vdcs_dict
= org_details_dict
['vdcs']
291 print ("Searching vdc UUUID")
292 for vdc
in vdcs_dict
:
293 if vdcs_dict
[vdc
] == self
.tenant_name
:
295 self
.logger
.debug("Setting vdc uuid {} for organization UUID {}".format(self
.tenant_id
,
299 raise vimconn
.vimconnException("Tenant name indicated but not present in vcloud director.")
300 # case two we have tenant_id but we don't have tenant name so we find and set it.
301 if self
.tenant_id
is not None and self
.tenant_name
is None and org_details_dict
.has_key('vdcs'):
302 print ("setting vdc from id")
303 vdcs_dict
= org_details_dict
['vdcs']
304 for vdc
in vdcs_dict
:
305 if vdc
== self
.tenant_id
:
306 self
.tenant_name
= vdcs_dict
[vdc
]
307 self
.logger
.debug("Setting vdc uuid {} for organization UUID {}".format(self
.tenant_id
,
311 raise vimconn
.vimconnException("Tenant id indicated but not present in vcloud director")
312 self
.logger
.debug("Setting organization uuid {}".format(self
.org_uuid
))
314 self
.logger
.debug("Failed initialize organization UUID for org {}".format(self
.org_name
))
315 self
.logger
.debug(traceback
.format_exc())
318 def new_tenant(self
, tenant_name
=None, tenant_description
=None):
319 """Adds a new tenant to VIM with this name and description
322 :param tenant_description:
323 :return: returns the tenant identifier
325 vdc_task
= self
.create_vdc(vdc_name
=tenant_name
)
326 if vdc_task
is not None:
327 vdc_uuid
, value
= vdc_task
.popitem()
328 self
.logger
.info("Crated new vdc {} and uuid: {}".format(tenant_name
, vdc_uuid
))
331 raise vimconn
.vimconnException("Failed create tenant {}".format(tenant_name
))
333 def delete_tenant(self
, tenant_id
, ):
334 """Delete a tenant from VIM"""
335 'Returns the tenant identifier'
336 raise vimconn
.vimconnNotImplemented("Should have implemented this")
338 def get_tenant_list(self
, filter_dict
={}):
339 '''Obtain tenants of VIM
340 filter_dict can contain the following keys:
341 name: filter by tenant name
342 id: filter by tenant uuid/id
344 Returns the tenant list of dictionaries:
345 [{'name':'<name>, 'id':'<id>, ...}, ...]
349 org_dict
= self
.get_org(self
.org_uuid
)
350 vdcs_dict
= org_dict
['vdcs']
355 entry
= {'name': vdcs_dict
[k
], 'id': k
}
356 filtered_entry
= entry
.copy()
357 filtered_dict
= set(entry
.keys()) - set(filter_dict
)
358 for unwanted_key
in filtered_dict
: del entry
[unwanted_key
]
359 if filter_dict
== entry
:
360 vdclist
.append(filtered_entry
)
362 self
.logger
.debug("Error in get_tenant_list()")
363 self
.logger
.debug(traceback
.format_exc())
368 def new_network(self
, net_name
, net_type
, ip_profile
=None, shared
=False):
369 '''Adds a tenant network to VIM
371 net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
372 ip_profile is a dict containing the IP parameters of the network
374 Returns the network identifier'''
377 "new_network tenant {} net_type {} ip_profile {} shared {}".format(net_name
, net_type
, ip_profile
, shared
))
383 network_uuid
= self
.create_network(network_name
=net_name
, isshared
=isshared
)
384 if network_uuid
is not None:
387 raise vimconn
.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name
))
389 def get_vcd_network_list(self
):
390 """ Method available organization for a logged in tenant
393 The return vca object that letter can be used to connect to vcloud direct as admin
396 self
.logger
.debug("get_vcd_network_list(): retrieving network list for vcd")
399 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
401 vdc
= vca
.get_vdc(self
.tenant_name
)
402 vdc_uuid
= vdc
.get_id().split(":")[3]
403 networks
= vca
.get_networks(vdc
.get_name())
406 for network
in networks
:
408 netid
= network
.get_id().split(":")
412 filter_dict
["name"] = network
.get_name()
413 filter_dict
["id"] = netid
[3]
414 filter_dict
["shared"] = network
.get_IsShared()
415 filter_dict
["tenant_id"] = vdc_uuid
416 if network
.get_status() == 1:
417 filter_dict
["admin_state_up"] = True
419 filter_dict
["admin_state_up"] = False
420 filter_dict
["status"] = "ACTIVE"
421 filter_dict
["type"] = "bridge"
422 network_list
.append(filter_dict
)
423 self
.logger
.debug("get_vcd_network_list adding entry {}".format(filter_dict
))
425 self
.logger
.debug("Error in get_vcd_network_list")
426 self
.logger
.debug(traceback
.format_exc())
429 self
.logger
.debug("get_vcd_network_list returning {}".format(network_list
))
432 def get_network_list(self
, filter_dict
={}):
433 '''Obtain tenant networks of VIM
435 name: network name OR/AND
436 id: network uuid OR/AND
437 shared: boolean OR/AND
438 tenant_id: tenant OR/AND
439 admin_state_up: boolean
442 [{key : value , key : value}]
444 Returns the network list of dictionaries:
445 [{<the fields at Filter_dict plus some VIM specific>}, ...]
451 raise vimconn
.vimconnConnectionException("self.connect() is failed")
453 vdc
= vca
.get_vdc(self
.tenant_name
)
454 vdcid
= vdc
.get_id().split(":")[3]
456 networks
= vca
.get_networks(vdc
.get_name())
460 for network
in networks
:
462 net_uuid
= network
.get_id().split(":")
463 if len(net_uuid
) != 4:
466 net_uuid
= net_uuid
[3]
468 self
.logger
.debug("Adding {} to a list vcd id {} network {}".format(net_uuid
,
471 filter_entry
["name"] = network
.get_name()
472 filter_entry
["id"] = net_uuid
473 filter_entry
["shared"] = network
.get_IsShared()
474 filter_entry
["tenant_id"] = vdcid
475 if network
.get_status() == 1:
476 filter_entry
["admin_state_up"] = True
478 filter_entry
["admin_state_up"] = False
479 filter_entry
["status"] = "ACTIVE"
480 filter_entry
["type"] = "bridge"
481 filtered_entry
= filter_entry
.copy()
483 # we remove all the key : value we dont' care and match only
485 filtered_dict
= set(filter_entry
.keys()) - set(filter_dict
)
486 for unwanted_key
in filtered_dict
: del filter_entry
[unwanted_key
]
487 if filter_dict
== filter_entry
:
488 network_list
.append(filtered_entry
)
490 self
.logger
.debug("Error in get_vcd_network_list")
491 self
.logger
.debug(traceback
.format_exc())
493 self
.logger
.debug("Returning {}".format(network_list
))
496 def get_network(self
, net_id
):
497 """Method bbtain network details of net_id VIM network
498 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
502 raise vimconn
.vimconnConnectionException("self.connect() is failed")
504 vdc
= vca
.get_vdc(self
.tenant_name
)
505 vdc_id
= vdc
.get_id().split(":")[3]
507 networks
= vca
.get_networks(vdc
.get_name())
511 for network
in networks
:
512 vdc_network_id
= network
.get_id().split(":")
513 if len(vdc_network_id
) == 4 and vdc_network_id
[3] == net_id
:
514 filter_dict
["name"] = network
.get_name()
515 filter_dict
["id"] = vdc_network_id
[3]
516 filter_dict
["shared"] = network
.get_IsShared()
517 filter_dict
["tenant_id"] = vdc_id
518 if network
.get_status() == 1:
519 filter_dict
["admin_state_up"] = True
521 filter_dict
["admin_state_up"] = False
522 filter_dict
["status"] = "ACTIVE"
523 filter_dict
["type"] = "bridge"
524 self
.logger
.debug("Returning {}".format(filter_dict
))
527 self
.logger
.debug("Error in get_network")
528 self
.logger
.debug(traceback
.format_exc())
532 def delete_network(self
, net_id
):
534 Method Deletes a tenant network from VIM, provide the network id.
536 Returns the network identifier or raise an exception
541 raise vimconn
.vimconnConnectionException("self.connect() for tenant {} is failed".format(self
.tenant_name
))
543 if self
.delete_network_action(net_id
):
546 raise vimconn
.vimconnNotFoundException("Network {} not found".format(net_id
))
548 def refresh_nets_status(self
, net_list
):
549 """Get the status of the networks
550 Params: the list of network identifiers
551 Returns a dictionary with:
552 net_id: #VIM id of this network
553 status: #Mandatory. Text with one of:
554 # DELETED (not found at vim)
555 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
556 # OTHER (Vim reported other status not understood)
557 # ERROR (VIM indicates an ERROR status)
558 # ACTIVE, INACTIVE, DOWN (admin down),
559 # BUILD (on building process)
561 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
562 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
566 # for net in net_list:
571 # vim vimcon failed == ERROR
574 raise vimconn
.vimconnConnectionException("self.connect() is failed")
581 vcd_network
= self
.get_vcd_network(network_uuid
=net
)
582 if vcd_network
is not None:
583 if vcd_network
['status'] == 1:
589 errormsg
= 'network not found'
590 dict_entry
['net'] = {'status': status
, 'error_msg': errormsg
,
591 'vm_info': yaml
.safe_dump(vcd_network
)}
593 self
.logger
.debug("Error in refresh_nets_status")
594 self
.logger
.debug(traceback
.format_exc())
598 def get_flavor(self
, flavor_id
):
599 """Obtain flavor details from the VIM
600 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
602 return flavorlist
[flavor_id
]
604 def new_flavor(self
, flavor_data
):
605 """Adds a tenant flavor to VIM
606 flavor_data contains a dictionary with information, keys:
608 ram: memory (cloud type) in MBytes
609 vpcus: cpus (cloud type)
610 extended: EPA parameters
611 - numas: #items requested in same NUMA
612 memory: number of 1G huge pages memory
613 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
614 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
615 - name: interface name
616 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
617 bandwidth: X Gbps; requested guarantee bandwidth
618 vpci: requested virtual PCI address
625 Returns the flavor identifier"""
627 # generate a new uuid put to internal dict and return it.
628 flavor_id
= uuid
.uuid4()
629 flavorlist
[str(flavor_id
)] = flavor_data
631 return str(flavor_id
)
633 def delete_flavor(self
, flavor_id
):
634 """Deletes a tenant flavor from VIM identify by its id
636 Returns the used id or raise an exception
639 # if key not present it will raise KeyError
640 # TODO check do I need raise any specific exception
641 flavorlist
.pop(flavor_id
, None)
644 def new_image(self
, image_dict
):
646 Adds a tenant image to VIM
648 200, image-id if the image is created
649 <0, message if there is an error
652 return self
.get_image_id_from_path(image_dict
['location'])
654 def delete_image(self
, image_id
):
655 '''Deletes a tenant image from VIM'''
656 '''Returns the HTTP response code and a message indicating details of the success or fail'''
657 raise vimconn
.vimconnNotImplemented("Should have implemented this")
659 def catalog_exists(self
, catalog_name
, catalogs
):
660 for catalog
in catalogs
:
661 if catalog
.name
== catalog_name
:
665 def create_vimcatalog(self
, vca
, catalog_name
):
666 """Create Catalog entry in VIM"""
667 task
= vca
.create_catalog(catalog_name
, catalog_name
)
668 result
= vca
.block_until_completed(task
)
671 catalogs
= vca
.get_catalogs()
672 return self
.catalog_exists(catalog_name
, catalogs
)
674 def upload_ovf(self
, vca
, catalog_name
, item_name
, media_file_name
, description
='', display_progress
=False,
675 chunk_bytes
=128 * 1024):
677 Uploads a OVF file to a vCloud catalog
679 :param catalog_name: (str): The name of the catalog to upload the media.
680 :param item_name: (str): The name of the media file in the catalog.
681 :param media_file_name: (str): The name of the local media file to upload.
682 :return: (bool) True if the media file was successfully uploaded, false otherwise.
684 os
.path
.isfile(media_file_name
)
685 statinfo
= os
.stat(media_file_name
)
688 # find a catalog entry where we upload OVF.
689 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
691 # if VCD can parse OVF we upload VMDK file
692 for catalog
in vca
.get_catalogs():
693 if catalog_name
!= catalog
.name
:
695 link
= filter(lambda link
: link
.get_type() == "application/vnd.vmware.vcloud.media+xml" and
696 link
.get_rel() == 'add', catalog
.get_Link())
697 assert len(link
) == 1
699 <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>
700 """ % (escape(item_name
), escape(description
))
701 headers
= vca
.vcloud_session
.get_vcloud_headers()
702 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
703 response
= Http
.post(link
[0].get_href(), headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=self
.logger
)
704 if response
.status_code
== requests
.codes
.created
:
705 catalogItem
= XmlElementTree
.fromstring(response
.content
)
706 entity
= [child
for child
in catalogItem
if
707 child
.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
708 href
= entity
.get('href')
710 response
= Http
.get(href
, headers
=vca
.vcloud_session
.get_vcloud_headers(),
711 verify
=vca
.verify
, logger
=self
.logger
)
713 if response
.status_code
== requests
.codes
.ok
:
714 media
= mediaType
.parseString(response
.content
, True)
716 filter(lambda link
: link
.get_rel() == 'upload:default',
717 media
.get_Files().get_File()[0].get_Link())[
719 headers
= vca
.vcloud_session
.get_vcloud_headers()
720 headers
['Content-Type'] = 'Content-Type text/xml'
721 response
= Http
.put(link
.get_href(), data
=open(media_file_name
, 'rb'), headers
=headers
,
722 verify
=vca
.verify
, logger
=self
.logger
)
723 if response
.status_code
!= requests
.codes
.ok
:
725 "Failed create vApp template for catalog name {} and image {}".format(catalog_name
,
729 # TODO fix this with aync block
732 self
.logger
.debug("Failed create vApp template for catalog name {} and image {}".
733 format(catalog_name
, media_file_name
))
735 # uploading VMDK file
736 # check status of OVF upload
737 response
= Http
.get(template
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
,
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())[
746 # The OVF file and VMDK must be in a same directory
747 head
, tail
= os
.path
.split(media_file_name
)
748 filevmdk
= head
+ '/' + os
.path
.basename(link
.get_href())
750 os
.path
.isfile(filevmdk
)
751 statinfo
= os
.stat(filevmdk
)
753 # TODO debug output remove it
754 # print media.get_Files().get_File()[0].get_Link()[0].get_href()
755 # print media.get_Files().get_File()[1].get_Link()[0].get_href()
756 # print link.get_href()
758 # in case first element is pointer to OVF.
759 hrefvmdk
= link
.get_href().replace("descriptor.ovf", "Cirros-disk1.vmdk")
761 f
= open(filevmdk
, 'rb')
762 bytes_transferred
= 0
763 while bytes_transferred
< statinfo
.st_size
:
764 my_bytes
= f
.read(chunk_bytes
)
765 if len(my_bytes
) <= chunk_bytes
:
766 headers
= vca
.vcloud_session
.get_vcloud_headers()
767 headers
['Content-Range'] = 'bytes %s-%s/%s' % (
768 bytes_transferred
, len(my_bytes
) - 1, statinfo
.st_size
)
769 headers
['Content-Length'] = str(len(my_bytes
))
770 response
= Http
.put(hrefvmdk
,
775 if response
.status_code
== requests
.codes
.ok
:
776 bytes_transferred
+= len(my_bytes
)
777 self
.logger
.debug('transferred %s of %s bytes' % (str(bytes_transferred
),
778 str(statinfo
.st_size
)))
780 self
.logger
.debug('file upload failed with error: [%s] %s' % (response
.status_code
,
786 self
.logger
.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
787 format(catalog_name
, media_file_name
))
790 self
.logger
.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name
, media_file_name
))
793 def upload_vimimage(self
, vca
, catalog_name
, media_name
, medial_file_name
):
794 """Upload media file"""
795 # TODO add named parameters for readbility
796 return self
.upload_ovf(vca
, catalog_name
, media_name
.split(".")[0], medial_file_name
, medial_file_name
, True)
798 def get_catalogid(self
, catalog_name
, catalogs
):
799 for catalog
in catalogs
:
800 if catalog
.name
== catalog_name
:
801 catalog_id
= catalog
.get_id().split(":")
805 def get_catalogbyid(self
, catalog_id
, catalogs
):
806 for catalog
in catalogs
:
807 catalogid
= catalog
.get_id().split(":")[3]
808 if catalogid
== catalog_id
:
812 def get_image_id_from_path(self
, path
):
813 '''Get the image id from image path in the VIM database'''
815 0,"Image not found" if there are no images with that path
816 1,image-id if there is one image with that path
817 <0,message if there was an error (Image not found, error contacting VIM, more than 1 image with that path, etc.)
822 raise vimconn
.vimconnConnectionException("self.connect() is failed")
824 self
.logger
.debug("get_image_id_from_path path {}".format(path
))
826 dirpath
, filename
= os
.path
.split(path
)
827 flname
, file_extension
= os
.path
.splitext(path
)
828 if file_extension
!= '.ovf':
829 self
.logger
.debug("Wrong file extension {}".format(file_extension
))
830 return -1, "Wrong container. vCloud director supports only OVF."
831 catalog_name
= os
.path
.splitext(filename
)[0]
833 self
.logger
.debug("File name {} Catalog Name {} file path {}".format(filename
, catalog_name
, path
))
834 self
.logger
.debug("Catalog name {}".format(catalog_name
))
836 catalogs
= vca
.get_catalogs()
837 if len(catalogs
) == 0:
838 self
.logger
.info("Creating new catalog entry {} in vcloud director".format(catalog_name
))
839 result
= self
.create_vimcatalog(vca
, catalog_name
)
841 return -1, "Failed create new catalog {} ".format(catalog_name
)
842 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
844 return -1, "Failed create vApp template for catalog {} ".format(catalog_name
)
845 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
847 for catalog
in catalogs
:
848 # search for existing catalog if we find same name we return ID
850 if catalog
.name
== catalog_name
:
851 self
.logger
.debug("Found existing catalog entry for {} catalog id {}".format(catalog_name
,
855 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
857 # if we didn't find existing catalog we create a new one.
858 self
.logger
.debug("Creating new catalog entry".format(catalog_name
))
859 result
= self
.create_vimcatalog(vca
, catalog_name
)
861 return -1, "Failed create new catalog {} ".format(catalog_name
)
862 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
864 return -1, "Failed create vApp template for catalog {} ".format(catalog_name
)
866 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
868 def get_vappid(self
, vdc
=None, vapp_name
=None):
869 """ Method takes vdc object and vApp name and returns vapp uuid or None
872 vca: Connector to VCA
874 vapp_name: is application vappp name identifier
877 The return vApp name otherwise None
880 """ Take vdc object and vApp name and returns vapp uuid or None
883 if vdc
is None or vapp_name
is None:
885 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
887 refs
= filter(lambda ref
: ref
.name
== vapp_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
888 vdc
.ResourceEntities
.ResourceEntity
)
890 return refs
[0].href
.split("vapp")[1][1:]
891 except Exception as e
:
892 self
.logger
.exception(e
)
896 def check_vapp(self
, vdc
, vapp_id
):
897 """ Take VDC object and vApp ID and return True if given ID in vCloud director
898 otherwise return False
901 """ Method Method returns vApp name from vCD and lookup done by vapp_id.
904 vca: Connector to VCA
906 vappid: vappid is application identifier
909 The return vApp name otherwise None
912 refs
= filter(lambda ref
:
913 ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
914 vdc
.ResourceEntities
.ResourceEntity
)
916 vappid
= ref
.href
.split("vapp")[1][1:]
917 # find vapp with respected vapp uuid
918 if vappid
== vapp_id
:
920 except Exception as e
:
921 self
.logger
.exception(e
)
925 def get_namebyvappid(self
, vca
, vdc
, vapp_id
):
926 """Method returns vApp name from vCD and lookup done by vapp_id.
929 vca: Connector to VCA
931 vapp_id: vappid is application identifier
934 The return vApp name otherwise None
938 refs
= filter(lambda ref
: ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
939 vdc
.ResourceEntities
.ResourceEntity
)
941 # we care only about UUID the rest doesn't matter
942 vappid
= ref
.href
.split("vapp")[1][1:]
943 if vappid
== vapp_id
:
944 response
= Http
.get(ref
.href
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
,
946 tree
= XmlElementTree
.fromstring(response
.content
)
947 return tree
.attrib
['name']
948 except Exception as e
:
949 self
.logger
.exception(e
)
953 def new_vminstance(self
, name
, description
, start
, image_id
, flavor_id
, net_list
, cloud_config
=None):
954 """Adds a VM instance to VIM
956 start: indicates if VM must start or boot in pause mode. Ignored
957 image_id,flavor_id: image and flavor uuid
958 net_list: list of interfaces, each one is a dictionary with:
960 net_id: network uuid to connect
961 vpci: virtual vcpi to assign
962 model: interface model, virtio, e2000, ...
964 use: 'data', 'bridge', 'mgmt'
965 type: 'virtual', 'PF', 'VF', 'VFnotShared'
966 vim_id: filled/added by this function
967 cloud_config: can be a text script to be passed directly to cloud-init,
968 or an object to inject users and ssh keys with format:
969 key-pairs: [] list of keys to install to the default user
970 users: [{ name, key-pairs: []}] list of users to add with their key-pair
971 #TODO ip, security groups
972 Returns >=0, the instance identifier
976 self
.logger
.info("Creating new instance for entry".format(name
))
977 self
.logger
.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
978 format(description
, start
, image_id
, flavor_id
, net_list
, cloud_config
))
981 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
983 # if vm already deployed we return existing uuid
984 vapp_uuid
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
985 if vapp_uuid
is not None:
988 # we check for presence of VDC, Catalog entry and Flavor.
989 vdc
= vca
.get_vdc(self
.tenant_name
)
991 raise vimconn
.vimconnUnexpectedResponse(
992 "new_vminstance(): Failed create vApp {}: (Failed reprieve VDC information)".format(name
))
993 catalogs
= vca
.get_catalogs()
995 raise vimconn
.vimconnUnexpectedResponse(
996 "new_vminstance(): Failed create vApp {}: Failed create vApp {}: (Failed reprieve Catalog information)".format(
999 flavor
= flavorlist
[flavor_id
]
1000 if catalogs
is None:
1001 raise vimconn
.vimconnUnexpectedResponse(
1002 "new_vminstance(): Failed create vApp {}: (Failed reprieve Flavor information)".format(name
))
1004 # image upload creates template name as catalog name space Template.
1005 templateName
= self
.get_catalogbyid(image_id
, catalogs
) + ' Template'
1010 # client must provide at least one entry in net_list if not we report error
1011 primary_net
= net_list
[0]
1012 if primary_net
is None:
1013 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name
))
1015 primary_net_id
= primary_net
['net_id']
1016 primary_net_name
= self
.get_network_name_by_id(primary_net_id
)
1017 network_mode
= primary_net
['use']
1019 # use: 'data', 'bridge', 'mgmt'
1020 # create vApp. Set vcpu and ram based on flavor id.
1021 vapptask
= vca
.create_vapp(self
.tenant_name
, name
, templateName
,
1022 self
.get_catalogbyid(image_id
, catalogs
),
1023 network_name
=primary_net_name
,
1024 network_mode
='bridged',
1026 vm_cpus
=flavor
['vcpus'],
1027 vm_memory
=flavor
['ram'])
1029 if vapptask
is None or vapptask
is False:
1030 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(name
))
1031 if type(vapptask
) is VappTask
:
1032 vca
.block_until_completed(vapptask
)
1034 # we should have now vapp in undeployed state.
1035 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), name
)
1037 raise vimconn
.vimconnUnexpectedResponse(
1038 "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(name
))
1043 for net
in net_list
:
1044 # openmano uses network id in UUID format.
1045 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
1046 interface_net_id
= net
['net_id']
1047 interface_net_name
= self
.get_network_name_by_id(interface_net_id
)
1048 interface_network_mode
= net
['use']
1050 if primary_net_name
is not None:
1051 nets
= filter(lambda n
: n
.name
== interface_net_name
, vca
.get_networks(self
.tenant_name
))
1053 task
= vapp
.connect_to_network(nets
[0].name
, nets
[0].href
)
1054 if type(task
) is GenericTask
:
1055 vca
.block_until_completed(task
)
1056 # connect network to VM
1057 # TODO figure out mapping between openmano representation to vCloud director.
1058 # one idea use first nic as managment DHCP all remaining in bridge mode
1059 task
= vapp
.connect_vms(nets
[0].name
, connection_index
=nicIndex
,
1060 connections_primary_index
=nicIndex
,
1061 ip_allocation_mode
='DHCP')
1062 if type(task
) is GenericTask
:
1063 vca
.block_until_completed(task
)
1066 # it might be a case if specific mandatory entry in dict is empty
1067 self
.logger
.debug("Key error {}".format(KeyError.message
))
1068 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name
))
1070 # deploy and power on vm
1071 task
= vapp
.poweron()
1072 if type(task
) is TaskType
:
1073 vca
.block_until_completed(task
)
1074 deploytask
= vapp
.deploy(powerOn
='True')
1075 if type(task
) is TaskType
:
1076 vca
.block_until_completed(deploytask
)
1078 # check if vApp deployed and if that the case return vApp UUID otherwise -1
1079 vapp_uuid
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
1080 if vapp_uuid
is not None:
1083 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name
))
1087 ## based on current discussion
1091 # created: '2016-09-08T11:51:58'
1092 # description: simple-instance.linux1.1
1093 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
1094 # hostId: e836c036-74e7-11e6-b249-0800273e724c
1095 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
1100 def get_vminstance(self
, vim_vm_uuid
):
1101 '''Returns the VM instance information from VIM'''
1103 self
.logger
.debug("Client requesting vm instance {} ".format(vim_vm_uuid
))
1104 vca
= self
.connect()
1106 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1108 vdc
= vca
.get_vdc(self
.tenant_name
)
1110 return -1, "Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
)
1112 vm_name
= self
.get_namebyvappid(vca
, vdc
, vim_vm_uuid
)
1114 self
.logger
.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid
))
1115 return None, "Failed to get vApp name by UUID {}".format(vim_vm_uuid
)
1117 the_vapp
= vca
.get_vapp(vdc
, vm_name
)
1118 vm_info
= the_vapp
.get_vms_details()
1120 vm_dict
= {'description': vm_info
[0]['name'], 'status': vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()],
1121 'error_msg': vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()],
1122 'vim_info': yaml
.safe_dump(the_vapp
.get_vms_details()), 'interfaces': []}
1125 vm_app_networks
= the_vapp
.get_vms_network_info()
1129 org_network_dict
= self
.get_org(self
.org_uuid
)['networks']
1130 for vapp_network
in vm_app_networks
:
1131 for vm_network
in vapp_network
:
1132 if vm_network
['name'] == vm_name
:
1134 # interface['vim_info'] = yaml.safe_dump(vm_network)
1135 interface
["mac_address"] = vm_network
['mac']
1136 for net_uuid
in org_network_dict
:
1137 if org_network_dict
[net_uuid
] == vm_network
['network_name']:
1138 interface
["vim_net_id"] = net_uuid
1139 interface
["vim_interface_id"] = vm_network
['network_name']
1140 interface
['ip_address'] = vm_network
['ip']
1141 interfaces
.append(interface
)
1143 self
.logger
.debug("Error in respond {}".format(KeyError.message
))
1144 self
.logger
.debug(traceback
.format_exc())
1146 vm_dict
['interfaces'] = interfaces
1150 def delete_vminstance(self
, vm__vim_uuid
):
1151 """Method poweroff and remove VM instance from vcloud director network.
1154 vm__vim_uuid: VM UUID
1157 Returns the instance identifier
1160 self
.logger
.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid
))
1161 vca
= self
.connect()
1163 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1165 vdc
= vca
.get_vdc(self
.tenant_name
)
1167 self
.logger
.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
1169 raise vimconn
.vimconnException(
1170 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1173 vapp_name
= self
.get_namebyvappid(vca
, vdc
, vm__vim_uuid
)
1174 if vapp_name
is None:
1175 self
.logger
.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1176 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
)
1178 self
.logger
.info("Deleting vApp {} and UUID {}".format(vapp_name
, vm__vim_uuid
))
1180 # Delete vApp and wait for status change if task executed and vApp is None.
1181 # We successfully delete vApp from vCloud
1182 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
)
1183 # poweroff vapp / undeploy and delete
1184 power_off_task
= vapp
.poweroff()
1185 if type(power_off_task
) is GenericTask
:
1186 vca
.block_until_completed(power_off_task
)
1188 if not power_off_task
:
1189 self
.logger
.debug("delete_vminstance(): Failed power off VM uuid {} ".format(vm__vim_uuid
))
1192 if vapp
.me
.deployed
:
1193 undeploy_task
= vapp
.undeploy()
1194 if type(undeploy_task
) is GenericTask
:
1196 while retry
<= DELETE_INSTANCE_RETRY
:
1197 result
= vca
.block_until_completed(undeploy_task
)
1205 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
)
1206 if vapp
is not None:
1207 delete_task
= vapp
.delete()
1209 while retry
<= DELETE_INSTANCE_RETRY
:
1210 task
= vapp
.delete()
1211 if type(task
) is GenericTask
:
1212 vca
.block_until_completed(delete_task
)
1214 self
.logger
.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid
))
1218 self
.logger
.debug(traceback
.format_exc())
1219 raise vimconn
.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid
))
1221 if vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
) is None:
1224 raise vimconn
.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid
))
1226 def refresh_vms_status(self
, vm_list
):
1227 """Get the status of the virtual machines and their interfaces/ports
1228 Params: the list of VM identifiers
1229 Returns a dictionary with:
1230 vm_id: #VIM id of this Virtual Machine
1231 status: #Mandatory. Text with one of:
1232 # DELETED (not found at vim)
1233 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1234 # OTHER (Vim reported other status not understood)
1235 # ERROR (VIM indicates an ERROR status)
1236 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
1237 # CREATING (on building process), ERROR
1238 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
1240 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1241 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1243 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1244 mac_address: #Text format XX:XX:XX:XX:XX:XX
1245 vim_net_id: #network id where this interface is connected
1246 vim_interface_id: #interface/port VIM id
1247 ip_address: #null, or text with IPv4, IPv6 address
1250 self
.logger
.debug("Client requesting refresh vm status for {} ".format(vm_list
))
1251 vca
= self
.connect()
1253 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1255 vdc
= vca
.get_vdc(self
.tenant_name
)
1257 raise vimconn
.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1260 for vmuuid
in vm_list
:
1261 vmname
= self
.get_namebyvappid(vca
, vdc
, vmuuid
)
1262 if vmname
is not None:
1264 the_vapp
= vca
.get_vapp(vdc
, vmname
)
1265 vm_info
= the_vapp
.get_vms_details()
1266 vm_status
= vm_info
[0]['status']
1268 vm_dict
= {'status': None, 'error_msg': None, 'vim_info': None, 'interfaces': []}
1269 vm_dict
['status'] = vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()]
1270 vm_dict
['error_msg'] = vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()]
1271 vm_dict
['vim_info'] = yaml
.safe_dump(the_vapp
.get_vms_details())
1275 vm_app_networks
= the_vapp
.get_vms_network_info()
1276 for vapp_network
in vm_app_networks
:
1277 for vm_network
in vapp_network
:
1278 if vm_network
['name'] == vmname
:
1280 # interface['vim_info'] = yaml.safe_dump(vm_network)
1281 interface
["mac_address"] = vm_network
['mac']
1282 interface
["vim_net_id"] = self
.get_network_name_by_id(vm_network
['network_name'])
1283 interface
["vim_interface_id"] = vm_network
['network_name']
1284 interface
['ip_address'] = vm_network
['ip']
1285 vm_dict
["interfaces"].append(interface
)
1286 # add a vm to vm dict
1287 vms_dict
.setdefault(vmuuid
, vm_dict
)
1289 self
.logger
.debug("Error in respond {}".format(KeyError.message
))
1290 self
.logger
.debug(traceback
.format_exc())
1294 def action_vminstance(self
, vm__vim_uuid
=None, action_dict
=None):
1295 """Send and action over a VM instance from VIM
1296 Returns the vm_id if the action was successfully sent to the VIM"""
1298 self
.logger
.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid
, action_dict
))
1299 if vm__vim_uuid
is None or action_dict
is None:
1300 raise vimconn
.vimconnException("Invalid request. VM id or action is None.")
1302 vca
= self
.connect()
1304 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1306 vdc
= vca
.get_vdc(self
.tenant_name
)
1308 return -1, "Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
)
1310 vapp_name
= self
.get_namebyvappid(vca
, vdc
, vm__vim_uuid
)
1311 if vapp_name
is None:
1312 self
.logger
.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1313 raise vimconn
.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1315 self
.logger
.info("Action_vminstance vApp {} and UUID {}".format(vapp_name
, vm__vim_uuid
))
1318 the_vapp
= vca
.get_vapp(vdc
, vapp_name
)
1319 # TODO fix all status
1320 if "start" in action_dict
:
1321 if action_dict
["start"] == "rebuild":
1322 the_vapp
.deploy(powerOn
=True)
1324 vm_info
= the_vapp
.get_vms_details()
1325 vm_status
= vm_info
[0]['status']
1326 if vm_status
== "Suspended":
1328 elif vm_status
.status
== "Powered off":
1330 elif "pause" in action_dict
:
1333 elif "resume" in action_dict
:
1336 elif "shutoff" in action_dict
or "shutdown" in action_dict
:
1338 elif "forceOff" in action_dict
:
1340 elif "terminate" in action_dict
:
1342 # elif "createImage" in action_dict:
1343 # server.create_image()
1349 def get_vminstance_console(self
, vm_id
, console_type
="vnc"):
1351 Get a console for the virtual machine
1353 vm_id: uuid of the VM
1354 console_type, can be:
1355 "novnc" (by default), "xvpvnc" for VNC types,
1356 "rdp-html5" for RDP types, "spice-html5" for SPICE types
1357 Returns dict with the console parameters:
1358 protocol: ssh, ftp, http, https, ...
1359 server: usually ip address
1360 port: the http, ssh, ... port
1361 suffix: extra text, e.g. the http path and query string
1363 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1365 # NOT USED METHODS in current version
1367 def host_vim2gui(self
, host
, server_dict
):
1368 '''Transform host dictionary from VIM format to GUI format,
1369 and append to the server_dict
1371 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1373 def get_hosts_info(self
):
1374 '''Get the information of deployed hosts
1375 Returns the hosts content'''
1376 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1378 def get_hosts(self
, vim_tenant
):
1379 '''Get the hosts and deployed instances
1380 Returns the hosts content'''
1381 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1383 def get_processor_rankings(self
):
1384 '''Get the processor rankings in the VIM database'''
1385 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1387 def new_host(self
, host_data
):
1388 '''Adds a new host to VIM'''
1389 '''Returns status code of the VIM response'''
1390 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1392 def new_external_port(self
, port_data
):
1393 '''Adds a external port to VIM'''
1394 '''Returns the port identifier'''
1395 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1397 def new_external_network(self
, net_name
, net_type
):
1398 '''Adds a external network to VIM (shared)'''
1399 '''Returns the network identifier'''
1400 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1402 def connect_port_network(self
, port_id
, network_id
, admin
=False):
1403 '''Connects a external port to a network'''
1404 '''Returns status code of the VIM response'''
1405 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1407 def new_vminstancefromJSON(self
, vm_data
):
1408 '''Adds a VM instance to VIM'''
1409 '''Returns the instance identifier'''
1410 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1412 def get_network_name_by_id(self
, network_name
=None):
1413 """Method gets vcloud director network named based on supplied uuid.
1416 network_name: network_id
1419 The return network name.
1422 vca
= self
.connect()
1424 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1426 if network_name
is None:
1430 org_network_dict
= self
.get_org(self
.org_uuid
)['networks']
1431 for net_uuid
in org_network_dict
:
1432 if org_network_dict
[net_uuid
] == network_name
:
1435 self
.logger
.debug("Exception in get_network_name_by_id")
1436 self
.logger
.debug(traceback
.format_exc())
1440 def list_org_action(self
):
1442 Method leverages vCloud director and query for available organization for particular user
1445 vca - is active VCA connection.
1446 vdc_name - is a vdc name that will be used to query vms action
1449 The return XML respond
1452 vca
= self
.connect()
1454 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1456 url_list
= [vca
.host
, '/api/org']
1457 vm_list_rest_call
= ''.join(url_list
)
1459 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1460 response
= Http
.get(url
=vm_list_rest_call
,
1461 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1464 if response
.status_code
== requests
.codes
.ok
:
1465 return response
.content
1469 def get_org_action(self
, org_uuid
=None):
1471 Method leverages vCloud director and retrieve available object fdr organization.
1474 vca - is active VCA connection.
1475 vdc_name - is a vdc name that will be used to query vms action
1478 The return XML respond
1481 vca
= self
.connect()
1483 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1485 if org_uuid
is None:
1488 url_list
= [vca
.host
, '/api/org/', org_uuid
]
1489 vm_list_rest_call
= ''.join(url_list
)
1491 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1492 response
= Http
.get(url
=vm_list_rest_call
,
1493 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1496 if response
.status_code
== requests
.codes
.ok
:
1497 return response
.content
1501 def get_org(self
, org_uuid
=None):
1503 Method retrieves available organization in vCloud Director
1506 vca - is active VCA connection.
1507 vdc_name - is a vdc name that will be used to query vms action
1510 The return dictionary and key for each entry vapp UUID
1515 vca
= self
.connect()
1517 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1519 if org_uuid
is None:
1522 content
= self
.get_org_action(org_uuid
=org_uuid
)
1527 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1528 for child
in vm_list_xmlroot
:
1529 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
1530 vdc_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1531 org_dict
['vdcs'] = vdc_list
1532 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
1533 network_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1534 org_dict
['networks'] = network_list
1535 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
1536 catalog_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1537 org_dict
['catalogs'] = catalog_list
1543 def get_org_list(self
):
1545 Method retrieves available organization in vCloud Director
1548 vca - is active VCA connection.
1551 The return dictionary and key for each entry VDC UUID
1555 vca
= self
.connect()
1557 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1559 content
= self
.list_org_action()
1561 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1562 for vm_xml
in vm_list_xmlroot
:
1563 if vm_xml
.tag
.split("}")[1] == 'Org':
1564 org_uuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1565 org_dict
[org_uuid
[0]] = vm_xml
.attrib
['name']
1571 def vms_view_action(self
, vdc_name
=None):
1572 """ Method leverages vCloud director vms query call
1575 vca - is active VCA connection.
1576 vdc_name - is a vdc name that will be used to query vms action
1579 The return XML respond
1581 vca
= self
.connect()
1582 if vdc_name
is None:
1585 url_list
= [vca
.host
, '/api/vms/query']
1586 vm_list_rest_call
= ''.join(url_list
)
1588 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1589 refs
= filter(lambda ref
: ref
.name
== vdc_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vdc+xml',
1590 vca
.vcloud_session
.organization
.Link
)
1592 response
= Http
.get(url
=vm_list_rest_call
,
1593 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1596 if response
.status_code
== requests
.codes
.ok
:
1597 return response
.content
1601 def get_vapp_list(self
, vdc_name
=None):
1603 Method retrieves vApp list deployed vCloud director and returns a dictionary
1604 contains a list of all vapp deployed for queried VDC.
1605 The key for a dictionary is vApp UUID
1609 vca - is active VCA connection.
1610 vdc_name - is a vdc name that will be used to query vms action
1613 The return dictionary and key for each entry vapp UUID
1617 if vdc_name
is None:
1620 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1622 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1623 for vm_xml
in vm_list_xmlroot
:
1624 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1625 if vm_xml
.attrib
['isVAppTemplate'] == 'true':
1626 rawuuid
= vm_xml
.attrib
['container'].split('/')[-1:]
1627 if 'vappTemplate-' in rawuuid
[0]:
1628 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1629 # vm and use raw UUID as key
1630 vapp_dict
[rawuuid
[0][13:]] = vm_xml
.attrib
1636 def get_vm_list(self
, vdc_name
=None):
1638 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1639 contains a list of all VM's deployed for queried VDC.
1640 The key for a dictionary is VM UUID
1644 vca - is active VCA connection.
1645 vdc_name - is a vdc name that will be used to query vms action
1648 The return dictionary and key for each entry vapp UUID
1652 if vdc_name
is None:
1655 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1657 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1658 for vm_xml
in vm_list_xmlroot
:
1659 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1660 if vm_xml
.attrib
['isVAppTemplate'] == 'false':
1661 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1662 if 'vm-' in rawuuid
[0]:
1663 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1664 # vm and use raw UUID as key
1665 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1671 def get_vapp(self
, vdc_name
=None, vapp_name
=None, isuuid
=False):
1673 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1674 contains a list of all VM's deployed for queried VDC.
1675 The key for a dictionary is VM UUID
1679 vca - is active VCA connection.
1680 vdc_name - is a vdc name that will be used to query vms action
1683 The return dictionary and key for each entry vapp UUID
1686 vca
= self
.connect()
1688 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1690 if vdc_name
is None:
1693 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1695 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1696 for vm_xml
in vm_list_xmlroot
:
1697 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1699 # lookup done by UUID
1700 if vapp_name
in vm_xml
.attrib
['container']:
1701 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1702 if 'vm-' in rawuuid
[0]:
1703 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1704 # vm and use raw UUID as key
1705 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1706 # lookup done by Name
1708 if vapp_name
in vm_xml
.attrib
['name']:
1709 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1710 if 'vm-' in rawuuid
[0]:
1711 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1712 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1713 # vm and use raw UUID as key
1719 def get_network_action(self
, network_uuid
=None):
1721 Method leverages vCloud director and query network based on network uuid
1724 vca - is active VCA connection.
1725 network_uuid - is a network uuid
1728 The return XML respond
1731 vca
= self
.connect()
1733 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1735 if network_uuid
is None:
1738 url_list
= [vca
.host
, '/api/network/', network_uuid
]
1739 vm_list_rest_call
= ''.join(url_list
)
1741 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1742 response
= Http
.get(url
=vm_list_rest_call
,
1743 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1746 if response
.status_code
== requests
.codes
.ok
:
1747 return response
.content
1751 def get_vcd_network(self
, network_uuid
=None):
1753 Method retrieves available network from vCloud Director
1756 network_uuid - is VCD network UUID
1758 Each element serialized as key : value pair
1760 Following keys available for access. network_configuration['Gateway'}
1764 <IsInherited>true</IsInherited>
1765 <Gateway>172.16.252.100</Gateway>
1766 <Netmask>255.255.255.0</Netmask>
1767 <Dns1>172.16.254.201</Dns1>
1768 <Dns2>172.16.254.202</Dns2>
1769 <DnsSuffix>vmwarelab.edu</DnsSuffix>
1770 <IsEnabled>true</IsEnabled>
1773 <StartAddress>172.16.252.1</StartAddress>
1774 <EndAddress>172.16.252.99</EndAddress>
1779 <FenceMode>bridged</FenceMode>
1782 The return dictionary and key for each entry vapp UUID
1785 network_configuration
= {}
1786 if network_uuid
is None:
1789 content
= self
.get_network_action(network_uuid
=network_uuid
)
1791 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1793 network_configuration
['status'] = vm_list_xmlroot
.get("status")
1794 network_configuration
['name'] = vm_list_xmlroot
.get("name")
1795 network_configuration
['uuid'] = vm_list_xmlroot
.get("id").split(":")[3]
1797 for child
in vm_list_xmlroot
:
1798 if child
.tag
.split("}")[1] == 'IsShared':
1799 network_configuration
['isShared'] = child
.text
.strip()
1800 if child
.tag
.split("}")[1] == 'Configuration':
1801 for configuration
in child
.iter():
1802 tagKey
= configuration
.tag
.split("}")[1].strip()
1804 network_configuration
[tagKey
] = configuration
.text
.strip()
1805 return network_configuration
1809 return network_configuration
1811 def delete_network_action(self
, network_uuid
=None):
1813 Method delete given network from vCloud director
1816 network_uuid - is a network uuid that client wish to delete
1819 The return None or XML respond or false
1822 vca
= self
.connect_as_admin()
1824 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1825 if network_uuid
is None:
1828 url_list
= [vca
.host
, '/api/admin/network/', network_uuid
]
1829 vm_list_rest_call
= ''.join(url_list
)
1831 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1832 response
= Http
.delete(url
=vm_list_rest_call
,
1833 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1837 if response
.status_code
== 202:
1842 def create_network(self
, network_name
=None, parent_network_uuid
=None, isshared
='true'):
1844 Method create network in vCloud director
1847 network_name - is network name to be created.
1848 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1849 It optional attribute. by default if no parent network indicate the first available will be used.
1852 The return network uuid or return None
1855 content
= self
.create_network_rest(network_name
=network_name
,
1856 parent_network_uuid
=parent_network_uuid
,
1859 self
.logger
.debug("Failed create network {}.".format(network_name
))
1863 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1864 vcd_uuid
= vm_list_xmlroot
.get('id').split(":")
1865 if len(vcd_uuid
) == 4:
1866 self
.logger
.info("Create new network name: {} uuid: {}".format(network_name
, vcd_uuid
[3]))
1869 self
.logger
.debug("Failed create network {}".format(network_name
))
1872 def create_network_rest(self
, network_name
=None, parent_network_uuid
=None, isshared
='true'):
1874 Method create network in vCloud director
1877 network_name - is network name to be created.
1878 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1879 It optional attribute. by default if no parent network indicate the first available will be used.
1882 The return network uuid or return None
1885 vca
= self
.connect_as_admin()
1887 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1888 if network_name
is None:
1891 url_list
= [vca
.host
, '/api/admin/vdc/', self
.tenant_id
]
1892 vm_list_rest_call
= ''.join(url_list
)
1893 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1894 response
= Http
.get(url
=vm_list_rest_call
,
1895 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1899 provider_network
= None
1900 available_networks
= None
1901 add_vdc_rest_url
= None
1903 if response
.status_code
!= requests
.codes
.ok
:
1904 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
1905 response
.status_code
))
1909 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
1910 for child
in vm_list_xmlroot
:
1911 if child
.tag
.split("}")[1] == 'ProviderVdcReference':
1912 provider_network
= child
.attrib
.get('href')
1913 # application/vnd.vmware.admin.providervdc+xml
1914 if child
.tag
.split("}")[1] == 'Link':
1915 if child
.attrib
.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
1916 and child
.attrib
.get('rel') == 'add':
1917 add_vdc_rest_url
= child
.attrib
.get('href')
1919 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
1920 self
.logger
.debug("Respond body {}".format(response
.content
))
1923 # find pvdc provided available network
1924 response
= Http
.get(url
=provider_network
,
1925 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1928 if response
.status_code
!= requests
.codes
.ok
:
1929 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
1930 response
.status_code
))
1933 # available_networks.split("/")[-1]
1935 if parent_network_uuid
is None:
1937 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
1938 for child
in vm_list_xmlroot
.iter():
1939 if child
.tag
.split("}")[1] == 'AvailableNetworks':
1940 for networks
in child
.iter():
1941 # application/vnd.vmware.admin.network+xml
1942 if networks
.attrib
.get('href') is not None:
1943 available_networks
= networks
.attrib
.get('href')
1948 # either use client provided UUID or search for a first available
1949 # if both are not defined we return none
1950 if parent_network_uuid
is not None:
1951 url_list
= [vca
.host
, '/api/admin/network/', parent_network_uuid
]
1952 add_vdc_rest_url
= ''.join(url_list
)
1954 # return response.content
1955 data
= """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
1956 <Description>Openmano created</Description>
1958 <ParentNetwork href="{1:s}"/>
1959 <FenceMode>{2:s}</FenceMode>
1961 <IsShared>{3:s}</IsShared>
1962 </OrgVdcNetwork> """.format(escape(network_name
), available_networks
, "bridged", isshared
)
1964 headers
= vca
.vcloud_session
.get_vcloud_headers()
1965 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
1966 response
= Http
.post(url
=add_vdc_rest_url
, headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=vca
.logger
)
1968 # if we all ok we respond with content otherwise by default None
1969 if response
.status_code
== 201:
1970 return response
.content
1973 def get_provider_rest(self
, vca
=None):
1975 Method gets provider vdc view from vcloud director
1978 network_name - is network name to be created.
1979 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1980 It optional attribute. by default if no parent network indicate the first available will be used.
1983 The return xml content of respond or None
1986 url_list
= [vca
.host
, '/api/admin']
1987 response
= Http
.get(url
=''.join(url_list
),
1988 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1992 if response
.status_code
== requests
.codes
.ok
:
1993 return response
.content
1996 def create_vdc(self
, vdc_name
=None):
2000 xml_content
= self
.create_vdc_from_tmpl_rest(vdc_name
=vdc_name
)
2001 if xml_content
is not None:
2004 task_resp_xmlroot
= XmlElementTree
.fromstring(xml_content
)
2005 for child
in task_resp_xmlroot
:
2006 if child
.tag
.split("}")[1] == 'Owner':
2007 vdc_id
= child
.attrib
.get('href').split("/")[-1]
2008 vdc_dict
[vdc_id
] = task_resp_xmlroot
.get('href')
2011 self
.logger
.debug("Respond body {}".format(xml_content
))
2015 def create_vdc_from_tmpl_rest(self
, vdc_name
=None):
2017 Method create vdc in vCloud director based on VDC template.
2018 it uses pre-defined template that must be named openmano
2021 vdc_name - name of a new vdc.
2024 The return xml content of respond or None
2027 self
.logger
.info("Creating new vdc {}".format(vdc_name
))
2028 print ("Creating new vdc {}".format(vdc_name
))
2030 vca
= self
.connect()
2032 raise vimconn
.vimconnConnectionException("self.connect() is failed")
2033 if vdc_name
is None:
2036 url_list
= [vca
.host
, '/api/vdcTemplates']
2037 vm_list_rest_call
= ''.join(url_list
)
2038 response
= Http
.get(url
=vm_list_rest_call
,
2039 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2043 # container url to a template
2044 vdc_template_ref
= None
2046 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2047 for child
in vm_list_xmlroot
:
2048 # application/vnd.vmware.admin.providervdc+xml
2049 # we need find a template from witch we instantiate VDC
2050 if child
.tag
.split("}")[1] == 'VdcTemplate':
2051 if child
.attrib
.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child
.attrib
.get(
2052 'name') == 'openmano':
2053 vdc_template_ref
= child
.attrib
.get('href')
2055 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2056 self
.logger
.debug("Respond body {}".format(response
.content
))
2059 # if we didn't found required pre defined template we return None
2060 if vdc_template_ref
is None:
2065 url_list
= [vca
.host
, '/api/org/', self
.org_uuid
, '/action/instantiate']
2066 vm_list_rest_call
= ''.join(url_list
)
2067 data
= """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2068 <Source href="{1:s}"></Source>
2069 <Description>opnemano</Description>
2070 </InstantiateVdcTemplateParams>""".format(vdc_name
, vdc_template_ref
)
2071 headers
= vca
.vcloud_session
.get_vcloud_headers()
2072 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
2073 response
= Http
.post(url
=vm_list_rest_call
, headers
=headers
, data
=data
, verify
=vca
.verify
,
2075 # if we all ok we respond with content otherwise by default None
2076 if response
.status_code
>= 200 and response
.status_code
< 300:
2077 return response
.content
2080 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2081 self
.logger
.debug("Respond body {}".format(response
.content
))
2085 def create_vdc_rest(self
, vdc_name
=None):
2087 Method create network in vCloud director
2090 network_name - is network name to be created.
2091 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2092 It optional attribute. by default if no parent network indicate the first available will be used.
2095 The return network uuid or return None
2098 self
.logger
.info("Creating new vdc {}".format(vdc_name
))
2099 print ("Creating new vdc {}".format(vdc_name
))
2101 vca
= self
.connect_as_admin()
2103 raise vimconn
.vimconnConnectionException("self.connect() is failed")
2104 if vdc_name
is None:
2107 url_list
= [vca
.host
, '/api/admin/org/', self
.org_uuid
]
2108 vm_list_rest_call
= ''.join(url_list
)
2109 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
2110 response
= Http
.get(url
=vm_list_rest_call
,
2111 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2115 provider_vdc_ref
= None
2116 add_vdc_rest_url
= None
2117 available_networks
= None
2119 if response
.status_code
!= requests
.codes
.ok
:
2120 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
2121 response
.status_code
))
2125 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2126 for child
in vm_list_xmlroot
:
2127 # application/vnd.vmware.admin.providervdc+xml
2128 if child
.tag
.split("}")[1] == 'Link':
2129 if child
.attrib
.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
2130 and child
.attrib
.get('rel') == 'add':
2131 add_vdc_rest_url
= child
.attrib
.get('href')
2133 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2134 self
.logger
.debug("Respond body {}".format(response
.content
))
2137 response
= self
.get_provider_rest(vca
=vca
)
2140 vm_list_xmlroot
= XmlElementTree
.fromstring(response
)
2141 for child
in vm_list_xmlroot
:
2142 if child
.tag
.split("}")[1] == 'ProviderVdcReferences':
2143 for sub_child
in child
:
2144 provider_vdc_ref
= sub_child
.attrib
.get('href')
2146 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2147 self
.logger
.debug("Respond body {}".format(response
))
2150 print "Add vdc {}".format(add_vdc_rest_url
)
2151 print "Provider ref {}".format(provider_vdc_ref
)
2152 if add_vdc_rest_url
is not None and provider_vdc_ref
is not None:
2153 data
= """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
2154 <AllocationModel>ReservationPool</AllocationModel>
2155 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
2156 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
2157 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
2158 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
2159 <ProviderVdcReference
2160 name="Main Provider"
2162 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name
),
2167 headers
= vca
.vcloud_session
.get_vcloud_headers()
2168 headers
['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
2169 response
= Http
.post(url
=add_vdc_rest_url
, headers
=headers
, data
=data
, verify
=vca
.verify
,
2172 print response
.status_code
2173 print response
.content
2174 # if we all ok we respond with content otherwise by default None
2175 if response
.status_code
== 201:
2176 return response
.content