Changes in vimconn_vmware.py :
[osm/RO.git] / vimconn_vmware.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
5 # This file is part of openmano
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact with: nfvlabs@tid.es
22 ##
23
24 """
25 vimconn_vmware implementation an Abstract class in order to interact with VMware vCloud Director.
26 mbayramov@vmware.com
27 """
28 from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
29
30 import vimconn
31 import os
32 import traceback
33 import itertools
34 import requests
35
36 from xml.etree import ElementTree as XmlElementTree
37
38 import yaml
39 from pyvcloud import Http
40 from pyvcloud.vcloudair import VCA
41 from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
42 vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
43 networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
44 from xml.sax.saxutils import escape
45
46 from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TaskType
47 from pyvcloud.schema.vcd.v1_5.schemas.vcloud.taskType import TaskType as GenericTask
48 from pyvcloud.schema.vcd.v1_5.schemas.vcloud.vAppType import TaskType as VappTask
49 from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TasksInProgressType
50
51 import logging
52 import json
53 import time
54 import uuid
55 import httplib
56 import hashlib
57
58 # global variable for vcd connector type
59 STANDALONE = 'standalone'
60
61 # key for flavor dicts
62 FLAVOR_RAM_KEY = 'ram'
63 FLAVOR_VCPUS_KEY = 'vcpus'
64
65 # global variables for number of retry
66 INTERVAL_TIME = 5
67 MAX_WAIT_TIME = 1800
68
69 VCAVERSION = '5.9'
70
71 __author__ = "Mustafa Bayramov, Arpita Kate"
72 __date__ = "$23-Dec-2016 11:09:29$"
73 __version__ = '0.1'
74
75 # -1: "Could not be created",
76 # 0: "Unresolved",
77 # 1: "Resolved",
78 # 2: "Deployed",
79 # 3: "Suspended",
80 # 4: "Powered on",
81 # 5: "Waiting for user input",
82 # 6: "Unknown state",
83 # 7: "Unrecognized state",
84 # 8: "Powered off",
85 # 9: "Inconsistent state",
86 # 10: "Children do not all have the same status",
87 # 11: "Upload initiated, OVF descriptor pending",
88 # 12: "Upload initiated, copying contents",
89 # 13: "Upload initiated , disk contents pending",
90 # 14: "Upload has been quarantined",
91 # 15: "Upload quarantine period has expired"
92
93 # mapping vCD status to MANO
94 vcdStatusCode2manoFormat = {4: 'ACTIVE',
95 7: 'PAUSED',
96 3: 'SUSPENDED',
97 8: 'INACTIVE',
98 12: 'BUILD',
99 -1: 'ERROR',
100 14: 'DELETED'}
101
102 #
103 netStatus2manoFormat = {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
104 'ERROR': 'ERROR', 'DELETED': 'DELETED'
105 }
106
107 # dict used to store flavor in memory
108 flavorlist = {}
109
110
111 class vimconnector(vimconn.vimconnector):
112 def __init__(self, uuid=None, name=None, tenant_id=None, tenant_name=None,
113 url=None, url_admin=None, user=None, passwd=None, log_level=None, config={}):
114 """
115 Constructor create vmware connector to vCloud director.
116
117 By default construct doesn't validate connection state. So client can create object with None arguments.
118 If client specified username , password and host and VDC name. Connector initialize other missing attributes.
119
120 a) It initialize organization UUID
121 b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
122
123 Args:
124 uuid - is organization uuid.
125 name - is organization name that must be presented in vCloud director.
126 tenant_id - is VDC uuid it must be presented in vCloud director
127 tenant_name - is VDC name.
128 url - is hostname or ip address of vCloud director
129 url_admin - same as above.
130 user - is user that administrator for organization. Caller must make sure that
131 username has right privileges.
132
133 password - is password for a user.
134
135 VMware connector also requires PVDC administrative privileges and separate account.
136 This variables must be passed via config argument dict contains keys
137
138 dict['admin_username']
139 dict['admin_password']
140
141 Returns:
142 Nothing.
143 """
144
145 vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
146 url_admin, user, passwd, log_level, config)
147
148 self.logger = logging.getLogger('openmano.vim.vmware')
149 self.logger.setLevel(10)
150
151 self.name = name
152 self.id = uuid
153 self.url = url
154 self.url_admin = url_admin
155 self.tenant_id = tenant_id
156 self.tenant_name = tenant_name
157 self.user = user
158 self.passwd = passwd
159 self.config = config
160 self.admin_password = None
161 self.admin_user = None
162 self.org_name = ""
163
164 if tenant_name is not None:
165 orgnameandtenant = tenant_name.split(":")
166 if len(orgnameandtenant) == 2:
167 self.tenant_name = orgnameandtenant[1]
168 self.org_name = orgnameandtenant[0]
169 else:
170 self.tenant_name = tenant_name
171 elif "orgname" in config:
172 self.org_name = config['orgname']
173
174 if log_level:
175 self.logger.setLevel(getattr(logging, log_level))
176
177 try:
178 self.admin_user = config['admin_username']
179 self.admin_password = config['admin_password']
180 except KeyError:
181 raise vimconn.vimconnException(message="Error admin username or admin password is empty.")
182
183 self.org_uuid = None
184 self.vca = None
185
186 if not url:
187 raise vimconn.vimconnException('url param can not be NoneType')
188
189 if not self.url_admin: # try to use normal url
190 self.url_admin = self.url
191
192 logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.org_name,
193 self.tenant_id, self.tenant_name))
194 logging.debug("vcd url {} vcd username: {} vcd password: {}".format(self.url, self.user, self.passwd))
195 logging.debug("vcd admin username {} vcd admin passowrd {}".format(self.admin_user, self.admin_password))
196
197 # initialize organization
198 if self.user is not None and self.passwd is not None and self.url:
199 self.init_organization()
200
201 def __getitem__(self, index):
202 if index == 'name':
203 return self.name
204 if index == 'tenant_id':
205 return self.tenant_id
206 if index == 'tenant_name':
207 return self.tenant_name
208 elif index == 'id':
209 return self.id
210 elif index == 'org_name':
211 return self.org_name
212 elif index == 'org_uuid':
213 return self.org_uuid
214 elif index == 'user':
215 return self.user
216 elif index == 'passwd':
217 return self.passwd
218 elif index == 'url':
219 return self.url
220 elif index == 'url_admin':
221 return self.url_admin
222 elif index == "config":
223 return self.config
224 else:
225 raise KeyError("Invalid key '%s'" % str(index))
226
227 def __setitem__(self, index, value):
228 if index == 'name':
229 self.name = value
230 if index == 'tenant_id':
231 self.tenant_id = value
232 if index == 'tenant_name':
233 self.tenant_name = value
234 elif index == 'id':
235 self.id = value
236 elif index == 'org_name':
237 self.org_name = value
238 elif index == 'org_uuid':
239 self.org_uuid = value
240 elif index == 'user':
241 self.user = value
242 elif index == 'passwd':
243 self.passwd = value
244 elif index == 'url':
245 self.url = value
246 elif index == 'url_admin':
247 self.url_admin = value
248 else:
249 raise KeyError("Invalid key '%s'" % str(index))
250
251 def connect_as_admin(self):
252 """ Method connect as pvdc admin user to vCloud director.
253 There are certain action that can be done only by provider vdc admin user.
254 Organization creation / provider network creation etc.
255
256 Returns:
257 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
258 """
259
260 self.logger.debug("Logging in to a vca {} as admin.".format(self.org_name))
261
262 vca_admin = VCA(host=self.url,
263 username=self.admin_user,
264 service_type=STANDALONE,
265 version=VCAVERSION,
266 verify=False,
267 log=False)
268 result = vca_admin.login(password=self.admin_password, org='System')
269 if not result:
270 raise vimconn.vimconnConnectionException(
271 "Can't connect to a vCloud director as: {}".format(self.admin_user))
272 result = vca_admin.login(token=vca_admin.token, org='System', org_url=vca_admin.vcloud_session.org_url)
273 if result is True:
274 self.logger.info(
275 "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self.admin_user))
276
277 return vca_admin
278
279 def connect(self):
280 """ Method connect as normal user to vCloud director.
281
282 Returns:
283 The return vca object that letter can be used to connect to vCloud director as admin for VDC
284 """
285
286 try:
287 self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org_name,
288 self.user,
289 self.org_name))
290 vca = VCA(host=self.url,
291 username=self.user,
292 service_type=STANDALONE,
293 version=VCAVERSION,
294 verify=False,
295 log=False)
296
297 result = vca.login(password=self.passwd, org=self.org_name)
298 if not result:
299 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
300 result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
301 if result is True:
302 self.logger.info(
303 "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org_name, self.user))
304
305 except:
306 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
307 "{} as user: {}".format(self.org_name, self.user))
308
309 return vca
310
311 def init_organization(self):
312 """ Method initialize organization UUID and VDC parameters.
313
314 At bare minimum client must provide organization name that present in vCloud director and VDC.
315
316 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
317 The Org - UUID will be initialized at the run time if data center present in vCloud director.
318
319 Returns:
320 The return vca object that letter can be used to connect to vcloud direct as admin
321 """
322 try:
323 if self.org_uuid is None:
324 org_dict = self.get_org_list()
325 for org in org_dict:
326 # we set org UUID at the init phase but we can do it only when we have valid credential.
327 if org_dict[org] == self.org_name:
328 self.org_uuid = org
329 self.logger.debug("Setting organization UUID {}".format(self.org_uuid))
330 break
331 else:
332 raise vimconn.vimconnException("Vcloud director organization {} not found".format(self.org_name))
333
334 # if well good we require for org details
335 org_details_dict = self.get_org(org_uuid=self.org_uuid)
336
337 # we have two case if we want to initialize VDC ID or VDC name at run time
338 # tenant_name provided but no tenant id
339 if self.tenant_id is None and self.tenant_name is not None and 'vdcs' in org_details_dict:
340 vdcs_dict = org_details_dict['vdcs']
341 for vdc in vdcs_dict:
342 if vdcs_dict[vdc] == self.tenant_name:
343 self.tenant_id = vdc
344 self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
345 self.org_name))
346 break
347 else:
348 raise vimconn.vimconnException("Tenant name indicated but not present in vcloud director.")
349 # case two we have tenant_id but we don't have tenant name so we find and set it.
350 if self.tenant_id is not None and self.tenant_name is None and 'vdcs' in org_details_dict:
351 vdcs_dict = org_details_dict['vdcs']
352 for vdc in vdcs_dict:
353 if vdc == self.tenant_id:
354 self.tenant_name = vdcs_dict[vdc]
355 self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
356 self.org_name))
357 break
358 else:
359 raise vimconn.vimconnException("Tenant id indicated but not present in vcloud director")
360 self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
361 except:
362 self.logger.debug("Failed initialize organization UUID for org {}".format(self.org_name))
363 self.logger.debug(traceback.format_exc())
364 self.org_uuid = None
365
366 def new_tenant(self, tenant_name=None, tenant_description=None):
367 """ Method adds a new tenant to VIM with this name.
368 This action requires access to create VDC action in vCloud director.
369
370 Args:
371 tenant_name is tenant_name to be created.
372 tenant_description not used for this call
373
374 Return:
375 returns the tenant identifier in UUID format.
376 If action is failed method will throw vimconn.vimconnException method
377 """
378 vdc_task = self.create_vdc(vdc_name=tenant_name)
379 if vdc_task is not None:
380 vdc_uuid, value = vdc_task.popitem()
381 self.logger.info("Crated new vdc {} and uuid: {}".format(tenant_name, vdc_uuid))
382 return vdc_uuid
383 else:
384 raise vimconn.vimconnException("Failed create tenant {}".format(tenant_name))
385
386 def delete_tenant(self, tenant_id=None):
387 """Delete a tenant from VIM"""
388 'Returns the tenant identifier'
389 raise vimconn.vimconnNotImplemented("Should have implemented this")
390
391 def get_tenant_list(self, filter_dict={}):
392 """Obtain tenants of VIM
393 filter_dict can contain the following keys:
394 name: filter by tenant name
395 id: filter by tenant uuid/id
396 <other VIM specific>
397 Returns the tenant list of dictionaries:
398 [{'name':'<name>, 'id':'<id>, ...}, ...]
399
400 """
401 org_dict = self.get_org(self.org_uuid)
402 vdcs_dict = org_dict['vdcs']
403
404 vdclist = []
405 try:
406 for k in vdcs_dict:
407 entry = {'name': vdcs_dict[k], 'id': k}
408 # if caller didn't specify dictionary we return all tenants.
409 if filter_dict is not None and filter_dict:
410 filtered_entry = entry.copy()
411 filtered_dict = set(entry.keys()) - set(filter_dict)
412 for unwanted_key in filtered_dict: del entry[unwanted_key]
413 if filter_dict == entry:
414 vdclist.append(filtered_entry)
415 else:
416 vdclist.append(entry)
417 except:
418 self.logger.debug("Error in get_tenant_list()")
419 self.logger.debug(traceback.format_exc())
420 raise vimconn.vimconnException("Incorrect state. {}")
421
422 return vdclist
423
424 def new_network(self, net_name, net_type, ip_profile=None, shared=False):
425 """Adds a tenant network to VIM
426 net_name is the name
427 net_type can be 'bridge','data'.'ptp'. TODO: this need to be revised
428 ip_profile is a dict containing the IP parameters of the network
429 shared is a boolean
430 Returns the network identifier"""
431
432 self.logger.debug(
433 "new_network tenant {} net_type {} ip_profile {} shared {}".format(net_name, net_type, ip_profile, shared))
434
435 isshared = 'false'
436 if shared:
437 isshared = 'true'
438
439 network_uuid = self.create_network(network_name=net_name, isshared=isshared)
440 if network_uuid is not None:
441 return network_uuid
442 else:
443 raise vimconn.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name))
444
445 def get_vcd_network_list(self):
446 """ Method available organization for a logged in tenant
447
448 Returns:
449 The return vca object that letter can be used to connect to vcloud direct as admin
450 """
451
452 self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
453 vca = self.connect()
454 if not vca:
455 raise vimconn.vimconnConnectionException("self.connect() is failed.")
456
457 if not self.tenant_name:
458 raise vimconn.vimconnConnectionException("Tenant name is empty.")
459
460 vdc = vca.get_vdc(self.tenant_name)
461 if vdc is None:
462 raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
463
464 vdc_uuid = vdc.get_id().split(":")[3]
465 networks = vca.get_networks(vdc.get_name())
466 network_list = []
467 try:
468 for network in networks:
469 filter_dict = {}
470 netid = network.get_id().split(":")
471 if len(netid) != 4:
472 continue
473
474 filter_dict["name"] = network.get_name()
475 filter_dict["id"] = netid[3]
476 filter_dict["shared"] = network.get_IsShared()
477 filter_dict["tenant_id"] = vdc_uuid
478 if network.get_status() == 1:
479 filter_dict["admin_state_up"] = True
480 else:
481 filter_dict["admin_state_up"] = False
482 filter_dict["status"] = "ACTIVE"
483 filter_dict["type"] = "bridge"
484 network_list.append(filter_dict)
485 self.logger.debug("get_vcd_network_list adding entry {}".format(filter_dict))
486 except:
487 self.logger.debug("Error in get_vcd_network_list")
488 self.logger.debug(traceback.format_exc())
489 pass
490
491 self.logger.debug("get_vcd_network_list returning {}".format(network_list))
492 return network_list
493
494 def get_network_list(self, filter_dict={}):
495 """Obtain tenant networks of VIM
496 Filter_dict can be:
497 name: network name OR/AND
498 id: network uuid OR/AND
499 shared: boolean OR/AND
500 tenant_id: tenant OR/AND
501 admin_state_up: boolean
502 status: 'ACTIVE'
503
504 [{key : value , key : value}]
505
506 Returns the network list of dictionaries:
507 [{<the fields at Filter_dict plus some VIM specific>}, ...]
508 List can be empty
509 """
510
511 self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
512 vca = self.connect()
513 if not vca:
514 raise vimconn.vimconnConnectionException("self.connect() is failed.")
515
516 if not self.tenant_name:
517 raise vimconn.vimconnConnectionException("Tenant name is empty.")
518
519 vdc = vca.get_vdc(self.tenant_name)
520 if vdc is None:
521 raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
522
523 vdcid = vdc.get_id().split(":")[3]
524 networks = vca.get_networks(vdc.get_name())
525 network_list = []
526
527 try:
528 for network in networks:
529 filter_entry = {}
530 net_uuid = network.get_id().split(":")
531 if len(net_uuid) != 4:
532 continue
533 else:
534 net_uuid = net_uuid[3]
535 # create dict entry
536 self.logger.debug("Adding {} to a list vcd id {} network {}".format(net_uuid,
537 vdcid,
538 network.get_name()))
539 filter_entry["name"] = network.get_name()
540 filter_entry["id"] = net_uuid
541 filter_entry["shared"] = network.get_IsShared()
542 filter_entry["tenant_id"] = vdcid
543 if network.get_status() == 1:
544 filter_entry["admin_state_up"] = True
545 else:
546 filter_entry["admin_state_up"] = False
547 filter_entry["status"] = "ACTIVE"
548 filter_entry["type"] = "bridge"
549 filtered_entry = filter_entry.copy()
550
551 if filter_dict is not None and filter_dict:
552 # we remove all the key : value we don't care and match only
553 # respected field
554 filtered_dict = set(filter_entry.keys()) - set(filter_dict)
555 for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
556 if filter_dict == filter_entry:
557 network_list.append(filtered_entry)
558 else:
559 network_list.append(filtered_entry)
560 except:
561 self.logger.debug("Error in get_vcd_network_list")
562 self.logger.debug(traceback.format_exc())
563
564 self.logger.debug("Returning {}".format(network_list))
565 return network_list
566
567 def get_network(self, net_id):
568 """Method obtains network details of net_id VIM network
569 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
570
571 vca = self.connect()
572 if not vca:
573 raise vimconn.vimconnConnectionException("self.connect() is failed")
574
575 vdc = vca.get_vdc(self.tenant_name)
576 vdc_id = vdc.get_id().split(":")[3]
577
578 networks = vca.get_networks(vdc.get_name())
579 filter_dict = {}
580
581 try:
582 for network in networks:
583 vdc_network_id = network.get_id().split(":")
584 if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
585 filter_dict["name"] = network.get_name()
586 filter_dict["id"] = vdc_network_id[3]
587 filter_dict["shared"] = network.get_IsShared()
588 filter_dict["tenant_id"] = vdc_id
589 if network.get_status() == 1:
590 filter_dict["admin_state_up"] = True
591 else:
592 filter_dict["admin_state_up"] = False
593 filter_dict["status"] = "ACTIVE"
594 filter_dict["type"] = "bridge"
595 self.logger.debug("Returning {}".format(filter_dict))
596 return filter_dict
597 except:
598 self.logger.debug("Error in get_network")
599 self.logger.debug(traceback.format_exc())
600
601 return filter_dict
602
603 def delete_network(self, net_id):
604 """
605 Method Deletes a tenant network from VIM, provide the network id.
606
607 Returns the network identifier or raise an exception
608 """
609
610 vca = self.connect()
611 if not vca:
612 raise vimconn.vimconnConnectionException("self.connect() for tenant {} is failed.".format(self.tenant_name))
613
614 vcd_network = self.get_vcd_network(network_uuid=net_id)
615 if vcd_network is not None and vcd_network:
616 if self.delete_network_action(network_uuid=net_id):
617 return net_id
618 else:
619 raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
620
621 def refresh_nets_status(self, net_list):
622 """Get the status of the networks
623 Params: the list of network identifiers
624 Returns a dictionary with:
625 net_id: #VIM id of this network
626 status: #Mandatory. Text with one of:
627 # DELETED (not found at vim)
628 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
629 # OTHER (Vim reported other status not understood)
630 # ERROR (VIM indicates an ERROR status)
631 # ACTIVE, INACTIVE, DOWN (admin down),
632 # BUILD (on building process)
633 #
634 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
635 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
636
637 """
638
639 vca = self.connect()
640 if not vca:
641 raise vimconn.vimconnConnectionException("self.connect() is failed")
642
643 dict_entry = {}
644 try:
645 for net in net_list:
646 errormsg = ''
647 vcd_network = self.get_vcd_network(network_uuid=net)
648 if vcd_network is not None and vcd_network:
649 if vcd_network['status'] == '1':
650 status = 'ACTIVE'
651 else:
652 status = 'DOWN'
653 else:
654 status = 'DELETED'
655 errormsg = 'Network not found.'
656
657 dict_entry[net] = {'status': status, 'error_msg': errormsg,
658 'vim_info': yaml.safe_dump(vcd_network)}
659 except:
660 self.logger.debug("Error in refresh_nets_status")
661 self.logger.debug(traceback.format_exc())
662
663 return dict_entry
664
665 def get_flavor(self, flavor_id):
666 """Obtain flavor details from the VIM
667 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
668 """
669 if flavor_id not in flavorlist:
670 raise vimconn.vimconnNotFoundException("Flavor not found.")
671 return flavorlist[flavor_id]
672
673 def new_flavor(self, flavor_data):
674 """Adds a tenant flavor to VIM
675 flavor_data contains a dictionary with information, keys:
676 name: flavor name
677 ram: memory (cloud type) in MBytes
678 vpcus: cpus (cloud type)
679 extended: EPA parameters
680 - numas: #items requested in same NUMA
681 memory: number of 1G huge pages memory
682 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
683 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
684 - name: interface name
685 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
686 bandwidth: X Gbps; requested guarantee bandwidth
687 vpci: requested virtual PCI address
688 disk: disk size
689 is_public:
690
691
692
693 #TODO to concrete
694 Returns the flavor identifier"""
695
696 # generate a new uuid put to internal dict and return it.
697 flavor_id = uuid.uuid4()
698 flavorlist[str(flavor_id)] = flavor_data
699
700 return str(flavor_id)
701
702 def delete_flavor(self, flavor_id):
703 """Deletes a tenant flavor from VIM identify by its id
704
705 Returns the used id or raise an exception
706 """
707 if flavor_id not in flavorlist:
708 raise vimconn.vimconnNotFoundException("Flavor not found.")
709
710 flavorlist.pop(flavor_id, None)
711 return flavor_id
712
713 def new_image(self, image_dict):
714 """
715 Adds a tenant image to VIM
716 Returns:
717 200, image-id if the image is created
718 <0, message if there is an error
719 """
720
721 return self.get_image_id_from_path(image_dict['location'])
722
723 def delete_image(self, image_id):
724 """
725
726 :param image_id:
727 :return:
728 """
729
730 raise vimconn.vimconnNotImplemented("Should have implemented this")
731
732 def catalog_exists(self, catalog_name, catalogs):
733 """
734
735 :param catalog_name:
736 :param catalogs:
737 :return:
738 """
739 for catalog in catalogs:
740 if catalog.name == catalog_name:
741 return True
742 return False
743
744 def create_vimcatalog(self, vca=None, catalog_name=None):
745 """ Create new catalog entry in vCloud director.
746
747 Args
748 vca: vCloud director.
749 catalog_name catalog that client wish to create. Note no validation done for a name.
750 Client must make sure that provide valid string representation.
751
752 Return (bool) True if catalog created.
753
754 """
755 try:
756 task = vca.create_catalog(catalog_name, catalog_name)
757 result = vca.block_until_completed(task)
758 if not result:
759 return False
760 catalogs = vca.get_catalogs()
761 except:
762 return False
763 return self.catalog_exists(catalog_name, catalogs)
764
765 # noinspection PyIncorrectDocstring
766 def upload_ovf(self, vca=None, catalog_name=None, image_name=None, media_file_name=None,
767 description='', progress=False, chunk_bytes=128 * 1024):
768 """
769 Uploads a OVF file to a vCloud catalog
770
771 :param chunk_bytes:
772 :param progress:
773 :param description:
774 :param image_name:
775 :param vca:
776 :param catalog_name: (str): The name of the catalog to upload the media.
777 :param media_file_name: (str): The name of the local media file to upload.
778 :return: (bool) True if the media file was successfully uploaded, false otherwise.
779 """
780 os.path.isfile(media_file_name)
781 statinfo = os.stat(media_file_name)
782
783 # find a catalog entry where we upload OVF.
784 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
785 # status change.
786 # if VCD can parse OVF we upload VMDK file
787 for catalog in vca.get_catalogs():
788 if catalog_name != catalog.name:
789 continue
790 link = filter(lambda link: link.get_type() == "application/vnd.vmware.vcloud.media+xml" and
791 link.get_rel() == 'add', catalog.get_Link())
792 assert len(link) == 1
793 data = """
794 <UploadVAppTemplateParams name="%s" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>%s vApp Template</Description></UploadVAppTemplateParams>
795 """ % (escape(catalog_name), escape(description))
796 headers = vca.vcloud_session.get_vcloud_headers()
797 headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
798 response = Http.post(link[0].get_href(), headers=headers, data=data, verify=vca.verify, logger=self.logger)
799 if response.status_code == requests.codes.created:
800 catalogItem = XmlElementTree.fromstring(response.content)
801 entity = [child for child in catalogItem if
802 child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
803 href = entity.get('href')
804 template = href
805 response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
806 verify=vca.verify, logger=self.logger)
807
808 if response.status_code == requests.codes.ok:
809 media = mediaType.parseString(response.content, True)
810 link = filter(lambda link: link.get_rel() == 'upload:default',
811 media.get_Files().get_File()[0].get_Link())[0]
812 headers = vca.vcloud_session.get_vcloud_headers()
813 headers['Content-Type'] = 'Content-Type text/xml'
814 response = Http.put(link.get_href(),
815 data=open(media_file_name, 'rb'),
816 headers=headers,
817 verify=vca.verify, logger=self.logger)
818 if response.status_code != requests.codes.ok:
819 self.logger.debug(
820 "Failed create vApp template for catalog name {} and image {}".format(catalog_name,
821 media_file_name))
822 return False
823
824 # TODO fix this with aync block
825 time.sleep(5)
826
827 self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
828
829 # uploading VMDK file
830 # check status of OVF upload and upload remaining files.
831 response = Http.get(template,
832 headers=vca.vcloud_session.get_vcloud_headers(),
833 verify=vca.verify,
834 logger=self.logger)
835
836 if response.status_code == requests.codes.ok:
837 media = mediaType.parseString(response.content, True)
838 number_of_files = len(media.get_Files().get_File())
839 for index in xrange(0, number_of_files):
840 links_list = filter(lambda link: link.get_rel() == 'upload:default',
841 media.get_Files().get_File()[index].get_Link())
842 for link in links_list:
843 # we skip ovf since it already uploaded.
844 if 'ovf' in link.get_href():
845 continue
846 # The OVF file and VMDK must be in a same directory
847 head, tail = os.path.split(media_file_name)
848 file_vmdk = head + '/' + link.get_href().split("/")[-1]
849 if not os.path.isfile(file_vmdk):
850 return False
851 statinfo = os.stat(file_vmdk)
852 if statinfo.st_size == 0:
853 return False
854 hrefvmdk = link.get_href()
855
856 if progress:
857 print("Uploading file: {}".format(file_vmdk))
858 if progress:
859 widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
860 FileTransferSpeed()]
861 progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
862
863 bytes_transferred = 0
864 f = open(file_vmdk, 'rb')
865 while bytes_transferred < statinfo.st_size:
866 my_bytes = f.read(chunk_bytes)
867 if len(my_bytes) <= chunk_bytes:
868 headers = vca.vcloud_session.get_vcloud_headers()
869 headers['Content-Range'] = 'bytes %s-%s/%s' % (
870 bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
871 headers['Content-Length'] = str(len(my_bytes))
872 response = Http.put(hrefvmdk,
873 headers=headers,
874 data=my_bytes,
875 verify=vca.verify,
876 logger=None)
877
878 if response.status_code == requests.codes.ok:
879 bytes_transferred += len(my_bytes)
880 if progress:
881 progress_bar.update(bytes_transferred)
882 else:
883 self.logger.debug(
884 'file upload failed with error: [%s] %s' % (response.status_code,
885 response.content))
886
887 f.close()
888 return False
889 f.close()
890 if progress:
891 progress_bar.finish()
892 return True
893 else:
894 self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
895 format(catalog_name, media_file_name))
896 return False
897
898 self.logger.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
899 return False
900
901 def upload_vimimage(self, vca=None, catalog_name=None, media_name=None, medial_file_name=None, progress=False):
902 """Upload media file"""
903 # TODO add named parameters for readability
904
905 return self.upload_ovf(vca=vca, catalog_name=catalog_name, image_name=media_name.split(".")[0],
906 media_file_name=medial_file_name, description='medial_file_name', progress=progress)
907
908 def validate_uuid4(self, uuid_string=None):
909 """ Method validate correct format of UUID.
910
911 Return: true if string represent valid uuid
912 """
913 try:
914 val = uuid.UUID(uuid_string, version=4)
915 except ValueError:
916 return False
917 return True
918
919 def get_catalogid(self, catalog_name=None, catalogs=None):
920 """ Method check catalog and return catalog ID in UUID format.
921
922 Args
923 catalog_name: catalog name as string
924 catalogs: list of catalogs.
925
926 Return: catalogs uuid
927 """
928
929 for catalog in catalogs:
930 if catalog.name == catalog_name:
931 catalog_id = catalog.get_id().split(":")
932 return catalog_id[3]
933 return None
934
935 def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
936 """ Method check catalog and return catalog name lookup done by catalog UUID.
937
938 Args
939 catalog_name: catalog name as string
940 catalogs: list of catalogs.
941
942 Return: catalogs name or None
943 """
944
945 if not self.validate_uuid4(uuid_string=catalog_uuid):
946 return None
947
948 for catalog in catalogs:
949 catalog_id = catalog.get_id().split(":")[3]
950 if catalog_id == catalog_uuid:
951 return catalog.name
952 return None
953
954 def get_image_id_from_path(self, path=None, progress=False):
955 """ Method upload OVF image to vCloud director.
956
957 Each OVF image represented as single catalog entry in vcloud director.
958 The method check for existing catalog entry. The check done by file name without file extension.
959
960 if given catalog name already present method will respond with existing catalog uuid otherwise
961 it will create new catalog entry and upload OVF file to newly created catalog.
962
963 If method can't create catalog entry or upload a file it will throw exception.
964
965 Method accept boolean flag progress that will output progress bar. It useful method
966 for standalone upload use case. In case to test large file upload.
967
968 Args
969 path: - valid path to OVF file.
970 progress - boolean progress bar show progress bar.
971
972 Return: if image uploaded correct method will provide image catalog UUID.
973 """
974 vca = self.connect()
975 if not vca:
976 raise vimconn.vimconnConnectionException("self.connect() is failed.")
977
978 if not path:
979 raise vimconn.vimconnException("Image path can't be None.")
980
981 if not os.path.isfile(path):
982 raise vimconn.vimconnException("Can't read file. File not found.")
983
984 if not os.access(path, os.R_OK):
985 raise vimconn.vimconnException("Can't read file. Check file permission to read.")
986
987 self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
988
989 dirpath, filename = os.path.split(path)
990 flname, file_extension = os.path.splitext(path)
991 if file_extension != '.ovf':
992 self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
993 raise vimconn.vimconnException("Wrong container. vCloud director supports only OVF.")
994
995 catalog_name = os.path.splitext(filename)[0]
996 catalog_md5_name = hashlib.md5(path).hexdigest()
997 self.logger.debug("File name {} Catalog Name {} file path {} "
998 "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
999
1000 catalogs = vca.get_catalogs()
1001 if len(catalogs) == 0:
1002 self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
1003 result = self.create_vimcatalog(vca, catalog_md5_name)
1004 if not result:
1005 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
1006 result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
1007 media_name=filename, medial_file_name=path, progress=progress)
1008 if not result:
1009 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
1010 return self.get_catalogid(catalog_name, vca.get_catalogs())
1011 else:
1012 for catalog in catalogs:
1013 # search for existing catalog if we find same name we return ID
1014 # TODO optimize this
1015 if catalog.name == catalog_md5_name:
1016 self.logger.debug("Found existing catalog entry for {} "
1017 "catalog id {}".format(catalog_name,
1018 self.get_catalogid(catalog_md5_name, catalogs)))
1019 return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
1020
1021 # if we didn't find existing catalog we create a new one and upload image.
1022 self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
1023 result = self.create_vimcatalog(vca, catalog_md5_name)
1024 if not result:
1025 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
1026
1027 result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
1028 media_name=filename, medial_file_name=path, progress=progress)
1029 if not result:
1030 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
1031
1032 return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
1033
1034 def get_vappid(self, vdc=None, vapp_name=None):
1035 """ Method takes vdc object and vApp name and returns vapp uuid or None
1036
1037 Args:
1038 vdc: The VDC object.
1039 vapp_name: is application vappp name identifier
1040
1041 Returns:
1042 The return vApp name otherwise None
1043 """
1044 if vdc is None or vapp_name is None:
1045 return None
1046 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
1047 try:
1048 refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1049 vdc.ResourceEntities.ResourceEntity)
1050 if len(refs) == 1:
1051 return refs[0].href.split("vapp")[1][1:]
1052 except Exception as e:
1053 self.logger.exception(e)
1054 return False
1055 return None
1056
1057 def check_vapp(self, vdc=None, vapp_uuid=None):
1058 """ Method Method returns True or False if vapp deployed in vCloud director
1059
1060 Args:
1061 vca: Connector to VCA
1062 vdc: The VDC object.
1063 vappid: vappid is application identifier
1064
1065 Returns:
1066 The return True if vApp deployed
1067 :param vdc:
1068 :param vapp_uuid:
1069 """
1070 try:
1071 refs = filter(lambda ref:
1072 ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1073 vdc.ResourceEntities.ResourceEntity)
1074 for ref in refs:
1075 vappid = ref.href.split("vapp")[1][1:]
1076 # find vapp with respected vapp uuid
1077 if vappid == vapp_uuid:
1078 return True
1079 except Exception as e:
1080 self.logger.exception(e)
1081 return False
1082 return False
1083
1084 def get_namebyvappid(self, vca=None, vdc=None, vapp_uuid=None):
1085 """Method returns vApp name from vCD and lookup done by vapp_id.
1086
1087 Args:
1088 vca: Connector to VCA
1089 vdc: The VDC object.
1090 vapp_uuid: vappid is application identifier
1091
1092 Returns:
1093 The return vApp name otherwise None
1094 """
1095
1096 try:
1097 refs = filter(lambda ref: ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1098 vdc.ResourceEntities.ResourceEntity)
1099 for ref in refs:
1100 # we care only about UUID the rest doesn't matter
1101 vappid = ref.href.split("vapp")[1][1:]
1102 if vappid == vapp_uuid:
1103 response = Http.get(ref.href, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify,
1104 logger=self.logger)
1105 tree = XmlElementTree.fromstring(response.content)
1106 return tree.attrib['name']
1107 except Exception as e:
1108 self.logger.exception(e)
1109 return None
1110 return None
1111
1112 def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
1113 cloud_config=None, disk_list=None):
1114 """Adds a VM instance to VIM
1115 Params:
1116 start: indicates if VM must start or boot in pause mode. Ignored
1117 image_id,flavor_id: image and flavor uuid
1118 net_list: list of interfaces, each one is a dictionary with:
1119 name:
1120 net_id: network uuid to connect
1121 vpci: virtual vcpi to assign
1122 model: interface model, virtio, e2000, ...
1123 mac_address:
1124 use: 'data', 'bridge', 'mgmt'
1125 type: 'virtual', 'PF', 'VF', 'VFnotShared'
1126 vim_id: filled/added by this function
1127 cloud_config: can be a text script to be passed directly to cloud-init,
1128 or an object to inject users and ssh keys with format:
1129 key-pairs: [] list of keys to install to the default user
1130 users: [{ name, key-pairs: []}] list of users to add with their key-pair
1131 #TODO ip, security groups
1132 Returns >=0, the instance identifier
1133 <0, error_text
1134 """
1135
1136 self.logger.info("Creating new instance for entry {}".format(name))
1137 self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".
1138 format(description, start, image_id, flavor_id, net_list, cloud_config))
1139 vca = self.connect()
1140 if not vca:
1141 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1142
1143 #new vm name = vmname + tenant_id + uuid
1144 new_vm_name = [name, '-', str(uuid.uuid4())]
1145 vmname_andid = ''.join(new_vm_name)
1146
1147 # if vm already deployed we return existing uuid
1148 # vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
1149 # if vapp_uuid is not None:
1150 # return vapp_uuid
1151
1152 # we check for presence of VDC, Catalog entry and Flavor.
1153 vdc = vca.get_vdc(self.tenant_name)
1154 if vdc is None:
1155 raise vimconn.vimconnNotFoundException(
1156 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
1157 catalogs = vca.get_catalogs()
1158 if catalogs is None:
1159 raise vimconn.vimconnNotFoundException(
1160 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
1161
1162 catalog_hash_name = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
1163 if catalog_hash_name:
1164 self.logger.info("Found catalog entry {} for image id {}".format(catalog_hash_name, image_id))
1165 else:
1166 raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
1167 "(Failed retrieve catalog information {})".format(name, image_id))
1168
1169
1170 # Set vCPU and Memory based on flavor.
1171 #
1172 vm_cpus = None
1173 vm_memory = None
1174 if flavor_id is not None:
1175 if flavor_id not in flavorlist:
1176 raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
1177 "Failed retrieve flavor information "
1178 "flavor id {}".format(name, flavor_id))
1179 else:
1180 try:
1181 flavor = flavorlist[flavor_id]
1182 vm_cpus = flavor[FLAVOR_VCPUS_KEY]
1183 vm_memory = flavor[FLAVOR_RAM_KEY]
1184 except KeyError:
1185 raise vimconn.vimconnException("Corrupted flavor. {}".format(flavor_id))
1186
1187 # image upload creates template name as catalog name space Template.
1188 templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
1189 power_on = 'false'
1190 if start:
1191 power_on = 'true'
1192
1193 # client must provide at least one entry in net_list if not we report error
1194 #
1195 primary_netname = None
1196 network_mode = 'bridged'
1197 if net_list is not None and len(net_list) > 0:
1198 primary_net = net_list[0]
1199 if primary_net is None:
1200 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
1201 else:
1202 try:
1203 primary_net_id = primary_net['net_id']
1204 network_dict = self.get_vcd_network(network_uuid=primary_net_id)
1205 if 'name' in network_dict:
1206 primary_netname = network_dict['name']
1207 self.logger.info("Connecting VM to a network name {} "
1208 " network id {}".format(primary_netname, primary_net_id))
1209 if 'use' in primary_net:
1210 if primary_net['use'] == 'bridge':
1211 network_mode = 'bridged'
1212 except KeyError:
1213 raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
1214
1215 # use: 'data', 'bridge', 'mgmt'
1216 # create vApp. Set vcpu and ram based on flavor id.
1217 vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
1218 self.get_catalogbyid(image_id, catalogs),
1219 network_name=primary_netname, # can be None if net_list None
1220 network_mode=network_mode,
1221 vm_name=vmname_andid,
1222 vm_cpus=vm_cpus, # can be None if flavor is None
1223 vm_memory=vm_memory) # can be None if flavor is None
1224
1225 if vapptask is None or vapptask is False:
1226 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): failed deploy vApp {}".format(vmname_andid))
1227 if type(vapptask) is VappTask:
1228 vca.block_until_completed(vapptask)
1229
1230 # we should have now vapp in undeployed state.
1231 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
1232 if vapp is None:
1233 raise vimconn.vimconnUnexpectedResponse(
1234 "new_vminstance(): Failed failed retrieve vApp {} after we deployed".format(vmname_andid))
1235
1236 # add first NIC
1237 try:
1238 self.logger.info("Request to connect VM to a network: {}".format(net_list))
1239 nicIndex = 0
1240 for net in net_list:
1241 # openmano uses network id in UUID format.
1242 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
1243 # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
1244 # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
1245
1246 if 'net_id' not in net:
1247 continue
1248
1249 interface_net_id = net['net_id']
1250 interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
1251 interface_network_mode = net['use']
1252
1253 """- POOL (A static IP address is allocated automatically from a pool of addresses.)
1254 - DHCP (The IP address is obtained from a DHCP service.)
1255 - MANUAL (The IP address is assigned manually in the IpAddress element.)
1256 - NONE (No IP addressing mode specified.)"""
1257
1258 if primary_netname is not None:
1259 nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
1260 if len(nets) == 1:
1261 self.logger.info("Found requested network: {}".format(nets[0].name))
1262 task = vapp.connect_to_network(nets[0].name, nets[0].href)
1263 if type(task) is GenericTask:
1264 vca.block_until_completed(task)
1265 # connect network to VM
1266 # TODO figure out mapping between openmano representation to vCloud director.
1267 # one idea use first nic as management DHCP all remaining in bridge mode
1268 self.logger.info("Connecting VM to a network network {}".format(nets[0].name))
1269 task = vapp.connect_vms(nets[0].name,
1270 connection_index=nicIndex,
1271 connections_primary_index=nicIndex,
1272 ip_allocation_mode='DHCP')
1273 if type(task) is GenericTask:
1274 vca.block_until_completed(task)
1275 nicIndex += 1
1276 except KeyError:
1277 # it might be a case if specific mandatory entry in dict is empty
1278 self.logger.debug("Key error {}".format(KeyError.message))
1279 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
1280
1281 # deploy and power on vm
1282 task = vapp.poweron()
1283 if type(task) is TaskType:
1284 vca.block_until_completed(task)
1285 deploytask = vapp.deploy(powerOn='True')
1286 if type(task) is TaskType:
1287 vca.block_until_completed(deploytask)
1288
1289 # check if vApp deployed and if that the case return vApp UUID otherwise -1
1290 wait_time = 0
1291 vapp_uuid = None
1292 while wait_time <= MAX_WAIT_TIME:
1293 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
1294 if vapp and vapp.me.deployed:
1295 vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
1296 break
1297 else:
1298 self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
1299 time.sleep(INTERVAL_TIME)
1300
1301 wait_time +=INTERVAL_TIME
1302
1303 if vapp_uuid is not None:
1304 return vapp_uuid
1305 else:
1306 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
1307
1308 ##
1309 ##
1310 ## based on current discussion
1311 ##
1312 ##
1313 ## server:
1314 # created: '2016-09-08T11:51:58'
1315 # description: simple-instance.linux1.1
1316 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
1317 # hostId: e836c036-74e7-11e6-b249-0800273e724c
1318 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
1319 # status: ACTIVE
1320 # error_msg:
1321 # interfaces: …
1322 #
1323 def get_vminstance(self, vim_vm_uuid=None):
1324 """Returns the VM instance information from VIM"""
1325
1326 self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
1327 vca = self.connect()
1328 if not vca:
1329 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1330
1331 vdc = vca.get_vdc(self.tenant_name)
1332 if vdc is None:
1333 raise vimconn.vimconnConnectionException(
1334 "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
1335
1336 vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
1337 if not vm_info_dict:
1338 self.logger.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid))
1339 raise vimconn.vimconnNotFoundException("Failed to get vApp name by UUID {}".format(vim_vm_uuid))
1340
1341 status_key = vm_info_dict['status']
1342 error = ''
1343 try:
1344 vm_dict = {'created': vm_info_dict['created'],
1345 'description': vm_info_dict['name'],
1346 'status': vcdStatusCode2manoFormat[int(status_key)],
1347 'hostId': vm_info_dict['vmuuid'],
1348 'error_msg': error,
1349 'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
1350
1351 if 'interfaces' in vm_info_dict:
1352 vm_dict['interfaces'] = vm_info_dict['interfaces']
1353 else:
1354 vm_dict['interfaces'] = []
1355 except KeyError:
1356 vm_dict = {'created': '',
1357 'description': '',
1358 'status': vcdStatusCode2manoFormat[int(-1)],
1359 'hostId': vm_info_dict['vmuuid'],
1360 'error_msg': "Inconsistency state",
1361 'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
1362
1363 return vm_dict
1364
1365 def delete_vminstance(self, vm__vim_uuid):
1366 """Method poweroff and remove VM instance from vcloud director network.
1367
1368 Args:
1369 vm__vim_uuid: VM UUID
1370
1371 Returns:
1372 Returns the instance identifier
1373 """
1374
1375 self.logger.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid))
1376 vca = self.connect()
1377 if not vca:
1378 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1379
1380 vdc = vca.get_vdc(self.tenant_name)
1381 if vdc is None:
1382 self.logger.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
1383 self.tenant_name))
1384 raise vimconn.vimconnException(
1385 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
1386
1387 try:
1388 vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
1389 if vapp_name is None:
1390 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1391 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1392 else:
1393 self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
1394
1395 # Delete vApp and wait for status change if task executed and vApp is None.
1396 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1397
1398 if vapp:
1399 if vapp.me.deployed:
1400 self.logger.info("Powering off vApp {}".format(vapp_name))
1401 #Power off vApp
1402 powered_off = False
1403 wait_time = 0
1404 while wait_time <= MAX_WAIT_TIME:
1405 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1406 if not vapp:
1407 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1408 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1409
1410 power_off_task = vapp.poweroff()
1411 if type(power_off_task) is GenericTask:
1412 result = vca.block_until_completed(power_off_task)
1413 if result:
1414 powered_off = True
1415 break
1416 else:
1417 self.logger.info("Wait for vApp {} to power off".format(vapp_name))
1418 time.sleep(INTERVAL_TIME)
1419
1420 wait_time +=INTERVAL_TIME
1421 if not powered_off:
1422 self.logger.debug("delete_vminstance(): Failed to power off VM instance {} ".format(vm__vim_uuid))
1423 else:
1424 self.logger.info("delete_vminstance(): Powered off VM instance {} ".format(vm__vim_uuid))
1425
1426 #Undeploy vApp
1427 self.logger.info("Undeploy vApp {}".format(vapp_name))
1428 wait_time = 0
1429 undeployed = False
1430 while wait_time <= MAX_WAIT_TIME:
1431 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1432 if not vapp:
1433 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1434 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1435 undeploy_task = vapp.undeploy(action='powerOff')
1436
1437 if type(undeploy_task) is GenericTask:
1438 result = vca.block_until_completed(undeploy_task)
1439 if result:
1440 undeployed = True
1441 break
1442 else:
1443 self.logger.debug("Wait for vApp {} to undeploy".format(vapp_name))
1444 time.sleep(INTERVAL_TIME)
1445
1446 wait_time +=INTERVAL_TIME
1447
1448 if not undeployed:
1449 self.logger.debug("delete_vminstance(): Failed to undeploy vApp {} ".format(vm__vim_uuid))
1450
1451 # delete vapp
1452 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
1453 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1454
1455 if vapp is not None:
1456 wait_time = 0
1457 result = False
1458
1459 while wait_time <= MAX_WAIT_TIME:
1460 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1461 if not vapp:
1462 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1463 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1464
1465 delete_task = vapp.delete()
1466
1467 if type(delete_task) is GenericTask:
1468 vca.block_until_completed(delete_task)
1469 result = vca.block_until_completed(delete_task)
1470 if result:
1471 break
1472 else:
1473 self.logger.debug("Wait for vApp {} to delete".format(vapp_name))
1474 time.sleep(INTERVAL_TIME)
1475
1476 wait_time +=INTERVAL_TIME
1477
1478 if not result:
1479 self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
1480
1481 except:
1482 self.logger.debug(traceback.format_exc())
1483 raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
1484
1485 if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
1486 self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
1487 return vm__vim_uuid
1488 else:
1489 raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
1490
1491 def refresh_vms_status(self, vm_list):
1492 """Get the status of the virtual machines and their interfaces/ports
1493 Params: the list of VM identifiers
1494 Returns a dictionary with:
1495 vm_id: #VIM id of this Virtual Machine
1496 status: #Mandatory. Text with one of:
1497 # DELETED (not found at vim)
1498 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1499 # OTHER (Vim reported other status not understood)
1500 # ERROR (VIM indicates an ERROR status)
1501 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
1502 # CREATING (on building process), ERROR
1503 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
1504 #
1505 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1506 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1507 interfaces:
1508 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1509 mac_address: #Text format XX:XX:XX:XX:XX:XX
1510 vim_net_id: #network id where this interface is connected
1511 vim_interface_id: #interface/port VIM id
1512 ip_address: #null, or text with IPv4, IPv6 address
1513 """
1514
1515 self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
1516 vca = self.connect()
1517 if not vca:
1518 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1519
1520 vdc = vca.get_vdc(self.tenant_name)
1521 if vdc is None:
1522 raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
1523
1524 vms_dict = {}
1525 for vmuuid in vm_list:
1526 vmname = self.get_namebyvappid(vca, vdc, vmuuid)
1527 if vmname is not None:
1528
1529 the_vapp = vca.get_vapp(vdc, vmname)
1530 vm_info = the_vapp.get_vms_details()
1531 vm_status = vm_info[0]['status']
1532
1533 vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
1534 'error_msg': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
1535 'vim_info': yaml.safe_dump(the_vapp.get_vms_details()), 'interfaces': []}
1536
1537 # get networks
1538 try:
1539 vm_app_networks = the_vapp.get_vms_network_info()
1540 for vapp_network in vm_app_networks:
1541 for vm_network in vapp_network:
1542 if vm_network['name'] == vmname:
1543 interface = {"mac_address": vm_network['mac'],
1544 "vim_net_id": self.get_network_id_by_name(vm_network['network_name']),
1545 "vim_interface_id": self.get_network_id_by_name(vm_network['network_name']),
1546 'ip_address': vm_network['ip']}
1547 # interface['vim_info'] = yaml.safe_dump(vm_network)
1548 vm_dict["interfaces"].append(interface)
1549 # add a vm to vm dict
1550 vms_dict.setdefault(vmuuid, vm_dict)
1551 except KeyError:
1552 self.logger.debug("Error in respond {}".format(KeyError.message))
1553 self.logger.debug(traceback.format_exc())
1554
1555 return vms_dict
1556
1557 def action_vminstance(self, vm__vim_uuid=None, action_dict=None):
1558 """Send and action over a VM instance from VIM
1559 Returns the vm_id if the action was successfully sent to the VIM"""
1560
1561 self.logger.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid, action_dict))
1562 if vm__vim_uuid is None or action_dict is None:
1563 raise vimconn.vimconnException("Invalid request. VM id or action is None.")
1564
1565 vca = self.connect()
1566 if not vca:
1567 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1568
1569 vdc = vca.get_vdc(self.tenant_name)
1570 if vdc is None:
1571 return -1, "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name)
1572
1573 vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
1574 if vapp_name is None:
1575 self.logger.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1576 raise vimconn.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1577 else:
1578 self.logger.info("Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
1579
1580 try:
1581 the_vapp = vca.get_vapp(vdc, vapp_name)
1582 # TODO fix all status
1583 if "start" in action_dict:
1584 if action_dict["start"] == "rebuild":
1585 the_vapp.deploy(powerOn=True)
1586 else:
1587 vm_info = the_vapp.get_vms_details()
1588 vm_status = vm_info[0]['status']
1589 if vm_status == "Suspended":
1590 the_vapp.poweron()
1591 elif vm_status.status == "Powered off":
1592 the_vapp.poweron()
1593 elif "pause" in action_dict:
1594 pass
1595 ## server.pause()
1596 elif "resume" in action_dict:
1597 pass
1598 ## server.resume()
1599 elif "shutoff" in action_dict or "shutdown" in action_dict:
1600 the_vapp.shutdown()
1601 elif "forceOff" in action_dict:
1602 the_vapp.reset()
1603 elif "terminate" in action_dict:
1604 the_vapp.delete()
1605 # elif "createImage" in action_dict:
1606 # server.create_image()
1607 else:
1608 pass
1609 except:
1610 pass
1611
1612 def get_vminstance_console(self, vm_id, console_type="vnc"):
1613 """
1614 Get a console for the virtual machine
1615 Params:
1616 vm_id: uuid of the VM
1617 console_type, can be:
1618 "novnc" (by default), "xvpvnc" for VNC types,
1619 "rdp-html5" for RDP types, "spice-html5" for SPICE types
1620 Returns dict with the console parameters:
1621 protocol: ssh, ftp, http, https, ...
1622 server: usually ip address
1623 port: the http, ssh, ... port
1624 suffix: extra text, e.g. the http path and query string
1625 """
1626 raise vimconn.vimconnNotImplemented("Should have implemented this")
1627
1628 # NOT USED METHODS in current version
1629
1630 def host_vim2gui(self, host, server_dict):
1631 """Transform host dictionary from VIM format to GUI format,
1632 and append to the server_dict
1633 """
1634 raise vimconn.vimconnNotImplemented("Should have implemented this")
1635
1636 def get_hosts_info(self):
1637 """Get the information of deployed hosts
1638 Returns the hosts content"""
1639 raise vimconn.vimconnNotImplemented("Should have implemented this")
1640
1641 def get_hosts(self, vim_tenant):
1642 """Get the hosts and deployed instances
1643 Returns the hosts content"""
1644 raise vimconn.vimconnNotImplemented("Should have implemented this")
1645
1646 def get_processor_rankings(self):
1647 """Get the processor rankings in the VIM database"""
1648 raise vimconn.vimconnNotImplemented("Should have implemented this")
1649
1650 def new_host(self, host_data):
1651 """Adds a new host to VIM"""
1652 '''Returns status code of the VIM response'''
1653 raise vimconn.vimconnNotImplemented("Should have implemented this")
1654
1655 def new_external_port(self, port_data):
1656 """Adds a external port to VIM"""
1657 '''Returns the port identifier'''
1658 raise vimconn.vimconnNotImplemented("Should have implemented this")
1659
1660 def new_external_network(self, net_name, net_type):
1661 """Adds a external network to VIM (shared)"""
1662 '''Returns the network identifier'''
1663 raise vimconn.vimconnNotImplemented("Should have implemented this")
1664
1665 def connect_port_network(self, port_id, network_id, admin=False):
1666 """Connects a external port to a network"""
1667 '''Returns status code of the VIM response'''
1668 raise vimconn.vimconnNotImplemented("Should have implemented this")
1669
1670 def new_vminstancefromJSON(self, vm_data):
1671 """Adds a VM instance to VIM"""
1672 '''Returns the instance identifier'''
1673 raise vimconn.vimconnNotImplemented("Should have implemented this")
1674
1675 def get_network_name_by_id(self, network_uuid=None):
1676 """Method gets vcloud director network named based on supplied uuid.
1677
1678 Args:
1679 network_uuid: network_id
1680
1681 Returns:
1682 The return network name.
1683 """
1684
1685 vca = self.connect()
1686 if not vca:
1687 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1688
1689 if not network_uuid:
1690 return None
1691
1692 try:
1693 org_dict = self.get_org(self.org_uuid)
1694 if 'networks' in org_dict:
1695 org_network_dict = org_dict['networks']
1696 for net_uuid in org_network_dict:
1697 if net_uuid == network_uuid:
1698 return org_network_dict[net_uuid]
1699 except:
1700 self.logger.debug("Exception in get_network_name_by_id")
1701 self.logger.debug(traceback.format_exc())
1702
1703 return None
1704
1705 def get_network_id_by_name(self, network_name=None):
1706 """Method gets vcloud director network uuid based on supplied name.
1707
1708 Args:
1709 network_name: network_name
1710 Returns:
1711 The return network uuid.
1712 network_uuid: network_id
1713 """
1714
1715 vca = self.connect()
1716 if not vca:
1717 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1718
1719 if not network_name:
1720 self.logger.debug("get_network_id_by_name() : Network name is empty")
1721 return None
1722
1723 try:
1724 org_dict = self.get_org(self.org_uuid)
1725 if org_dict and 'networks' in org_dict:
1726 org_network_dict = org_dict['networks']
1727 for net_uuid,net_name in org_network_dict.iteritems():
1728 if net_name == network_name:
1729 return net_uuid
1730
1731 except KeyError as exp:
1732 self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
1733
1734 return None
1735
1736 def list_org_action(self):
1737 """
1738 Method leverages vCloud director and query for available organization for particular user
1739
1740 Args:
1741 vca - is active VCA connection.
1742 vdc_name - is a vdc name that will be used to query vms action
1743
1744 Returns:
1745 The return XML respond
1746 """
1747
1748 vca = self.connect()
1749 if not vca:
1750 raise vimconn.vimconnConnectionException("self.connect() is failed")
1751
1752 url_list = [vca.host, '/api/org']
1753 vm_list_rest_call = ''.join(url_list)
1754
1755 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
1756 response = Http.get(url=vm_list_rest_call,
1757 headers=vca.vcloud_session.get_vcloud_headers(),
1758 verify=vca.verify,
1759 logger=vca.logger)
1760 if response.status_code == requests.codes.ok:
1761 return response.content
1762
1763 return None
1764
1765 def get_org_action(self, org_uuid=None):
1766 """
1767 Method leverages vCloud director and retrieve available object fdr organization.
1768
1769 Args:
1770 vca - is active VCA connection.
1771 vdc_name - is a vdc name that will be used to query vms action
1772
1773 Returns:
1774 The return XML respond
1775 """
1776
1777 vca = self.connect()
1778 if not vca:
1779 raise vimconn.vimconnConnectionException("self.connect() is failed")
1780
1781 if org_uuid is None:
1782 return None
1783
1784 url_list = [vca.host, '/api/org/', org_uuid]
1785 vm_list_rest_call = ''.join(url_list)
1786
1787 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
1788 response = Http.get(url=vm_list_rest_call,
1789 headers=vca.vcloud_session.get_vcloud_headers(),
1790 verify=vca.verify,
1791 logger=vca.logger)
1792 if response.status_code == requests.codes.ok:
1793 return response.content
1794
1795 return None
1796
1797 def get_org(self, org_uuid=None):
1798 """
1799 Method retrieves available organization in vCloud Director
1800
1801 Args:
1802 org_uuid - is a organization uuid.
1803
1804 Returns:
1805 The return dictionary with following key
1806 "network" - for network list under the org
1807 "catalogs" - for network list under the org
1808 "vdcs" - for vdc list under org
1809 """
1810
1811 org_dict = {}
1812 vca = self.connect()
1813 if not vca:
1814 raise vimconn.vimconnConnectionException("self.connect() is failed")
1815
1816 if org_uuid is None:
1817 return org_dict
1818
1819 content = self.get_org_action(org_uuid=org_uuid)
1820 try:
1821 vdc_list = {}
1822 network_list = {}
1823 catalog_list = {}
1824 vm_list_xmlroot = XmlElementTree.fromstring(content)
1825 for child in vm_list_xmlroot:
1826 if child.attrib['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
1827 vdc_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
1828 org_dict['vdcs'] = vdc_list
1829 if child.attrib['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
1830 network_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
1831 org_dict['networks'] = network_list
1832 if child.attrib['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
1833 catalog_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
1834 org_dict['catalogs'] = catalog_list
1835 except:
1836 pass
1837
1838 return org_dict
1839
1840 def get_org_list(self):
1841 """
1842 Method retrieves available organization in vCloud Director
1843
1844 Args:
1845 vca - is active VCA connection.
1846
1847 Returns:
1848 The return dictionary and key for each entry VDC UUID
1849 """
1850
1851 org_dict = {}
1852 vca = self.connect()
1853 if not vca:
1854 raise vimconn.vimconnConnectionException("self.connect() is failed")
1855
1856 content = self.list_org_action()
1857 try:
1858 vm_list_xmlroot = XmlElementTree.fromstring(content)
1859 for vm_xml in vm_list_xmlroot:
1860 if vm_xml.tag.split("}")[1] == 'Org':
1861 org_uuid = vm_xml.attrib['href'].split('/')[-1:]
1862 org_dict[org_uuid[0]] = vm_xml.attrib['name']
1863 except:
1864 pass
1865
1866 return org_dict
1867
1868 def vms_view_action(self, vdc_name=None):
1869 """ Method leverages vCloud director vms query call
1870
1871 Args:
1872 vca - is active VCA connection.
1873 vdc_name - is a vdc name that will be used to query vms action
1874
1875 Returns:
1876 The return XML respond
1877 """
1878 vca = self.connect()
1879 if vdc_name is None:
1880 return None
1881
1882 url_list = [vca.host, '/api/vms/query']
1883 vm_list_rest_call = ''.join(url_list)
1884
1885 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
1886 refs = filter(lambda ref: ref.name == vdc_name and ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml',
1887 vca.vcloud_session.organization.Link)
1888 if len(refs) == 1:
1889 response = Http.get(url=vm_list_rest_call,
1890 headers=vca.vcloud_session.get_vcloud_headers(),
1891 verify=vca.verify,
1892 logger=vca.logger)
1893 if response.status_code == requests.codes.ok:
1894 return response.content
1895
1896 return None
1897
1898 def get_vapp_list(self, vdc_name=None):
1899 """
1900 Method retrieves vApp list deployed vCloud director and returns a dictionary
1901 contains a list of all vapp deployed for queried VDC.
1902 The key for a dictionary is vApp UUID
1903
1904
1905 Args:
1906 vca - is active VCA connection.
1907 vdc_name - is a vdc name that will be used to query vms action
1908
1909 Returns:
1910 The return dictionary and key for each entry vapp UUID
1911 """
1912
1913 vapp_dict = {}
1914 if vdc_name is None:
1915 return vapp_dict
1916
1917 content = self.vms_view_action(vdc_name=vdc_name)
1918 try:
1919 vm_list_xmlroot = XmlElementTree.fromstring(content)
1920 for vm_xml in vm_list_xmlroot:
1921 if vm_xml.tag.split("}")[1] == 'VMRecord':
1922 if vm_xml.attrib['isVAppTemplate'] == 'true':
1923 rawuuid = vm_xml.attrib['container'].split('/')[-1:]
1924 if 'vappTemplate-' in rawuuid[0]:
1925 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1926 # vm and use raw UUID as key
1927 vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
1928 except:
1929 pass
1930
1931 return vapp_dict
1932
1933 def get_vm_list(self, vdc_name=None):
1934 """
1935 Method retrieves VM's list deployed vCloud director. It returns a dictionary
1936 contains a list of all VM's deployed for queried VDC.
1937 The key for a dictionary is VM UUID
1938
1939
1940 Args:
1941 vca - is active VCA connection.
1942 vdc_name - is a vdc name that will be used to query vms action
1943
1944 Returns:
1945 The return dictionary and key for each entry vapp UUID
1946 """
1947 vm_dict = {}
1948
1949 if vdc_name is None:
1950 return vm_dict
1951
1952 content = self.vms_view_action(vdc_name=vdc_name)
1953 try:
1954 vm_list_xmlroot = XmlElementTree.fromstring(content)
1955 for vm_xml in vm_list_xmlroot:
1956 if vm_xml.tag.split("}")[1] == 'VMRecord':
1957 if vm_xml.attrib['isVAppTemplate'] == 'false':
1958 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
1959 if 'vm-' in rawuuid[0]:
1960 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
1961 # vm and use raw UUID as key
1962 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
1963 except:
1964 pass
1965
1966 return vm_dict
1967
1968 def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
1969 """
1970 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
1971 contains a list of all VM's deployed for queried VDC.
1972 The key for a dictionary is VM UUID
1973
1974
1975 Args:
1976 vca - is active VCA connection.
1977 vdc_name - is a vdc name that will be used to query vms action
1978
1979 Returns:
1980 The return dictionary and key for each entry vapp UUID
1981 """
1982 vm_dict = {}
1983 vca = self.connect()
1984 if not vca:
1985 raise vimconn.vimconnConnectionException("self.connect() is failed")
1986
1987 if vdc_name is None:
1988 return vm_dict
1989
1990 content = self.vms_view_action(vdc_name=vdc_name)
1991 try:
1992 vm_list_xmlroot = XmlElementTree.fromstring(content)
1993 for vm_xml in vm_list_xmlroot:
1994 if vm_xml.tag.split("}")[1] == 'VMRecord' and vm_xml.attrib['isVAppTemplate'] == 'false':
1995 # lookup done by UUID
1996 if isuuid:
1997 if vapp_name in vm_xml.attrib['container']:
1998 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
1999 if 'vm-' in rawuuid[0]:
2000 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
2001 break
2002 # lookup done by Name
2003 else:
2004 if vapp_name in vm_xml.attrib['name']:
2005 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
2006 if 'vm-' in rawuuid[0]:
2007 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
2008 break
2009 except:
2010 pass
2011
2012 return vm_dict
2013
2014 def get_network_action(self, network_uuid=None):
2015 """
2016 Method leverages vCloud director and query network based on network uuid
2017
2018 Args:
2019 vca - is active VCA connection.
2020 network_uuid - is a network uuid
2021
2022 Returns:
2023 The return XML respond
2024 """
2025
2026 vca = self.connect()
2027 if not vca:
2028 raise vimconn.vimconnConnectionException("self.connect() is failed")
2029
2030 if network_uuid is None:
2031 return None
2032
2033 url_list = [vca.host, '/api/network/', network_uuid]
2034 vm_list_rest_call = ''.join(url_list)
2035
2036 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2037 response = Http.get(url=vm_list_rest_call,
2038 headers=vca.vcloud_session.get_vcloud_headers(),
2039 verify=vca.verify,
2040 logger=vca.logger)
2041 if response.status_code == requests.codes.ok:
2042 return response.content
2043
2044 return None
2045
2046 def get_vcd_network(self, network_uuid=None):
2047 """
2048 Method retrieves available network from vCloud Director
2049
2050 Args:
2051 network_uuid - is VCD network UUID
2052
2053 Each element serialized as key : value pair
2054
2055 Following keys available for access. network_configuration['Gateway'}
2056 <Configuration>
2057 <IpScopes>
2058 <IpScope>
2059 <IsInherited>true</IsInherited>
2060 <Gateway>172.16.252.100</Gateway>
2061 <Netmask>255.255.255.0</Netmask>
2062 <Dns1>172.16.254.201</Dns1>
2063 <Dns2>172.16.254.202</Dns2>
2064 <DnsSuffix>vmwarelab.edu</DnsSuffix>
2065 <IsEnabled>true</IsEnabled>
2066 <IpRanges>
2067 <IpRange>
2068 <StartAddress>172.16.252.1</StartAddress>
2069 <EndAddress>172.16.252.99</EndAddress>
2070 </IpRange>
2071 </IpRanges>
2072 </IpScope>
2073 </IpScopes>
2074 <FenceMode>bridged</FenceMode>
2075
2076 Returns:
2077 The return dictionary and key for each entry vapp UUID
2078 """
2079
2080 network_configuration = {}
2081 if network_uuid is None:
2082 return network_uuid
2083
2084 content = self.get_network_action(network_uuid=network_uuid)
2085 try:
2086 vm_list_xmlroot = XmlElementTree.fromstring(content)
2087
2088 network_configuration['status'] = vm_list_xmlroot.get("status")
2089 network_configuration['name'] = vm_list_xmlroot.get("name")
2090 network_configuration['uuid'] = vm_list_xmlroot.get("id").split(":")[3]
2091
2092 for child in vm_list_xmlroot:
2093 if child.tag.split("}")[1] == 'IsShared':
2094 network_configuration['isShared'] = child.text.strip()
2095 if child.tag.split("}")[1] == 'Configuration':
2096 for configuration in child.iter():
2097 tagKey = configuration.tag.split("}")[1].strip()
2098 if tagKey != "":
2099 network_configuration[tagKey] = configuration.text.strip()
2100 return network_configuration
2101 except:
2102 pass
2103
2104 return network_configuration
2105
2106 def delete_network_action(self, network_uuid=None):
2107 """
2108 Method delete given network from vCloud director
2109
2110 Args:
2111 network_uuid - is a network uuid that client wish to delete
2112
2113 Returns:
2114 The return None or XML respond or false
2115 """
2116
2117 vca = self.connect_as_admin()
2118 if not vca:
2119 raise vimconn.vimconnConnectionException("self.connect() is failed")
2120 if network_uuid is None:
2121 return False
2122
2123 url_list = [vca.host, '/api/admin/network/', network_uuid]
2124 vm_list_rest_call = ''.join(url_list)
2125
2126 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2127 response = Http.delete(url=vm_list_rest_call,
2128 headers=vca.vcloud_session.get_vcloud_headers(),
2129 verify=vca.verify,
2130 logger=vca.logger)
2131
2132 if response.status_code == 202:
2133 return True
2134
2135 return False
2136
2137 def create_network(self, network_name=None, parent_network_uuid=None, isshared='true'):
2138 """
2139 Method create network in vCloud director
2140
2141 Args:
2142 network_name - is network name to be created.
2143 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2144 It optional attribute. by default if no parent network indicate the first available will be used.
2145
2146 Returns:
2147 The return network uuid or return None
2148 """
2149
2150 new_network_name = [network_name, '-', str(uuid.uuid4())]
2151 content = self.create_network_rest(network_name=''.join(new_network_name),
2152 parent_network_uuid=parent_network_uuid,
2153 isshared=isshared)
2154 if content is None:
2155 self.logger.debug("Failed create network {}.".format(network_name))
2156 return None
2157
2158 try:
2159 vm_list_xmlroot = XmlElementTree.fromstring(content)
2160 vcd_uuid = vm_list_xmlroot.get('id').split(":")
2161 if len(vcd_uuid) == 4:
2162 self.logger.info("Create new network name: {} uuid: {}".format(network_name, vcd_uuid[3]))
2163 return vcd_uuid[3]
2164 except:
2165 self.logger.debug("Failed create network {}".format(network_name))
2166 return None
2167
2168 def create_network_rest(self, network_name=None, parent_network_uuid=None, isshared='true'):
2169 """
2170 Method create network in vCloud director
2171
2172 Args:
2173 network_name - is network name to be created.
2174 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2175 It optional attribute. by default if no parent network indicate the first available will be used.
2176
2177 Returns:
2178 The return network uuid or return None
2179 """
2180
2181 vca = self.connect_as_admin()
2182 if not vca:
2183 raise vimconn.vimconnConnectionException("self.connect() is failed.")
2184 if network_name is None:
2185 return None
2186
2187 url_list = [vca.host, '/api/admin/vdc/', self.tenant_id]
2188 vm_list_rest_call = ''.join(url_list)
2189 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2190 response = Http.get(url=vm_list_rest_call,
2191 headers=vca.vcloud_session.get_vcloud_headers(),
2192 verify=vca.verify,
2193 logger=vca.logger)
2194
2195 provider_network = None
2196 available_networks = None
2197 add_vdc_rest_url = None
2198
2199 if response.status_code != requests.codes.ok:
2200 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2201 response.status_code))
2202 return None
2203 else:
2204 try:
2205 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2206 for child in vm_list_xmlroot:
2207 if child.tag.split("}")[1] == 'ProviderVdcReference':
2208 provider_network = child.attrib.get('href')
2209 # application/vnd.vmware.admin.providervdc+xml
2210 if child.tag.split("}")[1] == 'Link':
2211 if child.attrib.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
2212 and child.attrib.get('rel') == 'add':
2213 add_vdc_rest_url = child.attrib.get('href')
2214 except:
2215 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2216 self.logger.debug("Respond body {}".format(response.content))
2217 return None
2218
2219 # find pvdc provided available network
2220 response = Http.get(url=provider_network,
2221 headers=vca.vcloud_session.get_vcloud_headers(),
2222 verify=vca.verify,
2223 logger=vca.logger)
2224 if response.status_code != requests.codes.ok:
2225 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2226 response.status_code))
2227 return None
2228
2229 # available_networks.split("/")[-1]
2230
2231 if parent_network_uuid is None:
2232 try:
2233 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2234 for child in vm_list_xmlroot.iter():
2235 if child.tag.split("}")[1] == 'AvailableNetworks':
2236 for networks in child.iter():
2237 # application/vnd.vmware.admin.network+xml
2238 if networks.attrib.get('href') is not None:
2239 available_networks = networks.attrib.get('href')
2240 break
2241 except:
2242 return None
2243
2244 # either use client provided UUID or search for a first available
2245 # if both are not defined we return none
2246 if parent_network_uuid is not None:
2247 url_list = [vca.host, '/api/admin/network/', parent_network_uuid]
2248 add_vdc_rest_url = ''.join(url_list)
2249
2250 # return response.content
2251 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2252 <Description>Openmano created</Description>
2253 <Configuration>
2254 <ParentNetwork href="{1:s}"/>
2255 <FenceMode>{2:s}</FenceMode>
2256 </Configuration>
2257 <IsShared>{3:s}</IsShared>
2258 </OrgVdcNetwork> """.format(escape(network_name), available_networks, "bridged", isshared)
2259
2260 headers = vca.vcloud_session.get_vcloud_headers()
2261 headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
2262 response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify, logger=vca.logger)
2263
2264 # if we all ok we respond with content otherwise by default None
2265 if response.status_code == 201:
2266 return response.content
2267 return None
2268
2269 def get_provider_rest(self, vca=None):
2270 """
2271 Method gets provider vdc view from vcloud director
2272
2273 Args:
2274 network_name - is network name to be created.
2275 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2276 It optional attribute. by default if no parent network indicate the first available will be used.
2277
2278 Returns:
2279 The return xml content of respond or None
2280 """
2281
2282 url_list = [vca.host, '/api/admin']
2283 response = Http.get(url=''.join(url_list),
2284 headers=vca.vcloud_session.get_vcloud_headers(),
2285 verify=vca.verify,
2286 logger=vca.logger)
2287
2288 if response.status_code == requests.codes.ok:
2289 return response.content
2290 return None
2291
2292 def create_vdc(self, vdc_name=None):
2293
2294 vdc_dict = {}
2295
2296 xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
2297 if xml_content is not None:
2298 try:
2299 task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
2300 for child in task_resp_xmlroot:
2301 if child.tag.split("}")[1] == 'Owner':
2302 vdc_id = child.attrib.get('href').split("/")[-1]
2303 vdc_dict[vdc_id] = task_resp_xmlroot.get('href')
2304 return vdc_dict
2305 except:
2306 self.logger.debug("Respond body {}".format(xml_content))
2307
2308 return None
2309
2310 def create_vdc_from_tmpl_rest(self, vdc_name=None):
2311 """
2312 Method create vdc in vCloud director based on VDC template.
2313 it uses pre-defined template that must be named openmano
2314
2315 Args:
2316 vdc_name - name of a new vdc.
2317
2318 Returns:
2319 The return xml content of respond or None
2320 """
2321
2322 self.logger.info("Creating new vdc {}".format(vdc_name))
2323 vca = self.connect()
2324 if not vca:
2325 raise vimconn.vimconnConnectionException("self.connect() is failed")
2326 if vdc_name is None:
2327 return None
2328
2329 url_list = [vca.host, '/api/vdcTemplates']
2330 vm_list_rest_call = ''.join(url_list)
2331 response = Http.get(url=vm_list_rest_call,
2332 headers=vca.vcloud_session.get_vcloud_headers(),
2333 verify=vca.verify,
2334 logger=vca.logger)
2335
2336 # container url to a template
2337 vdc_template_ref = None
2338 try:
2339 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2340 for child in vm_list_xmlroot:
2341 # application/vnd.vmware.admin.providervdc+xml
2342 # we need find a template from witch we instantiate VDC
2343 if child.tag.split("}")[1] == 'VdcTemplate':
2344 if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child.attrib.get(
2345 'name') == 'openmano':
2346 vdc_template_ref = child.attrib.get('href')
2347 except:
2348 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2349 self.logger.debug("Respond body {}".format(response.content))
2350 return None
2351
2352 # if we didn't found required pre defined template we return None
2353 if vdc_template_ref is None:
2354 return None
2355
2356 try:
2357 # instantiate vdc
2358 url_list = [vca.host, '/api/org/', self.org_uuid, '/action/instantiate']
2359 vm_list_rest_call = ''.join(url_list)
2360 data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2361 <Source href="{1:s}"></Source>
2362 <Description>opnemano</Description>
2363 </InstantiateVdcTemplateParams>""".format(vdc_name, vdc_template_ref)
2364 headers = vca.vcloud_session.get_vcloud_headers()
2365 headers['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
2366 response = Http.post(url=vm_list_rest_call, headers=headers, data=data, verify=vca.verify,
2367 logger=vca.logger)
2368 # if we all ok we respond with content otherwise by default None
2369 if response.status_code >= 200 and response.status_code < 300:
2370 return response.content
2371 return None
2372 except:
2373 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2374 self.logger.debug("Respond body {}".format(response.content))
2375
2376 return None
2377
2378 def create_vdc_rest(self, vdc_name=None):
2379 """
2380 Method create network in vCloud director
2381
2382 Args:
2383 network_name - is network name to be created.
2384 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2385 It optional attribute. by default if no parent network indicate the first available will be used.
2386
2387 Returns:
2388 The return network uuid or return None
2389 """
2390
2391 self.logger.info("Creating new vdc {}".format(vdc_name))
2392
2393 vca = self.connect_as_admin()
2394 if not vca:
2395 raise vimconn.vimconnConnectionException("self.connect() is failed")
2396 if vdc_name is None:
2397 return None
2398
2399 url_list = [vca.host, '/api/admin/org/', self.org_uuid]
2400 vm_list_rest_call = ''.join(url_list)
2401 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2402 response = Http.get(url=vm_list_rest_call,
2403 headers=vca.vcloud_session.get_vcloud_headers(),
2404 verify=vca.verify,
2405 logger=vca.logger)
2406
2407 provider_vdc_ref = None
2408 add_vdc_rest_url = None
2409 available_networks = None
2410
2411 if response.status_code != requests.codes.ok:
2412 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2413 response.status_code))
2414 return None
2415 else:
2416 try:
2417 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2418 for child in vm_list_xmlroot:
2419 # application/vnd.vmware.admin.providervdc+xml
2420 if child.tag.split("}")[1] == 'Link':
2421 if child.attrib.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
2422 and child.attrib.get('rel') == 'add':
2423 add_vdc_rest_url = child.attrib.get('href')
2424 except:
2425 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2426 self.logger.debug("Respond body {}".format(response.content))
2427 return None
2428
2429 response = self.get_provider_rest(vca=vca)
2430 try:
2431 vm_list_xmlroot = XmlElementTree.fromstring(response)
2432 for child in vm_list_xmlroot:
2433 if child.tag.split("}")[1] == 'ProviderVdcReferences':
2434 for sub_child in child:
2435 provider_vdc_ref = sub_child.attrib.get('href')
2436 except:
2437 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2438 self.logger.debug("Respond body {}".format(response))
2439 return None
2440
2441 if add_vdc_rest_url is not None and provider_vdc_ref is not None:
2442 data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
2443 <AllocationModel>ReservationPool</AllocationModel>
2444 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
2445 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
2446 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
2447 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
2448 <ProviderVdcReference
2449 name="Main Provider"
2450 href="{2:s}" />
2451 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name),
2452 escape(vdc_name),
2453 provider_vdc_ref)
2454
2455 headers = vca.vcloud_session.get_vcloud_headers()
2456 headers['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
2457 response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify,
2458 logger=vca.logger)
2459
2460 # if we all ok we respond with content otherwise by default None
2461 if response.status_code == 201:
2462 return response.content
2463 return None
2464
2465 def get_vapp_details_rest(self, vapp_uuid=None):
2466 """
2467 Method retrieve vapp detail from vCloud director
2468
2469 Args:
2470 vapp_uuid - is vapp identifier.
2471
2472 Returns:
2473 The return network uuid or return None
2474 """
2475
2476 parsed_respond = {}
2477
2478 vca = self.connect()
2479 if not vca:
2480 raise vimconn.vimconnConnectionException("self.connect() is failed")
2481 if vapp_uuid is None:
2482 return None
2483
2484 url_list = [vca.host, '/api/vApp/vapp-', vapp_uuid]
2485 get_vapp_restcall = ''.join(url_list)
2486 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2487 response = Http.get(url=get_vapp_restcall,
2488 headers=vca.vcloud_session.get_vcloud_headers(),
2489 verify=vca.verify,
2490 logger=vca.logger)
2491
2492 if response.status_code != requests.codes.ok:
2493 self.logger.debug("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
2494 response.status_code))
2495 return parsed_respond
2496
2497 try:
2498 xmlroot_respond = XmlElementTree.fromstring(response.content)
2499 parsed_respond['ovfDescriptorUploaded'] = xmlroot_respond.attrib['ovfDescriptorUploaded']
2500
2501 namespaces_ovf = {'ovf': 'http://schemas.dmtf.org/ovf/envelope/1'}
2502 namespace_vmm = {'vmw': 'http://www.vmware.com/schema/ovf'}
2503 namespace_vm = {'vm': 'http://www.vmware.com/vcloud/v1.5'}
2504
2505 created_section = xmlroot_respond.find('vm:DateCreated', namespace_vm)
2506 if created_section is not None:
2507 parsed_respond['created'] = created_section.text
2508
2509 network_section = xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig', namespace_vm)
2510 if network_section is not None and 'networkName' in network_section.attrib:
2511 parsed_respond['networkname'] = network_section.attrib['networkName']
2512
2513 ipscopes_section = \
2514 xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes',
2515 namespace_vm)
2516 if ipscopes_section is not None:
2517 for ipscope in ipscopes_section:
2518 for scope in ipscope:
2519 tag_key = scope.tag.split("}")[1]
2520 if tag_key == 'IpRanges':
2521 ip_ranges = scope.getchildren()
2522 for ipblock in ip_ranges:
2523 for block in ipblock:
2524 parsed_respond[block.tag.split("}")[1]] = block.text
2525 else:
2526 parsed_respond[tag_key] = scope.text
2527
2528 # parse children section for other attrib
2529 children_section = xmlroot_respond.find('vm:Children/', namespace_vm)
2530 if children_section is not None:
2531 parsed_respond['name'] = children_section.attrib['name']
2532 parsed_respond['nestedHypervisorEnabled'] = children_section.attrib['nestedHypervisorEnabled']
2533 parsed_respond['deployed'] = children_section.attrib['deployed']
2534 parsed_respond['status'] = children_section.attrib['status']
2535 parsed_respond['vmuuid'] = children_section.attrib['id'].split(":")[-1]
2536 network_adapter = children_section.find('vm:NetworkConnectionSection', namespace_vm)
2537 nic_list = []
2538 for adapters in network_adapter:
2539 adapter_key = adapters.tag.split("}")[1]
2540 if adapter_key == 'PrimaryNetworkConnectionIndex':
2541 parsed_respond['primarynetwork'] = adapters.text
2542 if adapter_key == 'NetworkConnection':
2543 vnic = {}
2544 if 'network' in adapters.attrib:
2545 vnic['network'] = adapters.attrib['network']
2546 for adapter in adapters:
2547 setting_key = adapter.tag.split("}")[1]
2548 vnic[setting_key] = adapter.text
2549 nic_list.append(vnic)
2550
2551 for link in children_section:
2552 if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
2553 if link.attrib['rel'] == 'screen:acquireTicket':
2554 parsed_respond['acquireTicket'] = link.attrib
2555 if link.attrib['rel'] == 'screen:acquireMksTicket':
2556 parsed_respond['acquireMksTicket'] = link.attrib
2557
2558 parsed_respond['interfaces'] = nic_list
2559 except:
2560 pass
2561
2562 return parsed_respond
2563
2564 def acuire_console(self, vm_uuid=None):
2565
2566 vca = self.connect()
2567 if not vca:
2568 raise vimconn.vimconnConnectionException("self.connect() is failed")
2569 if vm_uuid is None:
2570 return None
2571
2572 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2573 vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
2574 console_dict = vm_dict['acquireTicket']
2575 console_rest_call = console_dict['href']
2576
2577 response = Http.post(url=console_rest_call,
2578 headers=vca.vcloud_session.get_vcloud_headers(),
2579 verify=vca.verify,
2580 logger=vca.logger)
2581
2582 if response.status_code == requests.codes.ok:
2583 return response.content
2584
2585 return None
2586