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