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
=None, config
={}):
108 Constructor create vmware connector to vCloud director.
110 By default construct doesn't validate connection state. So client can create object with None arguments.
111 If client specified username , password and host and VDC name. Connector initialize other missing attributes.
113 a) It initialize organization UUID
114 b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
117 uuid - is organization uuid.
118 name - is organization name that must be presented in vCloud director.
119 tenant_id - is VDC uuid it must be presented in vCloud director
120 tenant_name - is VDC name.
121 url - is hostname or ip address of vCloud director
122 url_admin - same as above.
123 user - is user that administrator for organization. Caller must make sure that
124 username has right privileges.
126 password - is password for a user.
128 VMware connector also requires PVDC administrative privileges and separate account.
129 This variables must be passed via config argument dict contains keys
131 dict['admin_username']
132 dict['admin_password']
138 vimconn
.vimconnector
.__init
__(self
, uuid
, name
, tenant_id
, tenant_name
, url
,
139 url_admin
, user
, passwd
, log_level
, config
)
144 self
.url_admin
= url_admin
145 self
.tenant_id
= tenant_id
146 self
.tenant_name
= tenant_name
150 self
.admin_password
= None
151 self
.admin_user
= None
153 self
.logger
= logging
.getLogger('openmano.vim.vmware')
155 self
.logger
.setLevel( getattr(logging
, log_level
) )
158 self
.admin_user
= config
['admin_username']
159 self
.admin_password
= config
['admin_password']
161 raise vimconn
.vimconnException(message
="Error admin username or admin password is empty.")
167 raise TypeError, 'url param can not be NoneType'
169 if not self
.url_admin
: # try to use normal url
170 self
.url_admin
= self
.url
172 logging
.debug("Calling constructor with following paramters")
173 logging
.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self
.id, self
.name
,
174 self
.tenant_id
, self
.tenant_name
))
175 logging
.debug("vcd url {} vcd username: {} vcd password: {}".format(self
.url
, self
.user
, self
.passwd
))
176 logging
.debug("vcd admin username {} vcd admin passowrd {}".format(self
.admin_user
, self
.admin_password
))
178 # initialize organization
179 if self
.user
is not None and self
.passwd
is not None and self
.url
:
180 self
.init_organization()
182 def __getitem__(self
, index
):
183 if index
== 'tenant_id':
184 return self
.tenant_id
185 if index
== 'tenant_name':
186 return self
.tenant_name
189 elif index
== 'name':
191 elif index
== 'org_name':
193 elif index
== 'org_uuid':
195 elif index
== 'user':
197 elif index
== 'passwd':
201 elif index
== 'url_admin':
202 return self
.url_admin
203 elif index
== "config":
206 raise KeyError("Invalid key '%s'" % str(index
))
208 def __setitem__(self
, index
, value
):
209 if index
== 'tenant_id':
210 self
.tenant_id
= value
211 if index
== 'tenant_name':
212 self
.tenant_name
= value
215 # we use name = org #TODO later refactor
216 elif index
== 'name':
219 elif index
== 'org_name':
220 self
.org_name
= value
222 elif index
== 'org_uuid':
223 self
.org_name
= value
224 elif index
== 'user':
226 elif index
== 'passwd':
230 elif index
== 'url_admin':
231 self
.url_admin
= value
233 raise KeyError("Invalid key '%s'" % str(index
))
235 def connect_as_admin(self
):
236 """ Method connect as pvdc admin user to vCloud director.
237 There are certain action that can be done only by provider vdc admin user.
238 Organization creation / provider network creation etc.
241 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
244 self
.logger
.debug("Logging in to a vca {} as admin.".format(self
.name
))
246 vca_admin
= VCA(host
=self
.url
,
247 username
=self
.admin_user
,
248 service_type
=STANDALONE
,
252 result
= vca_admin
.login(password
=self
.admin_password
, org
='System')
254 raise vimconn
.vimconnConnectionException(
255 "Can't connect to a vCloud director as: {}".format(self
.admin_user
))
256 result
= vca_admin
.login(token
=vca_admin
.token
, org
='System', org_url
=vca_admin
.vcloud_session
.org_url
)
259 "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self
.admin_user
))
264 """ Method connect as normal user to vCloud director.
267 The return vca object that letter can be used to connect to vCloud director as admin for VDC
271 self
.logger
.debug("Logging in to a vca {} as {} to datacenter {}.".format(self
.name
, self
.user
, self
.name
))
272 vca
= VCA(host
=self
.url
,
274 service_type
=STANDALONE
,
279 result
= vca
.login(password
=self
.passwd
, org
=self
.name
)
281 raise vimconn
.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self
.user
))
282 result
= vca
.login(token
=vca
.token
, org
=self
.name
, org_url
=vca
.vcloud_session
.org_url
)
284 self
.logger
.info("Successfully logged to a vcloud direct org: {} as user: {}".format(self
.name
, self
.user
))
287 raise vimconn
.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self
.user
))
291 def init_organization(self
):
292 """ Method initialize organization UUID and VDC parameters.
294 At bare minimum client must provide organization name that present in vCloud director and VDC.
296 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
297 The Org - UUID will be initialized at the run time if data center present in vCloud director.
300 The return vca object that letter can be used to connect to vcloud direct as admin
303 if self
.org_uuid
is None:
304 org_dict
= self
.get_org_list()
306 # we set org UUID at the init phase but we can do it only when we have valid credential.
307 if org_dict
[org
] == self
.org_name
:
309 self
.logger
.debug("Setting organization UUID {}".format(self
.org_uuid
))
313 raise vimconn
.vimconnException("Vcloud director organization {} not found".format(self
.org_name
))
315 # if well good we require for org details
316 org_details_dict
= self
.get_org(org_uuid
=self
.org_uuid
)
318 # we have two case if we want to initialize VDC ID or VDC name at run time
319 # tenant_name provided but no tenant id
320 if self
.tenant_id
is None and self
.tenant_name
is not None and org_details_dict
.has_key('vdcs'):
321 vdcs_dict
= org_details_dict
['vdcs']
322 for vdc
in vdcs_dict
:
323 if vdcs_dict
[vdc
] == self
.tenant_name
:
325 self
.logger
.debug("Setting vdc uuid {} for organization UUID {}".format(self
.tenant_id
,
329 raise vimconn
.vimconnException("Tenant name indicated but not present in vcloud director.")
330 # case two we have tenant_id but we don't have tenant name so we find and set it.
331 if self
.tenant_id
is not None and self
.tenant_name
is None and org_details_dict
.has_key('vdcs'):
332 vdcs_dict
= org_details_dict
['vdcs']
333 for vdc
in vdcs_dict
:
334 if vdc
== self
.tenant_id
:
335 self
.tenant_name
= vdcs_dict
[vdc
]
336 self
.logger
.debug("Setting vdc uuid {} for organization UUID {}".format(self
.tenant_id
,
340 raise vimconn
.vimconnException("Tenant id indicated but not present in vcloud director")
341 self
.logger
.debug("Setting organization uuid {}".format(self
.org_uuid
))
343 self
.logger
.debug("Failed initialize organization UUID for org {}".format(self
.org_name
))
344 self
.logger
.debug(traceback
.format_exc())
347 def new_tenant(self
, tenant_name
=None, tenant_description
=None):
348 """ Method adds a new tenant to VIM with this name.
349 This action requires access to create VDC action in vCloud director.
352 tenant_name is tenant_name to be created.
353 tenant_description not used for this call
356 returns the tenant identifier in UUID format.
357 If action is failed method will throw vimconn.vimconnException method
359 vdc_task
= self
.create_vdc(vdc_name
=tenant_name
)
360 if vdc_task
is not None:
361 vdc_uuid
, value
= vdc_task
.popitem()
362 self
.logger
.info("Crated new vdc {} and uuid: {}".format(tenant_name
, vdc_uuid
))
365 raise vimconn
.vimconnException("Failed create tenant {}".format(tenant_name
))
367 def delete_tenant(self
, tenant_id
=None):
368 """Delete a tenant from VIM"""
369 'Returns the tenant identifier'
370 raise vimconn
.vimconnNotImplemented("Should have implemented this")
372 def get_tenant_list(self
, filter_dict
={}):
373 """Obtain tenants of VIM
374 filter_dict can contain the following keys:
375 name: filter by tenant name
376 id: filter by tenant uuid/id
378 Returns the tenant list of dictionaries:
379 [{'name':'<name>, 'id':'<id>, ...}, ...]
382 org_dict
= self
.get_org(self
.org_uuid
)
383 vdcs_dict
= org_dict
['vdcs']
388 entry
= {'name': vdcs_dict
[k
], 'id': k
}
389 # if caller didn't specify dictionary we return all tenants.
390 if filter_dict
is not None and filter_dict
:
391 filtered_entry
= entry
.copy()
392 filtered_dict
= set(entry
.keys()) - set(filter_dict
)
393 for unwanted_key
in filtered_dict
: del entry
[unwanted_key
]
394 if filter_dict
== entry
:
395 vdclist
.append(filtered_entry
)
397 vdclist
.append(entry
)
399 self
.logger
.debug("Error in get_tenant_list()")
400 self
.logger
.debug(traceback
.format_exc())
401 raise vimconn
.vimconnException("Incorrect state. {}")
405 def new_network(self
, net_name
, net_type
, ip_profile
=None, shared
=False):
406 """Adds a tenant network to VIM
408 net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
409 ip_profile is a dict containing the IP parameters of the network
411 Returns the network identifier"""
414 "new_network tenant {} net_type {} ip_profile {} shared {}".format(net_name
, net_type
, ip_profile
, shared
))
420 network_uuid
= self
.create_network(network_name
=net_name
, isshared
=isshared
)
421 if network_uuid
is not None:
424 raise vimconn
.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name
))
426 def get_vcd_network_list(self
):
427 """ Method available organization for a logged in tenant
430 The return vca object that letter can be used to connect to vcloud direct as admin
433 self
.logger
.debug("get_vcd_network_list(): retrieving network list for vcd")
436 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
438 vdc
= vca
.get_vdc(self
.tenant_name
)
439 vdc_uuid
= vdc
.get_id().split(":")[3]
440 networks
= vca
.get_networks(vdc
.get_name())
443 for network
in networks
:
445 netid
= network
.get_id().split(":")
449 filter_dict
["name"] = network
.get_name()
450 filter_dict
["id"] = netid
[3]
451 filter_dict
["shared"] = network
.get_IsShared()
452 filter_dict
["tenant_id"] = vdc_uuid
453 if network
.get_status() == 1:
454 filter_dict
["admin_state_up"] = True
456 filter_dict
["admin_state_up"] = False
457 filter_dict
["status"] = "ACTIVE"
458 filter_dict
["type"] = "bridge"
459 network_list
.append(filter_dict
)
460 self
.logger
.debug("get_vcd_network_list adding entry {}".format(filter_dict
))
462 self
.logger
.debug("Error in get_vcd_network_list")
463 self
.logger
.debug(traceback
.format_exc())
466 self
.logger
.debug("get_vcd_network_list returning {}".format(network_list
))
469 def get_network_list(self
, filter_dict
={}):
470 """Obtain tenant networks of VIM
472 name: network name OR/AND
473 id: network uuid OR/AND
474 shared: boolean OR/AND
475 tenant_id: tenant OR/AND
476 admin_state_up: boolean
479 [{key : value , key : value}]
481 Returns the network list of dictionaries:
482 [{<the fields at Filter_dict plus some VIM specific>}, ...]
488 raise vimconn
.vimconnConnectionException("self.connect() is failed")
490 vdc
= vca
.get_vdc(self
.tenant_name
)
491 vdcid
= vdc
.get_id().split(":")[3]
493 networks
= vca
.get_networks(vdc
.get_name())
497 for network
in networks
:
499 net_uuid
= network
.get_id().split(":")
500 if len(net_uuid
) != 4:
503 net_uuid
= net_uuid
[3]
505 self
.logger
.debug("Adding {} to a list vcd id {} network {}".format(net_uuid
,
508 filter_entry
["name"] = network
.get_name()
509 filter_entry
["id"] = net_uuid
510 filter_entry
["shared"] = network
.get_IsShared()
511 filter_entry
["tenant_id"] = vdcid
512 if network
.get_status() == 1:
513 filter_entry
["admin_state_up"] = True
515 filter_entry
["admin_state_up"] = False
516 filter_entry
["status"] = "ACTIVE"
517 filter_entry
["type"] = "bridge"
518 filtered_entry
= filter_entry
.copy()
520 if filter_dict
is not None and filter_dict
:
521 # we remove all the key : value we don't care and match only
523 filtered_dict
= set(filter_entry
.keys()) - set(filter_dict
)
524 for unwanted_key
in filtered_dict
: del filter_entry
[unwanted_key
]
525 if filter_dict
== filter_entry
:
526 network_list
.append(filtered_entry
)
528 network_list
.append(filtered_entry
)
530 self
.logger
.debug("Error in get_vcd_network_list")
531 self
.logger
.debug(traceback
.format_exc())
533 self
.logger
.debug("Returning {}".format(network_list
))
536 def get_network(self
, net_id
):
537 """Method bbtain network details of net_id VIM network
538 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
542 raise vimconn
.vimconnConnectionException("self.connect() is failed")
544 vdc
= vca
.get_vdc(self
.tenant_name
)
545 vdc_id
= vdc
.get_id().split(":")[3]
547 networks
= vca
.get_networks(vdc
.get_name())
551 for network
in networks
:
552 vdc_network_id
= network
.get_id().split(":")
553 if len(vdc_network_id
) == 4 and vdc_network_id
[3] == net_id
:
554 filter_dict
["name"] = network
.get_name()
555 filter_dict
["id"] = vdc_network_id
[3]
556 filter_dict
["shared"] = network
.get_IsShared()
557 filter_dict
["tenant_id"] = vdc_id
558 if network
.get_status() == 1:
559 filter_dict
["admin_state_up"] = True
561 filter_dict
["admin_state_up"] = False
562 filter_dict
["status"] = "ACTIVE"
563 filter_dict
["type"] = "bridge"
564 self
.logger
.debug("Returning {}".format(filter_dict
))
567 self
.logger
.debug("Error in get_network")
568 self
.logger
.debug(traceback
.format_exc())
572 def delete_network(self
, net_id
):
574 Method Deletes a tenant network from VIM, provide the network id.
576 Returns the network identifier or raise an exception
581 raise vimconn
.vimconnConnectionException("self.connect() for tenant {} is failed".format(self
.tenant_name
))
583 if self
.delete_network_action(net_id
):
586 raise vimconn
.vimconnNotFoundException("Network {} not found".format(net_id
))
588 def refresh_nets_status(self
, net_list
):
589 """Get the status of the networks
590 Params: the list of network identifiers
591 Returns a dictionary with:
592 net_id: #VIM id of this network
593 status: #Mandatory. Text with one of:
594 # DELETED (not found at vim)
595 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
596 # OTHER (Vim reported other status not understood)
597 # ERROR (VIM indicates an ERROR status)
598 # ACTIVE, INACTIVE, DOWN (admin down),
599 # BUILD (on building process)
601 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
602 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
606 # for net in net_list:
611 # vim vimcon failed == ERROR
614 raise vimconn
.vimconnConnectionException("self.connect() is failed")
621 vcd_network
= self
.get_vcd_network(network_uuid
=net
)
622 if vcd_network
is not None:
623 if vcd_network
['status'] == 1:
629 errormsg
= 'network not found'
630 dict_entry
['net'] = {'status': status
, 'error_msg': errormsg
,
631 'vm_info': yaml
.safe_dump(vcd_network
)}
633 self
.logger
.debug("Error in refresh_nets_status")
634 self
.logger
.debug(traceback
.format_exc())
638 def get_flavor(self
, flavor_id
):
639 """Obtain flavor details from the VIM
640 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
642 return flavorlist
[flavor_id
]
644 def new_flavor(self
, flavor_data
):
645 """Adds a tenant flavor to VIM
646 flavor_data contains a dictionary with information, keys:
648 ram: memory (cloud type) in MBytes
649 vpcus: cpus (cloud type)
650 extended: EPA parameters
651 - numas: #items requested in same NUMA
652 memory: number of 1G huge pages memory
653 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
654 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
655 - name: interface name
656 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
657 bandwidth: X Gbps; requested guarantee bandwidth
658 vpci: requested virtual PCI address
665 Returns the flavor identifier"""
667 # generate a new uuid put to internal dict and return it.
668 flavor_id
= uuid
.uuid4()
669 flavorlist
[str(flavor_id
)] = flavor_data
671 return str(flavor_id
)
673 def delete_flavor(self
, flavor_id
):
674 """Deletes a tenant flavor from VIM identify by its id
676 Returns the used id or raise an exception
679 # if key not present it will raise KeyError
680 # TODO check do I need raise any specific exception
681 flavorlist
.pop(flavor_id
, None)
684 def new_image(self
, image_dict
):
686 Adds a tenant image to VIM
688 200, image-id if the image is created
689 <0, message if there is an error
692 return self
.get_image_id_from_path(image_dict
['location'])
694 def delete_image(self
, image_id
):
695 '''Deletes a tenant image from VIM'''
696 '''Returns the HTTP response code and a message indicating details of the success or fail'''
697 raise vimconn
.vimconnNotImplemented("Should have implemented this")
699 def catalog_exists(self
, catalog_name
, catalogs
):
700 for catalog
in catalogs
:
701 if catalog
.name
== catalog_name
:
705 def create_vimcatalog(self
, vca
=None, catalog_name
=None):
706 """ Create new catalog entry in vcloud director.
710 vca: vCloud director.
711 catalog_name catalog that client wish to create. Note no validation done for a name.
712 Client must make sure that provide valid string representation.
714 Return (bool) True if catalog created.
718 task
= vca
.create_catalog(catalog_name
, catalog_name
)
719 result
= vca
.block_until_completed(task
)
722 catalogs
= vca
.get_catalogs()
725 return self
.catalog_exists(catalog_name
, catalogs
)
727 def upload_ovf(self
, vca
, catalog_name
, item_name
, media_file_name
, description
='', display_progress
=False,
728 chunk_bytes
=128 * 1024):
730 Uploads a OVF file to a vCloud catalog
732 :param catalog_name: (str): The name of the catalog to upload the media.
733 :param item_name: (str): The name of the media file in the catalog.
734 :param media_file_name: (str): The name of the local media file to upload.
735 :return: (bool) True if the media file was successfully uploaded, false otherwise.
737 os
.path
.isfile(media_file_name
)
738 statinfo
= os
.stat(media_file_name
)
741 # find a catalog entry where we upload OVF.
742 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
744 # if VCD can parse OVF we upload VMDK file
745 for catalog
in vca
.get_catalogs():
746 if catalog_name
!= catalog
.name
:
748 link
= filter(lambda link
: link
.get_type() == "application/vnd.vmware.vcloud.media+xml" and
749 link
.get_rel() == 'add', catalog
.get_Link())
750 assert len(link
) == 1
752 <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>
753 """ % (escape(item_name
), escape(description
))
754 headers
= vca
.vcloud_session
.get_vcloud_headers()
755 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
756 response
= Http
.post(link
[0].get_href(), headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=self
.logger
)
757 if response
.status_code
== requests
.codes
.created
:
758 catalogItem
= XmlElementTree
.fromstring(response
.content
)
759 entity
= [child
for child
in catalogItem
if
760 child
.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
761 href
= entity
.get('href')
763 response
= Http
.get(href
, headers
=vca
.vcloud_session
.get_vcloud_headers(),
764 verify
=vca
.verify
, logger
=self
.logger
)
766 if response
.status_code
== requests
.codes
.ok
:
767 media
= mediaType
.parseString(response
.content
, True)
769 filter(lambda link
: link
.get_rel() == 'upload:default',
770 media
.get_Files().get_File()[0].get_Link())[0]
771 headers
= vca
.vcloud_session
.get_vcloud_headers()
772 headers
['Content-Type'] = 'Content-Type text/xml'
773 response
= Http
.put(link
.get_href(), data
=open(media_file_name
, 'rb'), headers
=headers
,
774 verify
=vca
.verify
, logger
=self
.logger
)
775 if response
.status_code
!= requests
.codes
.ok
:
777 "Failed create vApp template for catalog name {} and image {}".format(catalog_name
,
781 # TODO fix this with aync block
784 self
.logger
.debug("Failed create vApp template for catalog name {} and image {}".
785 format(catalog_name
, media_file_name
))
787 # uploading VMDK file
788 # check status of OVF upload
789 response
= Http
.get(template
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
,
791 if response
.status_code
== requests
.codes
.ok
:
792 media
= mediaType
.parseString(response
.content
, True)
793 links_list
= filter(lambda link
: link
.get_rel() == 'upload:default',
794 media
.get_Files().get_File()[0].get_Link())
796 for link
in links_list
:
797 # The OVF file and VMDK must be in a same directory
798 head
, tail
= os
.path
.split(media_file_name
)
799 media_file_name
= link
.get_href()
800 if 'ovf' in media_file_name
:
801 print "skiping {}".format(media_file_name
)
803 file_vmdk
= head
+ '/' + os
.path
.basename(link
.get_href())
804 os
.path
.isfile(file_vmdk
)
805 statinfo
= os
.stat(file_vmdk
)
807 # in case first element is pointer to OVF.
808 hrefvmdk
= link
.get_href().replace("descriptor.ovf", media_file_name
)
809 print("Uploading file {}".format(hrefvmdk
))
811 f
= open(file_vmdk
, 'rb')
812 bytes_transferred
= 0
813 while bytes_transferred
< statinfo
.st_size
:
814 my_bytes
= f
.read(chunk_bytes
)
815 if len(my_bytes
) <= chunk_bytes
:
816 headers
= vca
.vcloud_session
.get_vcloud_headers()
817 headers
['Content-Range'] = 'bytes %s-%s/%s' % (
818 bytes_transferred
, len(my_bytes
) - 1, statinfo
.st_size
)
819 headers
['Content-Length'] = str(len(my_bytes
))
820 response
= Http
.put(hrefvmdk
,
825 if response
.status_code
== requests
.codes
.ok
:
826 bytes_transferred
+= len(my_bytes
)
827 self
.logger
.debug('transferred %s of %s bytes' % (str(bytes_transferred
),
828 str(statinfo
.st_size
)))
830 self
.logger
.debug('file upload failed with error: [%s] %s' % (response
.status_code
,
836 self
.logger
.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
837 format(catalog_name
, media_file_name
))
840 self
.logger
.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name
, media_file_name
))
843 def upload_vimimage(self
, vca
, catalog_name
, media_name
, medial_file_name
):
844 """Upload media file"""
845 # TODO add named parameters for readbility
846 return self
.upload_ovf(vca
, catalog_name
, media_name
.split(".")[0], medial_file_name
, medial_file_name
, True)
848 def validate_uuid4(self
, uuid_string
=None):
849 """ Method validate correct format of UUID.
851 Return: true if string represent valid uuid
854 val
= uuid
.UUID(uuid_string
, version
=4)
859 def get_catalogid(self
, catalog_name
=None, catalogs
=None):
860 """ Method check catalog and return catalog ID in UUID format.
863 catalog_name: catalog name as string
864 catalogs: list of catalogs.
866 Return: catalogs uuid
869 for catalog
in catalogs
:
870 if catalog
.name
== catalog_name
:
871 catalog_id
= catalog
.get_id().split(":")
875 def get_catalogbyid(self
, catalog_uuid
=None, catalogs
=None):
876 """ Method check catalog and return catalog name lookup done by catalog UUID.
879 catalog_name: catalog name as string
880 catalogs: list of catalogs.
882 Return: catalogs name or None
885 if not self
.validate_uuid4(uuid_string
=catalog_uuid
):
888 for catalog
in catalogs
:
889 catalog_id
= catalog
.get_id().split(":")[3]
890 if catalog_id
== catalog_uuid
:
894 def get_image_id_from_path(self
, path
=None):
895 """ Method upload OVF image to vCloud director.
897 Each OVF image represented as single catalog entry in vcloud director.
898 The method check for existing catalog entry. The check done by file name without file extension.
900 if given catalog name already present method will respond with existing catalog uuid otherwise
901 it will create new catalog entry and upload OVF file to newly created catalog.
903 If method can't create catalog entry or upload a file it will throw exception.
906 path: valid path to OVF file.
908 Return: if image uploaded correct method will provide image catalog UUID.
912 raise vimconn
.vimconnConnectionException("self.connect() is failed")
914 self
.logger
.debug("get_image_id_from_path path {}".format(path
))
916 dirpath
, filename
= os
.path
.split(path
)
917 flname
, file_extension
= os
.path
.splitext(path
)
918 if file_extension
!= '.ovf':
919 self
.logger
.debug("Wrong file extension {}".format(file_extension
))
920 raise vimconn
.vimconnException("Wrong container. vCloud director supports only OVF.")
921 catalog_name
= os
.path
.splitext(filename
)[0]
922 self
.logger
.debug("File name {} Catalog Name {} file path {}".format(filename
, catalog_name
, path
))
923 self
.logger
.debug("Catalog name {}".format(catalog_name
))
925 catalogs
= vca
.get_catalogs()
926 if len(catalogs
) == 0:
927 self
.logger
.info("Creating new catalog entry {} in vcloud director".format(catalog_name
))
928 result
= self
.create_vimcatalog(vca
, catalog_name
)
930 raise vimconn
.vimconnException("Failed create new catalog {} ".format(catalog_name
))
931 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
933 raise vimconn
.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name
))
934 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
936 for catalog
in catalogs
:
937 # search for existing catalog if we find same name we return ID
939 if catalog
.name
== catalog_name
:
940 self
.logger
.debug("Found existing catalog entry for {} catalog id {}".format(catalog_name
,
944 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
946 # if we didn't find existing catalog we create a new one.
947 self
.logger
.debug("Creating new catalog entry".format(catalog_name
))
948 result
= self
.create_vimcatalog(vca
, catalog_name
)
950 raise vimconn
.vimconnException("Failed create new catalog {} ".format(catalog_name
))
951 result
= self
.upload_vimimage(vca
, catalog_name
, filename
, path
)
953 raise vimconn
.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name
))
955 return self
.get_catalogid(catalog_name
, vca
.get_catalogs())
957 def get_vappid(self
, vdc
=None, vapp_name
=None):
958 """ Method takes vdc object and vApp name and returns vapp uuid or None
961 vca: Connector to VCA
963 vapp_name: is application vappp name identifier
966 The return vApp name otherwise None
968 if vdc
is None or vapp_name
is None:
970 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
972 refs
= filter(lambda ref
: ref
.name
== vapp_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
973 vdc
.ResourceEntities
.ResourceEntity
)
975 return refs
[0].href
.split("vapp")[1][1:]
976 except Exception as e
:
977 self
.logger
.exception(e
)
981 def check_vapp(self
, vdc
, vapp_id
):
982 """ Take VDC object and vApp ID and return True if given ID in vCloud director
983 otherwise return False
986 """ Method Method returns vApp name from vCD and lookup done by vapp_id.
989 vca: Connector to VCA
991 vappid: vappid is application identifier
994 The return vApp name otherwise None
997 refs
= filter(lambda ref
:
998 ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
999 vdc
.ResourceEntities
.ResourceEntity
)
1001 vappid
= ref
.href
.split("vapp")[1][1:]
1002 # find vapp with respected vapp uuid
1003 if vappid
== vapp_id
:
1005 except Exception as e
:
1006 self
.logger
.exception(e
)
1010 def get_namebyvappid(self
, vca
, vdc
, vapp_id
):
1011 """Method returns vApp name from vCD and lookup done by vapp_id.
1014 vca: Connector to VCA
1015 vdc: The VDC object.
1016 vapp_id: vappid is application identifier
1019 The return vApp name otherwise None
1023 refs
= filter(lambda ref
: ref
.type_
== 'application/vnd.vmware.vcloud.vApp+xml',
1024 vdc
.ResourceEntities
.ResourceEntity
)
1026 # we care only about UUID the rest doesn't matter
1027 vappid
= ref
.href
.split("vapp")[1][1:]
1028 if vappid
== vapp_id
:
1029 response
= Http
.get(ref
.href
, headers
=vca
.vcloud_session
.get_vcloud_headers(), verify
=vca
.verify
,
1031 tree
= XmlElementTree
.fromstring(response
.content
)
1032 return tree
.attrib
['name']
1033 except Exception as e
:
1034 self
.logger
.exception(e
)
1038 def new_vminstance(self
, name
=None, description
="", start
=False, image_id
=None, flavor_id
=None, net_list
={}, cloud_config
=None):
1039 """Adds a VM instance to VIM
1041 start: indicates if VM must start or boot in pause mode. Ignored
1042 image_id,flavor_id: image and flavor uuid
1043 net_list: list of interfaces, each one is a dictionary with:
1045 net_id: network uuid to connect
1046 vpci: virtual vcpi to assign
1047 model: interface model, virtio, e2000, ...
1049 use: 'data', 'bridge', 'mgmt'
1050 type: 'virtual', 'PF', 'VF', 'VFnotShared'
1051 vim_id: filled/added by this function
1052 cloud_config: can be a text script to be passed directly to cloud-init,
1053 or an object to inject users and ssh keys with format:
1054 key-pairs: [] list of keys to install to the default user
1055 users: [{ name, key-pairs: []}] list of users to add with their key-pair
1056 #TODO ip, security groups
1057 Returns >=0, the instance identifier
1061 self
.logger
.info("Creating new instance for entry".format(name
))
1062 self
.logger
.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
1063 format(description
, start
, image_id
, flavor_id
, net_list
, cloud_config
))
1064 vca
= self
.connect()
1066 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1068 # if vm already deployed we return existing uuid
1069 vapp_uuid
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
1070 if vapp_uuid
is not None:
1073 # we check for presence of VDC, Catalog entry and Flavor.
1074 vdc
= vca
.get_vdc(self
.tenant_name
)
1076 raise vimconn
.vimconnUnexpectedResponse(
1077 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name
))
1078 catalogs
= vca
.get_catalogs()
1079 if catalogs
is None:
1080 raise vimconn
.vimconnUnexpectedResponse(
1081 "new_vminstance(): Failed create vApp {}: Failed create vApp {}: "
1082 "(Failed retrieve catalog information)".format(name
))
1086 if flavor_id
is not None:
1087 flavor
= flavorlist
[flavor_id
]
1089 raise vimconn
.vimconnUnexpectedResponse(
1090 "new_vminstance(): Failed create vApp {}: (Failed retrieve flavor information)".format(name
))
1093 vm_cpus
= flavor
['vcpus']
1094 vm_memory
= flavor
['ram']
1096 raise vimconn
.vimconnException("Corrupted flavor. {}".format(flavor_id
))
1098 # image upload creates template name as catalog name space Template.
1102 templateName
= self
.get_catalogbyid(catalog_uuid
=image_id
, catalogs
=catalogs
) + ' Template'
1107 # client must provide at least one entry in net_list if not we report error
1109 primary_net_name
= None
1110 if net_list
is not None and len(net_list
) > 0:
1111 primary_net
= net_list
[0]
1112 if primary_net
is None:
1113 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name
))
1117 primary_net_id
= primary_net
['net_id']
1118 primary_net_name
= self
.get_network_name_by_id(primary_net_id
)
1119 network_mode
= primary_net
['use']
1121 raise vimconn
.vimconnException("Corrupted flavor. {}".format(primary_net
))
1123 # use: 'data', 'bridge', 'mgmt'
1124 # create vApp. Set vcpu and ram based on flavor id.
1125 vapptask
= vca
.create_vapp(self
.tenant_name
, name
, templateName
,
1126 self
.get_catalogbyid(image_id
, catalogs
),
1127 network_name
=primary_net_name
, # can be None if net_list None
1128 network_mode
='bridged',
1130 vm_cpus
=vm_cpus
, # can be None if flavor is None
1131 vm_memory
=vm_memory
) # can be None if flavor is None
1133 if vapptask
is None or vapptask
is False:
1134 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(name
))
1135 if type(vapptask
) is VappTask
:
1136 vca
.block_until_completed(vapptask
)
1138 # we should have now vapp in undeployed state.
1139 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), name
)
1141 raise vimconn
.vimconnUnexpectedResponse(
1142 "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(name
))
1147 for net
in net_list
:
1148 # openmano uses network id in UUID format.
1149 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
1150 interface_net_id
= net
['net_id']
1151 interface_net_name
= self
.get_network_name_by_id(interface_net_id
)
1152 interface_network_mode
= net
['use']
1154 if primary_net_name
is not None:
1155 nets
= filter(lambda n
: n
.name
== interface_net_name
, vca
.get_networks(self
.tenant_name
))
1157 task
= vapp
.connect_to_network(nets
[0].name
, nets
[0].href
)
1158 if type(task
) is GenericTask
:
1159 vca
.block_until_completed(task
)
1160 # connect network to VM
1161 # TODO figure out mapping between openmano representation to vCloud director.
1162 # one idea use first nic as management DHCP all remaining in bridge mode
1163 task
= vapp
.connect_vms(nets
[0].name
, connection_index
=nicIndex
,
1164 connections_primary_index
=nicIndex
,
1165 ip_allocation_mode
='DHCP')
1166 if type(task
) is GenericTask
:
1167 vca
.block_until_completed(task
)
1170 # it might be a case if specific mandatory entry in dict is empty
1171 self
.logger
.debug("Key error {}".format(KeyError.message
))
1172 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name
))
1174 # deploy and power on vm
1175 task
= vapp
.poweron()
1176 if type(task
) is TaskType
:
1177 vca
.block_until_completed(task
)
1178 deploytask
= vapp
.deploy(powerOn
='True')
1179 if type(task
) is TaskType
:
1180 vca
.block_until_completed(deploytask
)
1182 # check if vApp deployed and if that the case return vApp UUID otherwise -1
1183 vapp_uuid
= self
.get_vappid(vca
.get_vdc(self
.tenant_name
), name
)
1184 if vapp_uuid
is not None:
1187 raise vimconn
.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name
))
1191 ## based on current discussion
1195 # created: '2016-09-08T11:51:58'
1196 # description: simple-instance.linux1.1
1197 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
1198 # hostId: e836c036-74e7-11e6-b249-0800273e724c
1199 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
1204 def get_vminstance(self
, vim_vm_uuid
):
1205 '''Returns the VM instance information from VIM'''
1207 self
.logger
.debug("Client requesting vm instance {} ".format(vim_vm_uuid
))
1208 vca
= self
.connect()
1210 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1212 vdc
= vca
.get_vdc(self
.tenant_name
)
1214 return -1, "Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
)
1216 vm_name
= self
.get_namebyvappid(vca
, vdc
, vim_vm_uuid
)
1218 self
.logger
.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid
))
1219 return None, "Failed to get vApp name by UUID {}".format(vim_vm_uuid
)
1221 the_vapp
= vca
.get_vapp(vdc
, vm_name
)
1222 vm_info
= the_vapp
.get_vms_details()
1224 vm_dict
= {'description': vm_info
[0]['name'], 'status': vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()],
1225 'error_msg': vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()],
1226 'vim_info': yaml
.safe_dump(the_vapp
.get_vms_details()), 'interfaces': []}
1229 vm_app_networks
= the_vapp
.get_vms_network_info()
1233 org_network_dict
= self
.get_org(self
.org_uuid
)['networks']
1234 for vapp_network
in vm_app_networks
:
1235 for vm_network
in vapp_network
:
1236 if vm_network
['name'] == vm_name
:
1238 # interface['vim_info'] = yaml.safe_dump(vm_network)
1239 interface
["mac_address"] = vm_network
['mac']
1240 for net_uuid
in org_network_dict
:
1241 if org_network_dict
[net_uuid
] == vm_network
['network_name']:
1242 interface
["vim_net_id"] = net_uuid
1243 interface
["vim_interface_id"] = vm_network
['network_name']
1244 interface
['ip_address'] = vm_network
['ip']
1245 interfaces
.append(interface
)
1247 self
.logger
.debug("Error in respond {}".format(KeyError.message
))
1248 self
.logger
.debug(traceback
.format_exc())
1250 vm_dict
['interfaces'] = interfaces
1254 def delete_vminstance(self
, vm__vim_uuid
):
1255 """Method poweroff and remove VM instance from vcloud director network.
1258 vm__vim_uuid: VM UUID
1261 Returns the instance identifier
1264 self
.logger
.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid
))
1265 vca
= self
.connect()
1267 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1269 vdc
= vca
.get_vdc(self
.tenant_name
)
1271 self
.logger
.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
1273 raise vimconn
.vimconnException(
1274 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1277 vapp_name
= self
.get_namebyvappid(vca
, vdc
, vm__vim_uuid
)
1278 if vapp_name
is None:
1279 self
.logger
.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1280 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
)
1282 self
.logger
.info("Deleting vApp {} and UUID {}".format(vapp_name
, vm__vim_uuid
))
1284 # Delete vApp and wait for status change if task executed and vApp is None.
1285 # We successfully delete vApp from vCloud
1286 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
)
1287 # poweroff vapp / undeploy and delete
1288 power_off_task
= vapp
.poweroff()
1289 if type(power_off_task
) is GenericTask
:
1290 vca
.block_until_completed(power_off_task
)
1292 if not power_off_task
:
1293 self
.logger
.debug("delete_vminstance(): Failed power off VM uuid {} ".format(vm__vim_uuid
))
1296 if vapp
.me
.deployed
:
1297 undeploy_task
= vapp
.undeploy()
1298 if type(undeploy_task
) is GenericTask
:
1300 while retry
<= DELETE_INSTANCE_RETRY
:
1301 result
= vca
.block_until_completed(undeploy_task
)
1309 vapp
= vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
)
1310 if vapp
is not None:
1311 delete_task
= vapp
.delete()
1313 while retry
<= DELETE_INSTANCE_RETRY
:
1314 task
= vapp
.delete()
1315 if type(task
) is GenericTask
:
1316 vca
.block_until_completed(delete_task
)
1318 self
.logger
.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid
))
1322 self
.logger
.debug(traceback
.format_exc())
1323 raise vimconn
.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid
))
1325 if vca
.get_vapp(vca
.get_vdc(self
.tenant_name
), vapp_name
) is None:
1328 raise vimconn
.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid
))
1330 def refresh_vms_status(self
, vm_list
):
1331 """Get the status of the virtual machines and their interfaces/ports
1332 Params: the list of VM identifiers
1333 Returns a dictionary with:
1334 vm_id: #VIM id of this Virtual Machine
1335 status: #Mandatory. Text with one of:
1336 # DELETED (not found at vim)
1337 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1338 # OTHER (Vim reported other status not understood)
1339 # ERROR (VIM indicates an ERROR status)
1340 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
1341 # CREATING (on building process), ERROR
1342 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
1344 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1345 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1347 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1348 mac_address: #Text format XX:XX:XX:XX:XX:XX
1349 vim_net_id: #network id where this interface is connected
1350 vim_interface_id: #interface/port VIM id
1351 ip_address: #null, or text with IPv4, IPv6 address
1354 self
.logger
.debug("Client requesting refresh vm status for {} ".format(vm_list
))
1355 vca
= self
.connect()
1357 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1359 vdc
= vca
.get_vdc(self
.tenant_name
)
1361 raise vimconn
.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
))
1364 for vmuuid
in vm_list
:
1365 vmname
= self
.get_namebyvappid(vca
, vdc
, vmuuid
)
1366 if vmname
is not None:
1368 the_vapp
= vca
.get_vapp(vdc
, vmname
)
1369 vm_info
= the_vapp
.get_vms_details()
1370 vm_status
= vm_info
[0]['status']
1372 vm_dict
= {'status': None, 'error_msg': None, 'vim_info': None, 'interfaces': []}
1373 vm_dict
['status'] = vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()]
1374 vm_dict
['error_msg'] = vcdStatusCode2manoFormat
[the_vapp
.me
.get_status()]
1375 vm_dict
['vim_info'] = yaml
.safe_dump(the_vapp
.get_vms_details())
1379 vm_app_networks
= the_vapp
.get_vms_network_info()
1380 for vapp_network
in vm_app_networks
:
1381 for vm_network
in vapp_network
:
1382 if vm_network
['name'] == vmname
:
1384 # interface['vim_info'] = yaml.safe_dump(vm_network)
1385 interface
["mac_address"] = vm_network
['mac']
1386 interface
["vim_net_id"] = self
.get_network_name_by_id(vm_network
['network_name'])
1387 interface
["vim_interface_id"] = vm_network
['network_name']
1388 interface
['ip_address'] = vm_network
['ip']
1389 vm_dict
["interfaces"].append(interface
)
1390 # add a vm to vm dict
1391 vms_dict
.setdefault(vmuuid
, vm_dict
)
1393 self
.logger
.debug("Error in respond {}".format(KeyError.message
))
1394 self
.logger
.debug(traceback
.format_exc())
1398 def action_vminstance(self
, vm__vim_uuid
=None, action_dict
=None):
1399 """Send and action over a VM instance from VIM
1400 Returns the vm_id if the action was successfully sent to the VIM"""
1402 self
.logger
.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid
, action_dict
))
1403 if vm__vim_uuid
is None or action_dict
is None:
1404 raise vimconn
.vimconnException("Invalid request. VM id or action is None.")
1406 vca
= self
.connect()
1408 raise vimconn
.vimconnConnectionException("self.connect() is failed.")
1410 vdc
= vca
.get_vdc(self
.tenant_name
)
1412 return -1, "Failed to get a reference of VDC for a tenant {}".format(self
.tenant_name
)
1414 vapp_name
= self
.get_namebyvappid(vca
, vdc
, vm__vim_uuid
)
1415 if vapp_name
is None:
1416 self
.logger
.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1417 raise vimconn
.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid
))
1419 self
.logger
.info("Action_vminstance vApp {} and UUID {}".format(vapp_name
, vm__vim_uuid
))
1422 the_vapp
= vca
.get_vapp(vdc
, vapp_name
)
1423 # TODO fix all status
1424 if "start" in action_dict
:
1425 if action_dict
["start"] == "rebuild":
1426 the_vapp
.deploy(powerOn
=True)
1428 vm_info
= the_vapp
.get_vms_details()
1429 vm_status
= vm_info
[0]['status']
1430 if vm_status
== "Suspended":
1432 elif vm_status
.status
== "Powered off":
1434 elif "pause" in action_dict
:
1437 elif "resume" in action_dict
:
1440 elif "shutoff" in action_dict
or "shutdown" in action_dict
:
1442 elif "forceOff" in action_dict
:
1444 elif "terminate" in action_dict
:
1446 # elif "createImage" in action_dict:
1447 # server.create_image()
1453 def get_vminstance_console(self
, vm_id
, console_type
="vnc"):
1455 Get a console for the virtual machine
1457 vm_id: uuid of the VM
1458 console_type, can be:
1459 "novnc" (by default), "xvpvnc" for VNC types,
1460 "rdp-html5" for RDP types, "spice-html5" for SPICE types
1461 Returns dict with the console parameters:
1462 protocol: ssh, ftp, http, https, ...
1463 server: usually ip address
1464 port: the http, ssh, ... port
1465 suffix: extra text, e.g. the http path and query string
1467 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1469 # NOT USED METHODS in current version
1471 def host_vim2gui(self
, host
, server_dict
):
1472 '''Transform host dictionary from VIM format to GUI format,
1473 and append to the server_dict
1475 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1477 def get_hosts_info(self
):
1478 '''Get the information of deployed hosts
1479 Returns the hosts content'''
1480 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1482 def get_hosts(self
, vim_tenant
):
1483 '''Get the hosts and deployed instances
1484 Returns the hosts content'''
1485 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1487 def get_processor_rankings(self
):
1488 '''Get the processor rankings in the VIM database'''
1489 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1491 def new_host(self
, host_data
):
1492 '''Adds a new host to VIM'''
1493 '''Returns status code of the VIM response'''
1494 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1496 def new_external_port(self
, port_data
):
1497 '''Adds a external port to VIM'''
1498 '''Returns the port identifier'''
1499 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1501 def new_external_network(self
, net_name
, net_type
):
1502 '''Adds a external network to VIM (shared)'''
1503 '''Returns the network identifier'''
1504 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1506 def connect_port_network(self
, port_id
, network_id
, admin
=False):
1507 '''Connects a external port to a network'''
1508 '''Returns status code of the VIM response'''
1509 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1511 def new_vminstancefromJSON(self
, vm_data
):
1512 '''Adds a VM instance to VIM'''
1513 '''Returns the instance identifier'''
1514 raise vimconn
.vimconnNotImplemented("Should have implemented this")
1516 def get_network_name_by_id(self
, network_name
=None):
1517 """Method gets vcloud director network named based on supplied uuid.
1520 network_name: network_id
1523 The return network name.
1526 vca
= self
.connect()
1528 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1530 if network_name
is None:
1534 org_network_dict
= self
.get_org(self
.org_uuid
)['networks']
1535 for net_uuid
in org_network_dict
:
1536 if org_network_dict
[net_uuid
] == network_name
:
1539 self
.logger
.debug("Exception in get_network_name_by_id")
1540 self
.logger
.debug(traceback
.format_exc())
1544 def list_org_action(self
):
1546 Method leverages vCloud director and query for available organization for particular user
1549 vca - is active VCA connection.
1550 vdc_name - is a vdc name that will be used to query vms action
1553 The return XML respond
1556 vca
= self
.connect()
1558 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1560 url_list
= [vca
.host
, '/api/org']
1561 vm_list_rest_call
= ''.join(url_list
)
1563 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1564 response
= Http
.get(url
=vm_list_rest_call
,
1565 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1568 if response
.status_code
== requests
.codes
.ok
:
1569 return response
.content
1573 def get_org_action(self
, org_uuid
=None):
1575 Method leverages vCloud director and retrieve available object fdr organization.
1578 vca - is active VCA connection.
1579 vdc_name - is a vdc name that will be used to query vms action
1582 The return XML respond
1585 vca
= self
.connect()
1587 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1589 if org_uuid
is None:
1592 url_list
= [vca
.host
, '/api/org/', org_uuid
]
1593 vm_list_rest_call
= ''.join(url_list
)
1595 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1596 response
= Http
.get(url
=vm_list_rest_call
,
1597 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1600 if response
.status_code
== requests
.codes
.ok
:
1601 return response
.content
1605 def get_org(self
, org_uuid
=None):
1607 Method retrieves available organization in vCloud Director
1610 org_uuid - is a organization uuid.
1613 The return dictionary with following key
1614 "network" - for network list under the org
1615 "catalogs" - for network list under the org
1616 "vdcs" - for vdc list under org
1620 vca
= self
.connect()
1622 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1624 if org_uuid
is None:
1627 content
= self
.get_org_action(org_uuid
=org_uuid
)
1632 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1633 for child
in vm_list_xmlroot
:
1634 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
1635 vdc_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1636 org_dict
['vdcs'] = vdc_list
1637 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
1638 network_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1639 org_dict
['networks'] = network_list
1640 if child
.attrib
['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
1641 catalog_list
[child
.attrib
['href'].split("/")[-1:][0]] = child
.attrib
['name']
1642 org_dict
['catalogs'] = catalog_list
1648 def get_org_list(self
):
1650 Method retrieves available organization in vCloud Director
1653 vca - is active VCA connection.
1656 The return dictionary and key for each entry VDC UUID
1660 vca
= self
.connect()
1662 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1664 content
= self
.list_org_action()
1666 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1667 for vm_xml
in vm_list_xmlroot
:
1668 if vm_xml
.tag
.split("}")[1] == 'Org':
1669 org_uuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1670 org_dict
[org_uuid
[0]] = vm_xml
.attrib
['name']
1676 def vms_view_action(self
, vdc_name
=None):
1677 """ Method leverages vCloud director vms query call
1680 vca - is active VCA connection.
1681 vdc_name - is a vdc name that will be used to query vms action
1684 The return XML respond
1686 vca
= self
.connect()
1687 if vdc_name
is None:
1690 url_list
= [vca
.host
, '/api/vms/query']
1691 vm_list_rest_call
= ''.join(url_list
)
1693 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1694 refs
= filter(lambda ref
: ref
.name
== vdc_name
and ref
.type_
== 'application/vnd.vmware.vcloud.vdc+xml',
1695 vca
.vcloud_session
.organization
.Link
)
1697 response
= Http
.get(url
=vm_list_rest_call
,
1698 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1701 if response
.status_code
== requests
.codes
.ok
:
1702 return response
.content
1706 def get_vapp_list(self
, vdc_name
=None):
1708 Method retrieves vApp list deployed vCloud director and returns a dictionary
1709 contains a list of all vapp deployed for queried VDC.
1710 The key for a dictionary is vApp UUID
1714 vca - is active VCA connection.
1715 vdc_name - is a vdc name that will be used to query vms action
1718 The return dictionary and key for each entry vapp UUID
1722 if vdc_name
is None:
1725 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1727 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1728 for vm_xml
in vm_list_xmlroot
:
1729 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1730 if vm_xml
.attrib
['isVAppTemplate'] == 'true':
1731 rawuuid
= vm_xml
.attrib
['container'].split('/')[-1:]
1732 if 'vappTemplate-' in rawuuid
[0]:
1733 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1734 # vm and use raw UUID as key
1735 vapp_dict
[rawuuid
[0][13:]] = vm_xml
.attrib
1741 def get_vm_list(self
, vdc_name
=None):
1743 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1744 contains a list of all VM's deployed for queried VDC.
1745 The key for a dictionary is VM UUID
1749 vca - is active VCA connection.
1750 vdc_name - is a vdc name that will be used to query vms action
1753 The return dictionary and key for each entry vapp UUID
1757 if vdc_name
is None:
1760 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1762 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1763 for vm_xml
in vm_list_xmlroot
:
1764 if vm_xml
.tag
.split("}")[1] == 'VMRecord':
1765 if vm_xml
.attrib
['isVAppTemplate'] == 'false':
1766 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1767 if 'vm-' in rawuuid
[0]:
1768 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1769 # vm and use raw UUID as key
1770 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1776 def get_vapp(self
, vdc_name
=None, vapp_name
=None, isuuid
=False):
1778 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
1779 contains a list of all VM's deployed for queried VDC.
1780 The key for a dictionary is VM UUID
1784 vca - is active VCA connection.
1785 vdc_name - is a vdc name that will be used to query vms action
1788 The return dictionary and key for each entry vapp UUID
1791 vca
= self
.connect()
1793 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1795 if vdc_name
is None:
1798 content
= self
.vms_view_action(vdc_name
=vdc_name
)
1800 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1801 for vm_xml
in vm_list_xmlroot
:
1802 if vm_xml
.tag
.split("}")[1] == 'VMRecord' and vm_xml
.attrib
['isVAppTemplate'] == 'false':
1803 # lookup done by UUID
1805 if vapp_name
in vm_xml
.attrib
['container']:
1806 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1807 if 'vm-' in rawuuid
[0]:
1808 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1810 # lookup done by Name
1812 if vapp_name
in vm_xml
.attrib
['name']:
1813 rawuuid
= vm_xml
.attrib
['href'].split('/')[-1:]
1814 if 'vm-' in rawuuid
[0]:
1815 vm_dict
[rawuuid
[0][3:]] = vm_xml
.attrib
1822 def get_network_action(self
, network_uuid
=None):
1824 Method leverages vCloud director and query network based on network uuid
1827 vca - is active VCA connection.
1828 network_uuid - is a network uuid
1831 The return XML respond
1834 vca
= self
.connect()
1836 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1838 if network_uuid
is None:
1841 url_list
= [vca
.host
, '/api/network/', network_uuid
]
1842 vm_list_rest_call
= ''.join(url_list
)
1844 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1845 response
= Http
.get(url
=vm_list_rest_call
,
1846 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1849 if response
.status_code
== requests
.codes
.ok
:
1850 return response
.content
1854 def get_vcd_network(self
, network_uuid
=None):
1856 Method retrieves available network from vCloud Director
1859 network_uuid - is VCD network UUID
1861 Each element serialized as key : value pair
1863 Following keys available for access. network_configuration['Gateway'}
1867 <IsInherited>true</IsInherited>
1868 <Gateway>172.16.252.100</Gateway>
1869 <Netmask>255.255.255.0</Netmask>
1870 <Dns1>172.16.254.201</Dns1>
1871 <Dns2>172.16.254.202</Dns2>
1872 <DnsSuffix>vmwarelab.edu</DnsSuffix>
1873 <IsEnabled>true</IsEnabled>
1876 <StartAddress>172.16.252.1</StartAddress>
1877 <EndAddress>172.16.252.99</EndAddress>
1882 <FenceMode>bridged</FenceMode>
1885 The return dictionary and key for each entry vapp UUID
1888 network_configuration
= {}
1889 if network_uuid
is None:
1892 content
= self
.get_network_action(network_uuid
=network_uuid
)
1894 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1896 network_configuration
['status'] = vm_list_xmlroot
.get("status")
1897 network_configuration
['name'] = vm_list_xmlroot
.get("name")
1898 network_configuration
['uuid'] = vm_list_xmlroot
.get("id").split(":")[3]
1900 for child
in vm_list_xmlroot
:
1901 if child
.tag
.split("}")[1] == 'IsShared':
1902 network_configuration
['isShared'] = child
.text
.strip()
1903 if child
.tag
.split("}")[1] == 'Configuration':
1904 for configuration
in child
.iter():
1905 tagKey
= configuration
.tag
.split("}")[1].strip()
1907 network_configuration
[tagKey
] = configuration
.text
.strip()
1908 return network_configuration
1912 return network_configuration
1914 def delete_network_action(self
, network_uuid
=None):
1916 Method delete given network from vCloud director
1919 network_uuid - is a network uuid that client wish to delete
1922 The return None or XML respond or false
1925 vca
= self
.connect_as_admin()
1927 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1928 if network_uuid
is None:
1931 url_list
= [vca
.host
, '/api/admin/network/', network_uuid
]
1932 vm_list_rest_call
= ''.join(url_list
)
1934 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1935 response
= Http
.delete(url
=vm_list_rest_call
,
1936 headers
=vca
.vcloud_session
.get_vcloud_headers(),
1940 if response
.status_code
== 202:
1945 def create_network(self
, network_name
=None, parent_network_uuid
=None, isshared
='true'):
1947 Method create network in vCloud director
1950 network_name - is network name to be created.
1951 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1952 It optional attribute. by default if no parent network indicate the first available will be used.
1955 The return network uuid or return None
1958 content
= self
.create_network_rest(network_name
=network_name
,
1959 parent_network_uuid
=parent_network_uuid
,
1962 self
.logger
.debug("Failed create network {}.".format(network_name
))
1966 vm_list_xmlroot
= XmlElementTree
.fromstring(content
)
1967 vcd_uuid
= vm_list_xmlroot
.get('id').split(":")
1968 if len(vcd_uuid
) == 4:
1969 self
.logger
.info("Create new network name: {} uuid: {}".format(network_name
, vcd_uuid
[3]))
1972 self
.logger
.debug("Failed create network {}".format(network_name
))
1975 def create_network_rest(self
, network_name
=None, parent_network_uuid
=None, isshared
='true'):
1977 Method create network in vCloud director
1980 network_name - is network name to be created.
1981 parent_network_uuid - is parent provider vdc network that will be used for mapping.
1982 It optional attribute. by default if no parent network indicate the first available will be used.
1985 The return network uuid or return None
1988 vca
= self
.connect_as_admin()
1990 raise vimconn
.vimconnConnectionException("self.connect() is failed")
1991 if network_name
is None:
1994 url_list
= [vca
.host
, '/api/admin/vdc/', self
.tenant_id
]
1995 vm_list_rest_call
= ''.join(url_list
)
1996 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
1997 response
= Http
.get(url
=vm_list_rest_call
,
1998 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2002 provider_network
= None
2003 available_networks
= None
2004 add_vdc_rest_url
= None
2006 if response
.status_code
!= requests
.codes
.ok
:
2007 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
2008 response
.status_code
))
2012 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2013 for child
in vm_list_xmlroot
:
2014 if child
.tag
.split("}")[1] == 'ProviderVdcReference':
2015 provider_network
= child
.attrib
.get('href')
2016 # application/vnd.vmware.admin.providervdc+xml
2017 if child
.tag
.split("}")[1] == 'Link':
2018 if child
.attrib
.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
2019 and child
.attrib
.get('rel') == 'add':
2020 add_vdc_rest_url
= child
.attrib
.get('href')
2022 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2023 self
.logger
.debug("Respond body {}".format(response
.content
))
2026 # find pvdc provided available network
2027 response
= Http
.get(url
=provider_network
,
2028 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2031 if response
.status_code
!= requests
.codes
.ok
:
2032 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
2033 response
.status_code
))
2036 # available_networks.split("/")[-1]
2038 if parent_network_uuid
is None:
2040 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2041 for child
in vm_list_xmlroot
.iter():
2042 if child
.tag
.split("}")[1] == 'AvailableNetworks':
2043 for networks
in child
.iter():
2044 # application/vnd.vmware.admin.network+xml
2045 if networks
.attrib
.get('href') is not None:
2046 available_networks
= networks
.attrib
.get('href')
2051 # either use client provided UUID or search for a first available
2052 # if both are not defined we return none
2053 if parent_network_uuid
is not None:
2054 url_list
= [vca
.host
, '/api/admin/network/', parent_network_uuid
]
2055 add_vdc_rest_url
= ''.join(url_list
)
2057 # return response.content
2058 data
= """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2059 <Description>Openmano created</Description>
2061 <ParentNetwork href="{1:s}"/>
2062 <FenceMode>{2:s}</FenceMode>
2064 <IsShared>{3:s}</IsShared>
2065 </OrgVdcNetwork> """.format(escape(network_name
), available_networks
, "bridged", isshared
)
2067 headers
= vca
.vcloud_session
.get_vcloud_headers()
2068 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
2069 response
= Http
.post(url
=add_vdc_rest_url
, headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=vca
.logger
)
2071 # if we all ok we respond with content otherwise by default None
2072 if response
.status_code
== 201:
2073 return response
.content
2076 def get_provider_rest(self
, vca
=None):
2078 Method gets provider vdc view from vcloud director
2081 network_name - is network name to be created.
2082 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2083 It optional attribute. by default if no parent network indicate the first available will be used.
2086 The return xml content of respond or None
2089 url_list
= [vca
.host
, '/api/admin']
2090 response
= Http
.get(url
=''.join(url_list
),
2091 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2095 if response
.status_code
== requests
.codes
.ok
:
2096 return response
.content
2099 def create_vdc(self
, vdc_name
=None):
2103 xml_content
= self
.create_vdc_from_tmpl_rest(vdc_name
=vdc_name
)
2104 if xml_content
is not None:
2106 task_resp_xmlroot
= XmlElementTree
.fromstring(xml_content
)
2107 for child
in task_resp_xmlroot
:
2108 if child
.tag
.split("}")[1] == 'Owner':
2109 vdc_id
= child
.attrib
.get('href').split("/")[-1]
2110 vdc_dict
[vdc_id
] = task_resp_xmlroot
.get('href')
2113 self
.logger
.debug("Respond body {}".format(xml_content
))
2117 def create_vdc_from_tmpl_rest(self
, vdc_name
=None):
2119 Method create vdc in vCloud director based on VDC template.
2120 it uses pre-defined template that must be named openmano
2123 vdc_name - name of a new vdc.
2126 The return xml content of respond or None
2129 self
.logger
.info("Creating new vdc {}".format(vdc_name
))
2130 vca
= self
.connect()
2132 raise vimconn
.vimconnConnectionException("self.connect() is failed")
2133 if vdc_name
is None:
2136 url_list
= [vca
.host
, '/api/vdcTemplates']
2137 vm_list_rest_call
= ''.join(url_list
)
2138 response
= Http
.get(url
=vm_list_rest_call
,
2139 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2143 # container url to a template
2144 vdc_template_ref
= None
2146 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2147 for child
in vm_list_xmlroot
:
2148 # application/vnd.vmware.admin.providervdc+xml
2149 # we need find a template from witch we instantiate VDC
2150 if child
.tag
.split("}")[1] == 'VdcTemplate':
2151 if child
.attrib
.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child
.attrib
.get(
2152 'name') == 'openmano':
2153 vdc_template_ref
= child
.attrib
.get('href')
2155 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2156 self
.logger
.debug("Respond body {}".format(response
.content
))
2159 # if we didn't found required pre defined template we return None
2160 if vdc_template_ref
is None:
2165 url_list
= [vca
.host
, '/api/org/', self
.org_uuid
, '/action/instantiate']
2166 vm_list_rest_call
= ''.join(url_list
)
2167 data
= """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2168 <Source href="{1:s}"></Source>
2169 <Description>opnemano</Description>
2170 </InstantiateVdcTemplateParams>""".format(vdc_name
, vdc_template_ref
)
2171 headers
= vca
.vcloud_session
.get_vcloud_headers()
2172 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
2173 response
= Http
.post(url
=vm_list_rest_call
, headers
=headers
, data
=data
, verify
=vca
.verify
,
2175 # if we all ok we respond with content otherwise by default None
2176 if response
.status_code
>= 200 and response
.status_code
< 300:
2177 return response
.content
2180 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2181 self
.logger
.debug("Respond body {}".format(response
.content
))
2185 def create_vdc_rest(self
, vdc_name
=None):
2187 Method create network in vCloud director
2190 network_name - is network name to be created.
2191 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2192 It optional attribute. by default if no parent network indicate the first available will be used.
2195 The return network uuid or return None
2198 self
.logger
.info("Creating new vdc {}".format(vdc_name
))
2200 vca
= self
.connect_as_admin()
2202 raise vimconn
.vimconnConnectionException("self.connect() is failed")
2203 if vdc_name
is None:
2206 url_list
= [vca
.host
, '/api/admin/org/', self
.org_uuid
]
2207 vm_list_rest_call
= ''.join(url_list
)
2208 if not (not vca
.vcloud_session
or not vca
.vcloud_session
.organization
):
2209 response
= Http
.get(url
=vm_list_rest_call
,
2210 headers
=vca
.vcloud_session
.get_vcloud_headers(),
2214 provider_vdc_ref
= None
2215 add_vdc_rest_url
= None
2216 available_networks
= None
2218 if response
.status_code
!= requests
.codes
.ok
:
2219 self
.logger
.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call
,
2220 response
.status_code
))
2224 vm_list_xmlroot
= XmlElementTree
.fromstring(response
.content
)
2225 for child
in vm_list_xmlroot
:
2226 # application/vnd.vmware.admin.providervdc+xml
2227 if child
.tag
.split("}")[1] == 'Link':
2228 if child
.attrib
.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
2229 and child
.attrib
.get('rel') == 'add':
2230 add_vdc_rest_url
= child
.attrib
.get('href')
2232 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2233 self
.logger
.debug("Respond body {}".format(response
.content
))
2236 response
= self
.get_provider_rest(vca
=vca
)
2238 vm_list_xmlroot
= XmlElementTree
.fromstring(response
)
2239 for child
in vm_list_xmlroot
:
2240 if child
.tag
.split("}")[1] == 'ProviderVdcReferences':
2241 for sub_child
in child
:
2242 provider_vdc_ref
= sub_child
.attrib
.get('href')
2244 self
.logger
.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call
))
2245 self
.logger
.debug("Respond body {}".format(response
))
2248 if add_vdc_rest_url
is not None and provider_vdc_ref
is not None:
2249 data
= """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
2250 <AllocationModel>ReservationPool</AllocationModel>
2251 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
2252 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
2253 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
2254 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
2255 <ProviderVdcReference
2256 name="Main Provider"
2258 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name
),
2262 headers
= vca
.vcloud_session
.get_vcloud_headers()
2263 headers
['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
2264 response
= Http
.post(url
=add_vdc_rest_url
, headers
=headers
, data
=data
, verify
=vca
.verify
,
2267 # if we all ok we respond with content otherwise by default None
2268 if response
.status_code
== 201:
2269 return response
.content