blob: 10111c1fb6582f588120bb47b217f91e68370054 [file] [log] [blame]
bayramov325fa1c2016-09-08 01:42:46 -07001# -*- 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
bayramov5761ad12016-10-04 09:00:30 +040024"""
bayramov325fa1c2016-09-08 01:42:46 -070025vimconn_vmware implementation an Abstract class in order to interact with VMware vCloud Director.
26mbayramov@vmware.com
bayramov5761ad12016-10-04 09:00:30 +040027"""
bayramovfe3f3c92016-10-04 07:53:41 +040028from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
bayramovbd6160f2016-09-28 04:12:05 +040029
30import vimconn
bayramov325fa1c2016-09-08 01:42:46 -070031import os
bayramovef390722016-09-27 03:34:46 -070032import traceback
bayramovef390722016-09-27 03:34:46 -070033import itertools
bayramov325fa1c2016-09-08 01:42:46 -070034import requests
bhangarefda5f7c2017-01-12 23:50:34 -080035import ssl
36import atexit
37
38from pyVmomi import vim, vmodl
39from pyVim.connect import SmartConnect, Disconnect
bayramov325fa1c2016-09-08 01:42:46 -070040
bayramovef390722016-09-27 03:34:46 -070041from xml.etree import ElementTree as XmlElementTree
bhangarea92ae392017-01-12 22:30:29 -080042from lxml import etree as lxmlElementTree
bayramov325fa1c2016-09-08 01:42:46 -070043
bayramovef390722016-09-27 03:34:46 -070044import yaml
bayramov325fa1c2016-09-08 01:42:46 -070045from pyvcloud import Http
46from pyvcloud.vcloudair import VCA
47from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
48 vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
49 networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
50from xml.sax.saxutils import escape
51
bayramovef390722016-09-27 03:34:46 -070052from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TaskType
53from pyvcloud.schema.vcd.v1_5.schemas.vcloud.taskType import TaskType as GenericTask
54from pyvcloud.schema.vcd.v1_5.schemas.vcloud.vAppType import TaskType as VappTask
55from pyvcloud.schema.vcd.v1_5.schemas.admin.vCloudEntities import TasksInProgressType
56
bayramov325fa1c2016-09-08 01:42:46 -070057import logging
58import json
bayramov325fa1c2016-09-08 01:42:46 -070059import time
60import uuid
61import httplib
kate15f1c382016-12-15 01:12:40 -080062import hashlib
bhangare0e571a92017-01-12 04:02:23 -080063import socket
64import struct
65import netaddr
kasarde691232017-03-25 03:37:31 -070066import random
bayramov325fa1c2016-09-08 01:42:46 -070067
bayramovbd6160f2016-09-28 04:12:05 +040068# global variable for vcd connector type
69STANDALONE = 'standalone'
70
kate15f1c382016-12-15 01:12:40 -080071# key for flavor dicts
72FLAVOR_RAM_KEY = 'ram'
73FLAVOR_VCPUS_KEY = 'vcpus'
bhangarea92ae392017-01-12 22:30:29 -080074FLAVOR_DISK_KEY = 'disk'
kasarde691232017-03-25 03:37:31 -070075DEFAULT_IP_PROFILE = {'dhcp_count':50,
bhangare0e571a92017-01-12 04:02:23 -080076 'dhcp_enabled':True,
kasarde691232017-03-25 03:37:31 -070077 'ip_version':"IPv4"
bhangare0e571a92017-01-12 04:02:23 -080078 }
79# global variable for wait time
kate13ab2c42016-12-23 01:34:24 -080080INTERVAL_TIME = 5
81MAX_WAIT_TIME = 1800
bayramov325fa1c2016-09-08 01:42:46 -070082
bayramovbd6160f2016-09-28 04:12:05 +040083VCAVERSION = '5.9'
84
bhangare0e571a92017-01-12 04:02:23 -080085__author__ = "Mustafa Bayramov, Arpita Kate, Sachin Bhangare"
bhangarea92ae392017-01-12 22:30:29 -080086__date__ = "$12-Jan-2017 11:09:29$"
bayramovfe3f3c92016-10-04 07:53:41 +040087__version__ = '0.1'
bayramov325fa1c2016-09-08 01:42:46 -070088
bayramovef390722016-09-27 03:34:46 -070089# -1: "Could not be created",
90# 0: "Unresolved",
91# 1: "Resolved",
92# 2: "Deployed",
93# 3: "Suspended",
94# 4: "Powered on",
95# 5: "Waiting for user input",
96# 6: "Unknown state",
97# 7: "Unrecognized state",
98# 8: "Powered off",
99# 9: "Inconsistent state",
100# 10: "Children do not all have the same status",
101# 11: "Upload initiated, OVF descriptor pending",
102# 12: "Upload initiated, copying contents",
103# 13: "Upload initiated , disk contents pending",
104# 14: "Upload has been quarantined",
105# 15: "Upload quarantine period has expired"
106
107# mapping vCD status to MANO
108vcdStatusCode2manoFormat = {4: 'ACTIVE',
109 7: 'PAUSED',
110 3: 'SUSPENDED',
111 8: 'INACTIVE',
112 12: 'BUILD',
113 -1: 'ERROR',
114 14: 'DELETED'}
115
116#
117netStatus2manoFormat = {'ACTIVE': 'ACTIVE', 'PAUSED': 'PAUSED', 'INACTIVE': 'INACTIVE', 'BUILD': 'BUILD',
118 'ERROR': 'ERROR', 'DELETED': 'DELETED'
119 }
120
bayramovbd6160f2016-09-28 04:12:05 +0400121class vimconnector(vimconn.vimconnector):
kateeb044522017-03-06 23:54:39 -0800122 # dict used to store flavor in memory
123 flavorlist = {}
124
bayramovbd6160f2016-09-28 04:12:05 +0400125 def __init__(self, uuid=None, name=None, tenant_id=None, tenant_name=None,
tiernob3d36742017-03-03 23:51:05 +0100126 url=None, url_admin=None, user=None, passwd=None, log_level=None, config={}, persistent_info={}):
bayramovb6ffe792016-09-28 11:50:56 +0400127 """
128 Constructor create vmware connector to vCloud director.
129
130 By default construct doesn't validate connection state. So client can create object with None arguments.
131 If client specified username , password and host and VDC name. Connector initialize other missing attributes.
132
133 a) It initialize organization UUID
134 b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
135
136 Args:
137 uuid - is organization uuid.
138 name - is organization name that must be presented in vCloud director.
139 tenant_id - is VDC uuid it must be presented in vCloud director
140 tenant_name - is VDC name.
141 url - is hostname or ip address of vCloud director
142 url_admin - same as above.
143 user - is user that administrator for organization. Caller must make sure that
144 username has right privileges.
145
146 password - is password for a user.
147
148 VMware connector also requires PVDC administrative privileges and separate account.
149 This variables must be passed via config argument dict contains keys
150
151 dict['admin_username']
152 dict['admin_password']
kateeb044522017-03-06 23:54:39 -0800153 config - Provide NSX and vCenter information
bayramovb6ffe792016-09-28 11:50:56 +0400154
155 Returns:
156 Nothing.
157 """
158
bayramovbd6160f2016-09-28 04:12:05 +0400159 vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url,
160 url_admin, user, passwd, log_level, config)
kate15f1c382016-12-15 01:12:40 -0800161
162 self.logger = logging.getLogger('openmano.vim.vmware')
163 self.logger.setLevel(10)
tiernob3d36742017-03-03 23:51:05 +0100164 self.persistent_info = persistent_info
kate15f1c382016-12-15 01:12:40 -0800165
bayramovef390722016-09-27 03:34:46 -0700166 self.name = name
kate15f1c382016-12-15 01:12:40 -0800167 self.id = uuid
bayramovef390722016-09-27 03:34:46 -0700168 self.url = url
bayramov325fa1c2016-09-08 01:42:46 -0700169 self.url_admin = url_admin
170 self.tenant_id = tenant_id
171 self.tenant_name = tenant_name
bayramovef390722016-09-27 03:34:46 -0700172 self.user = user
173 self.passwd = passwd
174 self.config = config
175 self.admin_password = None
176 self.admin_user = None
kate15f1c382016-12-15 01:12:40 -0800177 self.org_name = ""
bhangare985a1fd2017-01-31 01:53:21 -0800178 self.nsx_manager = None
179 self.nsx_user = None
180 self.nsx_password = None
kateeb044522017-03-06 23:54:39 -0800181 self.vcenter_ip = None
182 self.vcenter_port = None
183 self.vcenter_user = None
184 self.vcenter_password = None
bayramovef390722016-09-27 03:34:46 -0700185
kate15f1c382016-12-15 01:12:40 -0800186 if tenant_name is not None:
187 orgnameandtenant = tenant_name.split(":")
188 if len(orgnameandtenant) == 2:
katec324e002016-12-23 00:54:47 -0800189 self.tenant_name = orgnameandtenant[1]
190 self.org_name = orgnameandtenant[0]
kate15f1c382016-12-15 01:12:40 -0800191 else:
192 self.tenant_name = tenant_name
bhangarea92ae392017-01-12 22:30:29 -0800193 if "orgname" in config:
kate15f1c382016-12-15 01:12:40 -0800194 self.org_name = config['orgname']
katec324e002016-12-23 00:54:47 -0800195
tiernofe789902016-09-29 14:20:44 +0000196 if log_level:
bayramov5761ad12016-10-04 09:00:30 +0400197 self.logger.setLevel(getattr(logging, log_level))
bayramov325fa1c2016-09-08 01:42:46 -0700198
bayramovef390722016-09-27 03:34:46 -0700199 try:
200 self.admin_user = config['admin_username']
201 self.admin_password = config['admin_password']
202 except KeyError:
bayramovbd6160f2016-09-28 04:12:05 +0400203 raise vimconn.vimconnException(message="Error admin username or admin password is empty.")
bayramov325fa1c2016-09-08 01:42:46 -0700204
bhangare985a1fd2017-01-31 01:53:21 -0800205 try:
206 self.nsx_manager = config['nsx_manager']
207 self.nsx_user = config['nsx_user']
208 self.nsx_password = config['nsx_password']
209 except KeyError:
210 raise vimconn.vimconnException(message="Error: nsx manager or nsx user or nsx password is empty in Config")
211
kateeb044522017-03-06 23:54:39 -0800212 self.vcenter_ip = config.get("vcenter_ip", None)
213 self.vcenter_port = config.get("vcenter_port", None)
214 self.vcenter_user = config.get("vcenter_user", None)
215 self.vcenter_password = config.get("vcenter_password", None)
216
bayramovef390722016-09-27 03:34:46 -0700217 self.org_uuid = None
218 self.vca = None
bayramov325fa1c2016-09-08 01:42:46 -0700219
220 if not url:
bayramov5761ad12016-10-04 09:00:30 +0400221 raise vimconn.vimconnException('url param can not be NoneType')
bayramov325fa1c2016-09-08 01:42:46 -0700222
bayramovef390722016-09-27 03:34:46 -0700223 if not self.url_admin: # try to use normal url
bayramov325fa1c2016-09-08 01:42:46 -0700224 self.url_admin = self.url
225
kate15f1c382016-12-15 01:12:40 -0800226 logging.debug("UUID: {} name: {} tenant_id: {} tenant name {}".format(self.id, self.org_name,
bayramovef390722016-09-27 03:34:46 -0700227 self.tenant_id, self.tenant_name))
228 logging.debug("vcd url {} vcd username: {} vcd password: {}".format(self.url, self.user, self.passwd))
229 logging.debug("vcd admin username {} vcd admin passowrd {}".format(self.admin_user, self.admin_password))
bayramov325fa1c2016-09-08 01:42:46 -0700230
bayramovef390722016-09-27 03:34:46 -0700231 # initialize organization
bayramovbd6160f2016-09-28 04:12:05 +0400232 if self.user is not None and self.passwd is not None and self.url:
233 self.init_organization()
bayramovef390722016-09-27 03:34:46 -0700234
235 def __getitem__(self, index):
kate15f1c382016-12-15 01:12:40 -0800236 if index == 'name':
237 return self.name
bayramovef390722016-09-27 03:34:46 -0700238 if index == 'tenant_id':
bayramov325fa1c2016-09-08 01:42:46 -0700239 return self.tenant_id
bayramovef390722016-09-27 03:34:46 -0700240 if index == 'tenant_name':
bayramov325fa1c2016-09-08 01:42:46 -0700241 return self.tenant_name
bayramovef390722016-09-27 03:34:46 -0700242 elif index == 'id':
bayramov325fa1c2016-09-08 01:42:46 -0700243 return self.id
bayramovef390722016-09-27 03:34:46 -0700244 elif index == 'org_name':
245 return self.org_name
246 elif index == 'org_uuid':
247 return self.org_uuid
248 elif index == 'user':
bayramov325fa1c2016-09-08 01:42:46 -0700249 return self.user
bayramovef390722016-09-27 03:34:46 -0700250 elif index == 'passwd':
bayramov325fa1c2016-09-08 01:42:46 -0700251 return self.passwd
bayramovef390722016-09-27 03:34:46 -0700252 elif index == 'url':
bayramov325fa1c2016-09-08 01:42:46 -0700253 return self.url
bayramovef390722016-09-27 03:34:46 -0700254 elif index == 'url_admin':
bayramov325fa1c2016-09-08 01:42:46 -0700255 return self.url_admin
bayramovef390722016-09-27 03:34:46 -0700256 elif index == "config":
bayramov325fa1c2016-09-08 01:42:46 -0700257 return self.config
258 else:
bayramovef390722016-09-27 03:34:46 -0700259 raise KeyError("Invalid key '%s'" % str(index))
bayramov325fa1c2016-09-08 01:42:46 -0700260
bayramovef390722016-09-27 03:34:46 -0700261 def __setitem__(self, index, value):
kate15f1c382016-12-15 01:12:40 -0800262 if index == 'name':
263 self.name = value
bayramovef390722016-09-27 03:34:46 -0700264 if index == 'tenant_id':
bayramov325fa1c2016-09-08 01:42:46 -0700265 self.tenant_id = value
bayramovef390722016-09-27 03:34:46 -0700266 if index == 'tenant_name':
bayramov325fa1c2016-09-08 01:42:46 -0700267 self.tenant_name = value
bayramovef390722016-09-27 03:34:46 -0700268 elif index == 'id':
bayramov325fa1c2016-09-08 01:42:46 -0700269 self.id = value
bayramovef390722016-09-27 03:34:46 -0700270 elif index == 'org_name':
271 self.org_name = value
bayramovef390722016-09-27 03:34:46 -0700272 elif index == 'org_uuid':
kate15f1c382016-12-15 01:12:40 -0800273 self.org_uuid = value
bayramovef390722016-09-27 03:34:46 -0700274 elif index == 'user':
bayramov325fa1c2016-09-08 01:42:46 -0700275 self.user = value
bayramovef390722016-09-27 03:34:46 -0700276 elif index == 'passwd':
bayramov325fa1c2016-09-08 01:42:46 -0700277 self.passwd = value
bayramovef390722016-09-27 03:34:46 -0700278 elif index == 'url':
bayramov325fa1c2016-09-08 01:42:46 -0700279 self.url = value
bayramovef390722016-09-27 03:34:46 -0700280 elif index == 'url_admin':
bayramov325fa1c2016-09-08 01:42:46 -0700281 self.url_admin = value
282 else:
bayramovef390722016-09-27 03:34:46 -0700283 raise KeyError("Invalid key '%s'" % str(index))
bayramov325fa1c2016-09-08 01:42:46 -0700284
bayramovef390722016-09-27 03:34:46 -0700285 def connect_as_admin(self):
bayramovb6ffe792016-09-28 11:50:56 +0400286 """ Method connect as pvdc admin user to vCloud director.
287 There are certain action that can be done only by provider vdc admin user.
288 Organization creation / provider network creation etc.
bayramovef390722016-09-27 03:34:46 -0700289
290 Returns:
291 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
292 """
293
kate15f1c382016-12-15 01:12:40 -0800294 self.logger.debug("Logging in to a vca {} as admin.".format(self.org_name))
bayramov325fa1c2016-09-08 01:42:46 -0700295
bayramovef390722016-09-27 03:34:46 -0700296 vca_admin = VCA(host=self.url,
297 username=self.admin_user,
bayramovbd6160f2016-09-28 04:12:05 +0400298 service_type=STANDALONE,
299 version=VCAVERSION,
bayramovef390722016-09-27 03:34:46 -0700300 verify=False,
301 log=False)
302 result = vca_admin.login(password=self.admin_password, org='System')
303 if not result:
bayramovbd6160f2016-09-28 04:12:05 +0400304 raise vimconn.vimconnConnectionException(
305 "Can't connect to a vCloud director as: {}".format(self.admin_user))
bayramovef390722016-09-27 03:34:46 -0700306 result = vca_admin.login(token=vca_admin.token, org='System', org_url=vca_admin.vcloud_session.org_url)
307 if result is True:
308 self.logger.info(
309 "Successfully logged to a vcloud direct org: {} as user: {}".format('System', self.admin_user))
bayramov325fa1c2016-09-08 01:42:46 -0700310
bayramovef390722016-09-27 03:34:46 -0700311 return vca_admin
bayramov325fa1c2016-09-08 01:42:46 -0700312
bayramovef390722016-09-27 03:34:46 -0700313 def connect(self):
314 """ Method connect as normal user to vCloud director.
315
316 Returns:
317 The return vca object that letter can be used to connect to vCloud director as admin for VDC
318 """
319
bayramovb6ffe792016-09-28 11:50:56 +0400320 try:
kate15f1c382016-12-15 01:12:40 -0800321 self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org_name,
322 self.user,
323 self.org_name))
bayramovb6ffe792016-09-28 11:50:56 +0400324 vca = VCA(host=self.url,
325 username=self.user,
326 service_type=STANDALONE,
327 version=VCAVERSION,
328 verify=False,
329 log=False)
bayramovef390722016-09-27 03:34:46 -0700330
kate15f1c382016-12-15 01:12:40 -0800331 result = vca.login(password=self.passwd, org=self.org_name)
bayramovb6ffe792016-09-28 11:50:56 +0400332 if not result:
333 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self.user))
kate15f1c382016-12-15 01:12:40 -0800334 result = vca.login(token=vca.token, org=self.org_name, org_url=vca.vcloud_session.org_url)
bayramovb6ffe792016-09-28 11:50:56 +0400335 if result is True:
bayramovfe3f3c92016-10-04 07:53:41 +0400336 self.logger.info(
kate15f1c382016-12-15 01:12:40 -0800337 "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org_name, self.user))
bayramovb6ffe792016-09-28 11:50:56 +0400338
339 except:
kate15f1c382016-12-15 01:12:40 -0800340 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
341 "{} as user: {}".format(self.org_name, self.user))
bayramov325fa1c2016-09-08 01:42:46 -0700342
343 return vca
344
bayramovbd6160f2016-09-28 04:12:05 +0400345 def init_organization(self):
346 """ Method initialize organization UUID and VDC parameters.
347
348 At bare minimum client must provide organization name that present in vCloud director and VDC.
349
350 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
351 The Org - UUID will be initialized at the run time if data center present in vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -0700352
bayramovef390722016-09-27 03:34:46 -0700353 Returns:
354 The return vca object that letter can be used to connect to vcloud direct as admin
355 """
356 try:
357 if self.org_uuid is None:
358 org_dict = self.get_org_list()
359 for org in org_dict:
bayramovbd6160f2016-09-28 04:12:05 +0400360 # we set org UUID at the init phase but we can do it only when we have valid credential.
bayramovef390722016-09-27 03:34:46 -0700361 if org_dict[org] == self.org_name:
362 self.org_uuid = org
bayramovbd6160f2016-09-28 04:12:05 +0400363 self.logger.debug("Setting organization UUID {}".format(self.org_uuid))
364 break
bayramovbd6160f2016-09-28 04:12:05 +0400365 else:
366 raise vimconn.vimconnException("Vcloud director organization {} not found".format(self.org_name))
367
368 # if well good we require for org details
369 org_details_dict = self.get_org(org_uuid=self.org_uuid)
370
371 # we have two case if we want to initialize VDC ID or VDC name at run time
372 # tenant_name provided but no tenant id
bayramov5761ad12016-10-04 09:00:30 +0400373 if self.tenant_id is None and self.tenant_name is not None and 'vdcs' in org_details_dict:
bayramovbd6160f2016-09-28 04:12:05 +0400374 vdcs_dict = org_details_dict['vdcs']
bayramovbd6160f2016-09-28 04:12:05 +0400375 for vdc in vdcs_dict:
376 if vdcs_dict[vdc] == self.tenant_name:
377 self.tenant_id = vdc
378 self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
kate15f1c382016-12-15 01:12:40 -0800379 self.org_name))
bayramovbd6160f2016-09-28 04:12:05 +0400380 break
381 else:
382 raise vimconn.vimconnException("Tenant name indicated but not present in vcloud director.")
383 # case two we have tenant_id but we don't have tenant name so we find and set it.
bayramov5761ad12016-10-04 09:00:30 +0400384 if self.tenant_id is not None and self.tenant_name is None and 'vdcs' in org_details_dict:
bayramovbd6160f2016-09-28 04:12:05 +0400385 vdcs_dict = org_details_dict['vdcs']
386 for vdc in vdcs_dict:
387 if vdc == self.tenant_id:
388 self.tenant_name = vdcs_dict[vdc]
389 self.logger.debug("Setting vdc uuid {} for organization UUID {}".format(self.tenant_id,
kate15f1c382016-12-15 01:12:40 -0800390 self.org_name))
bayramovbd6160f2016-09-28 04:12:05 +0400391 break
392 else:
393 raise vimconn.vimconnException("Tenant id indicated but not present in vcloud director")
bayramovef390722016-09-27 03:34:46 -0700394 self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
395 except:
396 self.logger.debug("Failed initialize organization UUID for org {}".format(self.org_name))
397 self.logger.debug(traceback.format_exc())
398 self.org_uuid = None
bayramov325fa1c2016-09-08 01:42:46 -0700399
bayramovef390722016-09-27 03:34:46 -0700400 def new_tenant(self, tenant_name=None, tenant_description=None):
bayramovb6ffe792016-09-28 11:50:56 +0400401 """ Method adds a new tenant to VIM with this name.
402 This action requires access to create VDC action in vCloud director.
bayramovef390722016-09-27 03:34:46 -0700403
bayramovb6ffe792016-09-28 11:50:56 +0400404 Args:
405 tenant_name is tenant_name to be created.
406 tenant_description not used for this call
407
408 Return:
409 returns the tenant identifier in UUID format.
410 If action is failed method will throw vimconn.vimconnException method
bayramovbd6160f2016-09-28 04:12:05 +0400411 """
bayramovef390722016-09-27 03:34:46 -0700412 vdc_task = self.create_vdc(vdc_name=tenant_name)
413 if vdc_task is not None:
414 vdc_uuid, value = vdc_task.popitem()
415 self.logger.info("Crated new vdc {} and uuid: {}".format(tenant_name, vdc_uuid))
416 return vdc_uuid
417 else:
bayramovbd6160f2016-09-28 04:12:05 +0400418 raise vimconn.vimconnException("Failed create tenant {}".format(tenant_name))
bayramovef390722016-09-27 03:34:46 -0700419
bayramov163f1ae2016-09-28 17:16:55 +0400420 def delete_tenant(self, tenant_id=None):
bayramovef390722016-09-27 03:34:46 -0700421 """Delete a tenant from VIM"""
422 'Returns the tenant identifier'
bayramovbd6160f2016-09-28 04:12:05 +0400423 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -0700424
425 def get_tenant_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400426 """Obtain tenants of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700427 filter_dict can contain the following keys:
428 name: filter by tenant name
429 id: filter by tenant uuid/id
430 <other VIM specific>
bayramovb6ffe792016-09-28 11:50:56 +0400431 Returns the tenant list of dictionaries:
bayramov325fa1c2016-09-08 01:42:46 -0700432 [{'name':'<name>, 'id':'<id>, ...}, ...]
bayramov325fa1c2016-09-08 01:42:46 -0700433
bayramovb6ffe792016-09-28 11:50:56 +0400434 """
bayramovef390722016-09-27 03:34:46 -0700435 org_dict = self.get_org(self.org_uuid)
436 vdcs_dict = org_dict['vdcs']
437
438 vdclist = []
439 try:
440 for k in vdcs_dict:
441 entry = {'name': vdcs_dict[k], 'id': k}
bayramovb6ffe792016-09-28 11:50:56 +0400442 # if caller didn't specify dictionary we return all tenants.
443 if filter_dict is not None and filter_dict:
444 filtered_entry = entry.copy()
445 filtered_dict = set(entry.keys()) - set(filter_dict)
446 for unwanted_key in filtered_dict: del entry[unwanted_key]
447 if filter_dict == entry:
448 vdclist.append(filtered_entry)
449 else:
450 vdclist.append(entry)
bayramovef390722016-09-27 03:34:46 -0700451 except:
452 self.logger.debug("Error in get_tenant_list()")
453 self.logger.debug(traceback.format_exc())
bayramovb6ffe792016-09-28 11:50:56 +0400454 raise vimconn.vimconnException("Incorrect state. {}")
bayramovef390722016-09-27 03:34:46 -0700455
456 return vdclist
457
458 def new_network(self, net_name, net_type, ip_profile=None, shared=False):
bayramovb6ffe792016-09-28 11:50:56 +0400459 """Adds a tenant network to VIM
bayramov325fa1c2016-09-08 01:42:46 -0700460 net_name is the name
bhangare0e571a92017-01-12 04:02:23 -0800461 net_type can be 'bridge','data'.'ptp'.
bayramovb6ffe792016-09-28 11:50:56 +0400462 ip_profile is a dict containing the IP parameters of the network
bayramov325fa1c2016-09-08 01:42:46 -0700463 shared is a boolean
bayramovb6ffe792016-09-28 11:50:56 +0400464 Returns the network identifier"""
bayramov325fa1c2016-09-08 01:42:46 -0700465
bhangare0e571a92017-01-12 04:02:23 -0800466 self.logger.debug("new_network tenant {} net_type {} ip_profile {} shared {}"
467 .format(net_name, net_type, ip_profile, shared))
bayramov325fa1c2016-09-08 01:42:46 -0700468
bayramovef390722016-09-27 03:34:46 -0700469 isshared = 'false'
470 if shared:
471 isshared = 'true'
472
bhangare0e571a92017-01-12 04:02:23 -0800473 network_uuid = self.create_network(network_name=net_name, net_type=net_type,
474 ip_profile=ip_profile, isshared=isshared)
bayramovef390722016-09-27 03:34:46 -0700475 if network_uuid is not None:
476 return network_uuid
477 else:
bayramovbd6160f2016-09-28 04:12:05 +0400478 raise vimconn.vimconnUnexpectedResponse("Failed create a new network {}".format(net_name))
bayramovef390722016-09-27 03:34:46 -0700479
480 def get_vcd_network_list(self):
481 """ Method available organization for a logged in tenant
482
483 Returns:
484 The return vca object that letter can be used to connect to vcloud direct as admin
485 """
486
kate15f1c382016-12-15 01:12:40 -0800487 self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
bayramovef390722016-09-27 03:34:46 -0700488 vca = self.connect()
489 if not vca:
490 raise vimconn.vimconnConnectionException("self.connect() is failed.")
491
kate15f1c382016-12-15 01:12:40 -0800492 if not self.tenant_name:
493 raise vimconn.vimconnConnectionException("Tenant name is empty.")
494
bayramovef390722016-09-27 03:34:46 -0700495 vdc = vca.get_vdc(self.tenant_name)
kate15f1c382016-12-15 01:12:40 -0800496 if vdc is None:
497 raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}".format(self.tenant_name))
498
bayramovef390722016-09-27 03:34:46 -0700499 vdc_uuid = vdc.get_id().split(":")[3]
500 networks = vca.get_networks(vdc.get_name())
501 network_list = []
502 try:
503 for network in networks:
504 filter_dict = {}
505 netid = network.get_id().split(":")
506 if len(netid) != 4:
507 continue
508
509 filter_dict["name"] = network.get_name()
510 filter_dict["id"] = netid[3]
511 filter_dict["shared"] = network.get_IsShared()
512 filter_dict["tenant_id"] = vdc_uuid
513 if network.get_status() == 1:
514 filter_dict["admin_state_up"] = True
515 else:
516 filter_dict["admin_state_up"] = False
517 filter_dict["status"] = "ACTIVE"
518 filter_dict["type"] = "bridge"
519 network_list.append(filter_dict)
520 self.logger.debug("get_vcd_network_list adding entry {}".format(filter_dict))
521 except:
522 self.logger.debug("Error in get_vcd_network_list")
523 self.logger.debug(traceback.format_exc())
524 pass
525
526 self.logger.debug("get_vcd_network_list returning {}".format(network_list))
527 return network_list
bayramov325fa1c2016-09-08 01:42:46 -0700528
529 def get_network_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400530 """Obtain tenant networks of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700531 Filter_dict can be:
bayramovef390722016-09-27 03:34:46 -0700532 name: network name OR/AND
533 id: network uuid OR/AND
534 shared: boolean OR/AND
535 tenant_id: tenant OR/AND
bayramov325fa1c2016-09-08 01:42:46 -0700536 admin_state_up: boolean
537 status: 'ACTIVE'
bayramovef390722016-09-27 03:34:46 -0700538
539 [{key : value , key : value}]
540
bayramov325fa1c2016-09-08 01:42:46 -0700541 Returns the network list of dictionaries:
542 [{<the fields at Filter_dict plus some VIM specific>}, ...]
543 List can be empty
bayramovb6ffe792016-09-28 11:50:56 +0400544 """
bayramov325fa1c2016-09-08 01:42:46 -0700545
kate15f1c382016-12-15 01:12:40 -0800546 self.logger.debug("get_vcd_network_list(): retrieving network list for vcd {}".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -0700547 vca = self.connect()
548 if not vca:
kate15f1c382016-12-15 01:12:40 -0800549 raise vimconn.vimconnConnectionException("self.connect() is failed.")
550
551 if not self.tenant_name:
552 raise vimconn.vimconnConnectionException("Tenant name is empty.")
bayramov325fa1c2016-09-08 01:42:46 -0700553
554 vdc = vca.get_vdc(self.tenant_name)
kate15f1c382016-12-15 01:12:40 -0800555 if vdc is None:
556 raise vimconn.vimconnConnectionException("Can't retrieve information for a VDC {}.".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -0700557
bayramovef390722016-09-27 03:34:46 -0700558 try:
bhangarebfdca492017-03-11 01:32:46 -0800559 vdcid = vdc.get_id().split(":")[3]
560 networks = vca.get_networks(vdc.get_name())
561 network_list = []
562
bayramovef390722016-09-27 03:34:46 -0700563 for network in networks:
564 filter_entry = {}
565 net_uuid = network.get_id().split(":")
566 if len(net_uuid) != 4:
567 continue
568 else:
569 net_uuid = net_uuid[3]
570 # create dict entry
571 self.logger.debug("Adding {} to a list vcd id {} network {}".format(net_uuid,
572 vdcid,
573 network.get_name()))
574 filter_entry["name"] = network.get_name()
575 filter_entry["id"] = net_uuid
576 filter_entry["shared"] = network.get_IsShared()
577 filter_entry["tenant_id"] = vdcid
578 if network.get_status() == 1:
579 filter_entry["admin_state_up"] = True
580 else:
581 filter_entry["admin_state_up"] = False
582 filter_entry["status"] = "ACTIVE"
583 filter_entry["type"] = "bridge"
584 filtered_entry = filter_entry.copy()
585
bayramovb6ffe792016-09-28 11:50:56 +0400586 if filter_dict is not None and filter_dict:
587 # we remove all the key : value we don't care and match only
588 # respected field
589 filtered_dict = set(filter_entry.keys()) - set(filter_dict)
590 for unwanted_key in filtered_dict: del filter_entry[unwanted_key]
591 if filter_dict == filter_entry:
592 network_list.append(filtered_entry)
593 else:
bayramovef390722016-09-27 03:34:46 -0700594 network_list.append(filtered_entry)
595 except:
596 self.logger.debug("Error in get_vcd_network_list")
597 self.logger.debug(traceback.format_exc())
bayramov325fa1c2016-09-08 01:42:46 -0700598
599 self.logger.debug("Returning {}".format(network_list))
600 return network_list
601
602 def get_network(self, net_id):
bayramovfe3f3c92016-10-04 07:53:41 +0400603 """Method obtains network details of net_id VIM network
bayramovef390722016-09-27 03:34:46 -0700604 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
605
606 vca = self.connect()
607 if not vca:
608 raise vimconn.vimconnConnectionException("self.connect() is failed")
609
bayramovef390722016-09-27 03:34:46 -0700610 try:
bhangarebfdca492017-03-11 01:32:46 -0800611 vdc = vca.get_vdc(self.tenant_name)
612 vdc_id = vdc.get_id().split(":")[3]
613
614 networks = vca.get_networks(vdc.get_name())
615 filter_dict = {}
616
bayramovef390722016-09-27 03:34:46 -0700617 for network in networks:
618 vdc_network_id = network.get_id().split(":")
619 if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
620 filter_dict["name"] = network.get_name()
621 filter_dict["id"] = vdc_network_id[3]
622 filter_dict["shared"] = network.get_IsShared()
623 filter_dict["tenant_id"] = vdc_id
624 if network.get_status() == 1:
625 filter_dict["admin_state_up"] = True
626 else:
627 filter_dict["admin_state_up"] = False
628 filter_dict["status"] = "ACTIVE"
629 filter_dict["type"] = "bridge"
630 self.logger.debug("Returning {}".format(filter_dict))
631 return filter_dict
632 except:
633 self.logger.debug("Error in get_network")
634 self.logger.debug(traceback.format_exc())
635
636 return filter_dict
bayramov325fa1c2016-09-08 01:42:46 -0700637
638 def delete_network(self, net_id):
bayramovef390722016-09-27 03:34:46 -0700639 """
640 Method Deletes a tenant network from VIM, provide the network id.
641
642 Returns the network identifier or raise an exception
643 """
644
645 vca = self.connect()
646 if not vca:
bayramovfe3f3c92016-10-04 07:53:41 +0400647 raise vimconn.vimconnConnectionException("self.connect() for tenant {} is failed.".format(self.tenant_name))
bayramovef390722016-09-27 03:34:46 -0700648
bayramovfe3f3c92016-10-04 07:53:41 +0400649 vcd_network = self.get_vcd_network(network_uuid=net_id)
650 if vcd_network is not None and vcd_network:
651 if self.delete_network_action(network_uuid=net_id):
652 return net_id
bayramovef390722016-09-27 03:34:46 -0700653 else:
654 raise vimconn.vimconnNotFoundException("Network {} not found".format(net_id))
bayramov325fa1c2016-09-08 01:42:46 -0700655
656 def refresh_nets_status(self, net_list):
bayramovbd6160f2016-09-28 04:12:05 +0400657 """Get the status of the networks
bayramov325fa1c2016-09-08 01:42:46 -0700658 Params: the list of network identifiers
659 Returns a dictionary with:
660 net_id: #VIM id of this network
661 status: #Mandatory. Text with one of:
662 # DELETED (not found at vim)
bayramovbd6160f2016-09-28 04:12:05 +0400663 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
bayramov325fa1c2016-09-08 01:42:46 -0700664 # OTHER (Vim reported other status not understood)
665 # ERROR (VIM indicates an ERROR status)
bayramovbd6160f2016-09-28 04:12:05 +0400666 # ACTIVE, INACTIVE, DOWN (admin down),
bayramov325fa1c2016-09-08 01:42:46 -0700667 # BUILD (on building process)
668 #
bayramovbd6160f2016-09-28 04:12:05 +0400669 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
bayramov325fa1c2016-09-08 01:42:46 -0700670 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
671
bayramovbd6160f2016-09-28 04:12:05 +0400672 """
bayramov325fa1c2016-09-08 01:42:46 -0700673
bayramov325fa1c2016-09-08 01:42:46 -0700674 vca = self.connect()
675 if not vca:
bayramovef390722016-09-27 03:34:46 -0700676 raise vimconn.vimconnConnectionException("self.connect() is failed")
677
678 dict_entry = {}
679 try:
680 for net in net_list:
bayramovef390722016-09-27 03:34:46 -0700681 errormsg = ''
682 vcd_network = self.get_vcd_network(network_uuid=net)
bayramovfe3f3c92016-10-04 07:53:41 +0400683 if vcd_network is not None and vcd_network:
bhangare92d4af32016-12-24 02:54:51 -0800684 if vcd_network['status'] == '1':
bayramovef390722016-09-27 03:34:46 -0700685 status = 'ACTIVE'
686 else:
687 status = 'DOWN'
688 else:
689 status = 'DELETED'
bayramovfe3f3c92016-10-04 07:53:41 +0400690 errormsg = 'Network not found.'
691
692 dict_entry[net] = {'status': status, 'error_msg': errormsg,
bhangare92d4af32016-12-24 02:54:51 -0800693 'vim_info': yaml.safe_dump(vcd_network)}
bayramovef390722016-09-27 03:34:46 -0700694 except:
695 self.logger.debug("Error in refresh_nets_status")
696 self.logger.debug(traceback.format_exc())
697
698 return dict_entry
699
bayramovbd6160f2016-09-28 04:12:05 +0400700 def get_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -0700701 """Obtain flavor details from the VIM
702 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
703 """
kateeb044522017-03-06 23:54:39 -0800704 if flavor_id not in vimconnector.flavorlist:
bayramovfe3f3c92016-10-04 07:53:41 +0400705 raise vimconn.vimconnNotFoundException("Flavor not found.")
kateeb044522017-03-06 23:54:39 -0800706 return vimconnector.flavorlist[flavor_id]
bayramov325fa1c2016-09-08 01:42:46 -0700707
708 def new_flavor(self, flavor_data):
bayramovef390722016-09-27 03:34:46 -0700709 """Adds a tenant flavor to VIM
bayramov325fa1c2016-09-08 01:42:46 -0700710 flavor_data contains a dictionary with information, keys:
711 name: flavor name
712 ram: memory (cloud type) in MBytes
713 vpcus: cpus (cloud type)
714 extended: EPA parameters
715 - numas: #items requested in same NUMA
716 memory: number of 1G huge pages memory
717 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual threads
718 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
719 - name: interface name
720 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
721 bandwidth: X Gbps; requested guarantee bandwidth
bayramovef390722016-09-27 03:34:46 -0700722 vpci: requested virtual PCI address
bayramov325fa1c2016-09-08 01:42:46 -0700723 disk: disk size
724 is_public:
bayramov325fa1c2016-09-08 01:42:46 -0700725 #TODO to concrete
bayramovef390722016-09-27 03:34:46 -0700726 Returns the flavor identifier"""
bayramov325fa1c2016-09-08 01:42:46 -0700727
bayramovef390722016-09-27 03:34:46 -0700728 # generate a new uuid put to internal dict and return it.
bhangarea92ae392017-01-12 22:30:29 -0800729 self.logger.debug("Creating new flavor - flavor_data: {}".format(flavor_data))
730 new_flavor=flavor_data
731 ram = flavor_data.get(FLAVOR_RAM_KEY, 1024)
732 cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
733 disk = flavor_data.get(FLAVOR_DISK_KEY, 1)
734
735 extended_flv = flavor_data.get("extended")
736 if extended_flv:
737 numas=extended_flv.get("numas")
738 if numas:
739 for numa in numas:
740 #overwrite ram and vcpus
741 ram = numa['memory']*1024
742 if 'paired-threads' in numa:
743 cpu = numa['paired-threads']*2
744 elif 'cores' in numa:
745 cpu = numa['cores']
746 elif 'threads' in numa:
747 cpu = numa['threads']
748
749 new_flavor[FLAVOR_RAM_KEY] = ram
750 new_flavor[FLAVOR_VCPUS_KEY] = cpu
751 new_flavor[FLAVOR_DISK_KEY] = disk
752 # generate a new uuid put to internal dict and return it.
bayramovef390722016-09-27 03:34:46 -0700753 flavor_id = uuid.uuid4()
kateeb044522017-03-06 23:54:39 -0800754 vimconnector.flavorlist[str(flavor_id)] = new_flavor
bhangarea92ae392017-01-12 22:30:29 -0800755 self.logger.debug("Created flavor - {} : {}".format(flavor_id, new_flavor))
bayramov325fa1c2016-09-08 01:42:46 -0700756
bayramovef390722016-09-27 03:34:46 -0700757 return str(flavor_id)
bayramov325fa1c2016-09-08 01:42:46 -0700758
759 def delete_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -0700760 """Deletes a tenant flavor from VIM identify by its id
bayramov325fa1c2016-09-08 01:42:46 -0700761
bayramovfe3f3c92016-10-04 07:53:41 +0400762 Returns the used id or raise an exception
bayramovef390722016-09-27 03:34:46 -0700763 """
kateeb044522017-03-06 23:54:39 -0800764 if flavor_id not in vimconnector.flavorlist:
bayramovfe3f3c92016-10-04 07:53:41 +0400765 raise vimconn.vimconnNotFoundException("Flavor not found.")
bayramovef390722016-09-27 03:34:46 -0700766
kateeb044522017-03-06 23:54:39 -0800767 vimconnector.flavorlist.pop(flavor_id, None)
bayramovef390722016-09-27 03:34:46 -0700768 return flavor_id
769
770 def new_image(self, image_dict):
bayramov5761ad12016-10-04 09:00:30 +0400771 """
bayramov325fa1c2016-09-08 01:42:46 -0700772 Adds a tenant image to VIM
773 Returns:
774 200, image-id if the image is created
775 <0, message if there is an error
bayramov5761ad12016-10-04 09:00:30 +0400776 """
bayramov325fa1c2016-09-08 01:42:46 -0700777
bayramovef390722016-09-27 03:34:46 -0700778 return self.get_image_id_from_path(image_dict['location'])
bayramov325fa1c2016-09-08 01:42:46 -0700779
780 def delete_image(self, image_id):
bayramovfe3f3c92016-10-04 07:53:41 +0400781 """
782
783 :param image_id:
784 :return:
785 """
bayramovfe3f3c92016-10-04 07:53:41 +0400786
bayramovbd6160f2016-09-28 04:12:05 +0400787 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -0700788
789 def catalog_exists(self, catalog_name, catalogs):
bayramovfe3f3c92016-10-04 07:53:41 +0400790 """
791
792 :param catalog_name:
793 :param catalogs:
794 :return:
795 """
bayramov325fa1c2016-09-08 01:42:46 -0700796 for catalog in catalogs:
797 if catalog.name == catalog_name:
798 return True
799 return False
800
bayramovb6ffe792016-09-28 11:50:56 +0400801 def create_vimcatalog(self, vca=None, catalog_name=None):
bayramovfe3f3c92016-10-04 07:53:41 +0400802 """ Create new catalog entry in vCloud director.
bayramovb6ffe792016-09-28 11:50:56 +0400803
804 Args
805 vca: vCloud director.
806 catalog_name catalog that client wish to create. Note no validation done for a name.
807 Client must make sure that provide valid string representation.
808
809 Return (bool) True if catalog created.
810
811 """
812 try:
813 task = vca.create_catalog(catalog_name, catalog_name)
814 result = vca.block_until_completed(task)
815 if not result:
816 return False
817 catalogs = vca.get_catalogs()
818 except:
bayramov325fa1c2016-09-08 01:42:46 -0700819 return False
bayramov325fa1c2016-09-08 01:42:46 -0700820 return self.catalog_exists(catalog_name, catalogs)
821
bayramov5761ad12016-10-04 09:00:30 +0400822 # noinspection PyIncorrectDocstring
bayramovfe3f3c92016-10-04 07:53:41 +0400823 def upload_ovf(self, vca=None, catalog_name=None, image_name=None, media_file_name=None,
824 description='', progress=False, chunk_bytes=128 * 1024):
bayramov325fa1c2016-09-08 01:42:46 -0700825 """
826 Uploads a OVF file to a vCloud catalog
827
bayramov5761ad12016-10-04 09:00:30 +0400828 :param chunk_bytes:
829 :param progress:
830 :param description:
831 :param image_name:
832 :param vca:
bayramov325fa1c2016-09-08 01:42:46 -0700833 :param catalog_name: (str): The name of the catalog to upload the media.
bayramov325fa1c2016-09-08 01:42:46 -0700834 :param media_file_name: (str): The name of the local media file to upload.
835 :return: (bool) True if the media file was successfully uploaded, false otherwise.
836 """
837 os.path.isfile(media_file_name)
838 statinfo = os.stat(media_file_name)
bayramov325fa1c2016-09-08 01:42:46 -0700839
840 # find a catalog entry where we upload OVF.
841 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
842 # status change.
843 # if VCD can parse OVF we upload VMDK file
bhangarebfdca492017-03-11 01:32:46 -0800844 try:
845 for catalog in vca.get_catalogs():
846 if catalog_name != catalog.name:
847 continue
848 link = filter(lambda link: link.get_type() == "application/vnd.vmware.vcloud.media+xml" and
849 link.get_rel() == 'add', catalog.get_Link())
850 assert len(link) == 1
851 data = """
852 <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>
853 """ % (escape(catalog_name), escape(description))
854 headers = vca.vcloud_session.get_vcloud_headers()
855 headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
856 response = Http.post(link[0].get_href(), headers=headers, data=data, verify=vca.verify, logger=self.logger)
857 if response.status_code == requests.codes.created:
858 catalogItem = XmlElementTree.fromstring(response.content)
859 entity = [child for child in catalogItem if
860 child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
861 href = entity.get('href')
862 template = href
863 response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
bayramovef390722016-09-27 03:34:46 -0700864 verify=vca.verify, logger=self.logger)
bhangarebfdca492017-03-11 01:32:46 -0800865
866 if response.status_code == requests.codes.ok:
867 media = mediaType.parseString(response.content, True)
868 link = filter(lambda link: link.get_rel() == 'upload:default',
869 media.get_Files().get_File()[0].get_Link())[0]
870 headers = vca.vcloud_session.get_vcloud_headers()
871 headers['Content-Type'] = 'Content-Type text/xml'
872 response = Http.put(link.get_href(),
873 data=open(media_file_name, 'rb'),
874 headers=headers,
875 verify=vca.verify, logger=self.logger)
876 if response.status_code != requests.codes.ok:
877 self.logger.debug(
878 "Failed create vApp template for catalog name {} and image {}".format(catalog_name,
879 media_file_name))
880 return False
881
882 # TODO fix this with aync block
883 time.sleep(5)
884
885 self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
886
887 # uploading VMDK file
888 # check status of OVF upload and upload remaining files.
889 response = Http.get(template,
890 headers=vca.vcloud_session.get_vcloud_headers(),
891 verify=vca.verify,
892 logger=self.logger)
893
894 if response.status_code == requests.codes.ok:
895 media = mediaType.parseString(response.content, True)
896 number_of_files = len(media.get_Files().get_File())
897 for index in xrange(0, number_of_files):
898 links_list = filter(lambda link: link.get_rel() == 'upload:default',
899 media.get_Files().get_File()[index].get_Link())
900 for link in links_list:
901 # we skip ovf since it already uploaded.
902 if 'ovf' in link.get_href():
903 continue
904 # The OVF file and VMDK must be in a same directory
905 head, tail = os.path.split(media_file_name)
906 file_vmdk = head + '/' + link.get_href().split("/")[-1]
907 if not os.path.isfile(file_vmdk):
908 return False
909 statinfo = os.stat(file_vmdk)
910 if statinfo.st_size == 0:
911 return False
912 hrefvmdk = link.get_href()
913
914 if progress:
915 print("Uploading file: {}".format(file_vmdk))
916 if progress:
917 widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
918 FileTransferSpeed()]
919 progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
920
921 bytes_transferred = 0
922 f = open(file_vmdk, 'rb')
923 while bytes_transferred < statinfo.st_size:
924 my_bytes = f.read(chunk_bytes)
925 if len(my_bytes) <= chunk_bytes:
926 headers = vca.vcloud_session.get_vcloud_headers()
927 headers['Content-Range'] = 'bytes %s-%s/%s' % (
928 bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
929 headers['Content-Length'] = str(len(my_bytes))
930 response = Http.put(hrefvmdk,
931 headers=headers,
932 data=my_bytes,
933 verify=vca.verify,
934 logger=None)
935
936 if response.status_code == requests.codes.ok:
937 bytes_transferred += len(my_bytes)
938 if progress:
939 progress_bar.update(bytes_transferred)
940 else:
941 self.logger.debug(
942 'file upload failed with error: [%s] %s' % (response.status_code,
943 response.content))
944
945 f.close()
946 return False
947 f.close()
948 if progress:
949 progress_bar.finish()
950 time.sleep(10)
951 return True
952 else:
953 self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
954 format(catalog_name, media_file_name))
bayramov325fa1c2016-09-08 01:42:46 -0700955 return False
bhangarebfdca492017-03-11 01:32:46 -0800956 except Exception as exp:
957 self.logger.debug("Failed while uploading OVF to catalog {} for OVF file {} with Exception {}"
958 .format(catalog_name,media_file_name, exp))
959 raise vimconn.vimconnException(
960 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}"
961 .format(catalog_name,media_file_name, exp))
bayramov325fa1c2016-09-08 01:42:46 -0700962
963 self.logger.debug("Failed retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
964 return False
965
bayramovfe3f3c92016-10-04 07:53:41 +0400966 def upload_vimimage(self, vca=None, catalog_name=None, media_name=None, medial_file_name=None, progress=False):
bayramov325fa1c2016-09-08 01:42:46 -0700967 """Upload media file"""
bayramovfe3f3c92016-10-04 07:53:41 +0400968 # TODO add named parameters for readability
969
970 return self.upload_ovf(vca=vca, catalog_name=catalog_name, image_name=media_name.split(".")[0],
971 media_file_name=medial_file_name, description='medial_file_name', progress=progress)
bayramov325fa1c2016-09-08 01:42:46 -0700972
bayramovb6ffe792016-09-28 11:50:56 +0400973 def validate_uuid4(self, uuid_string=None):
974 """ Method validate correct format of UUID.
975
976 Return: true if string represent valid uuid
977 """
978 try:
979 val = uuid.UUID(uuid_string, version=4)
980 except ValueError:
981 return False
982 return True
983
984 def get_catalogid(self, catalog_name=None, catalogs=None):
985 """ Method check catalog and return catalog ID in UUID format.
986
987 Args
988 catalog_name: catalog name as string
989 catalogs: list of catalogs.
990
991 Return: catalogs uuid
992 """
993
bayramov325fa1c2016-09-08 01:42:46 -0700994 for catalog in catalogs:
995 if catalog.name == catalog_name:
bayramov325fa1c2016-09-08 01:42:46 -0700996 catalog_id = catalog.get_id().split(":")
997 return catalog_id[3]
998 return None
999
bayramovb6ffe792016-09-28 11:50:56 +04001000 def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
1001 """ Method check catalog and return catalog name lookup done by catalog UUID.
1002
1003 Args
1004 catalog_name: catalog name as string
1005 catalogs: list of catalogs.
1006
1007 Return: catalogs name or None
1008 """
1009
1010 if not self.validate_uuid4(uuid_string=catalog_uuid):
1011 return None
1012
bayramov325fa1c2016-09-08 01:42:46 -07001013 for catalog in catalogs:
bayramovb6ffe792016-09-28 11:50:56 +04001014 catalog_id = catalog.get_id().split(":")[3]
1015 if catalog_id == catalog_uuid:
bayramov325fa1c2016-09-08 01:42:46 -07001016 return catalog.name
1017 return None
1018
bayramovfe3f3c92016-10-04 07:53:41 +04001019 def get_image_id_from_path(self, path=None, progress=False):
bayramovb6ffe792016-09-28 11:50:56 +04001020 """ Method upload OVF image to vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -07001021
bayramovb6ffe792016-09-28 11:50:56 +04001022 Each OVF image represented as single catalog entry in vcloud director.
1023 The method check for existing catalog entry. The check done by file name without file extension.
1024
1025 if given catalog name already present method will respond with existing catalog uuid otherwise
1026 it will create new catalog entry and upload OVF file to newly created catalog.
1027
1028 If method can't create catalog entry or upload a file it will throw exception.
1029
bayramovfe3f3c92016-10-04 07:53:41 +04001030 Method accept boolean flag progress that will output progress bar. It useful method
1031 for standalone upload use case. In case to test large file upload.
1032
bayramovb6ffe792016-09-28 11:50:56 +04001033 Args
bayramovfe3f3c92016-10-04 07:53:41 +04001034 path: - valid path to OVF file.
1035 progress - boolean progress bar show progress bar.
bayramovb6ffe792016-09-28 11:50:56 +04001036
1037 Return: if image uploaded correct method will provide image catalog UUID.
1038 """
bayramov325fa1c2016-09-08 01:42:46 -07001039 vca = self.connect()
1040 if not vca:
bayramovfe3f3c92016-10-04 07:53:41 +04001041 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramov325fa1c2016-09-08 01:42:46 -07001042
kate15f1c382016-12-15 01:12:40 -08001043 if not path:
bayramovfe3f3c92016-10-04 07:53:41 +04001044 raise vimconn.vimconnException("Image path can't be None.")
1045
1046 if not os.path.isfile(path):
1047 raise vimconn.vimconnException("Can't read file. File not found.")
1048
1049 if not os.access(path, os.R_OK):
1050 raise vimconn.vimconnException("Can't read file. Check file permission to read.")
1051
1052 self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
bayramov325fa1c2016-09-08 01:42:46 -07001053
1054 dirpath, filename = os.path.split(path)
1055 flname, file_extension = os.path.splitext(path)
1056 if file_extension != '.ovf':
bayramovfe3f3c92016-10-04 07:53:41 +04001057 self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
bayramovb6ffe792016-09-28 11:50:56 +04001058 raise vimconn.vimconnException("Wrong container. vCloud director supports only OVF.")
kate15f1c382016-12-15 01:12:40 -08001059
bayramov325fa1c2016-09-08 01:42:46 -07001060 catalog_name = os.path.splitext(filename)[0]
kate15f1c382016-12-15 01:12:40 -08001061 catalog_md5_name = hashlib.md5(path).hexdigest()
1062 self.logger.debug("File name {} Catalog Name {} file path {} "
1063 "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name))
bayramov325fa1c2016-09-08 01:42:46 -07001064
bhangarebfdca492017-03-11 01:32:46 -08001065 try:
1066 catalogs = vca.get_catalogs()
1067 except Exception as exp:
1068 self.logger.debug("Failed get catalogs() with Exception {} ".format(exp))
1069 raise vimconn.vimconnException("Failed get catalogs() with Exception {} ".format(exp))
1070
bayramov325fa1c2016-09-08 01:42:46 -07001071 if len(catalogs) == 0:
bayramovfe3f3c92016-10-04 07:53:41 +04001072 self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
kate15f1c382016-12-15 01:12:40 -08001073 result = self.create_vimcatalog(vca, catalog_md5_name)
bayramov325fa1c2016-09-08 01:42:46 -07001074 if not result:
kate15f1c382016-12-15 01:12:40 -08001075 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
1076 result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
bayramovfe3f3c92016-10-04 07:53:41 +04001077 media_name=filename, medial_file_name=path, progress=progress)
bayramov325fa1c2016-09-08 01:42:46 -07001078 if not result:
bayramovb6ffe792016-09-28 11:50:56 +04001079 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_name))
bayramov325fa1c2016-09-08 01:42:46 -07001080 return self.get_catalogid(catalog_name, vca.get_catalogs())
1081 else:
1082 for catalog in catalogs:
1083 # search for existing catalog if we find same name we return ID
1084 # TODO optimize this
kate15f1c382016-12-15 01:12:40 -08001085 if catalog.name == catalog_md5_name:
1086 self.logger.debug("Found existing catalog entry for {} "
1087 "catalog id {}".format(catalog_name,
1088 self.get_catalogid(catalog_md5_name, catalogs)))
1089 return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001090
bayramovfe3f3c92016-10-04 07:53:41 +04001091 # if we didn't find existing catalog we create a new one and upload image.
kate15f1c382016-12-15 01:12:40 -08001092 self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name))
1093 result = self.create_vimcatalog(vca, catalog_md5_name)
bayramov325fa1c2016-09-08 01:42:46 -07001094 if not result:
kate15f1c382016-12-15 01:12:40 -08001095 raise vimconn.vimconnException("Failed create new catalog {} ".format(catalog_md5_name))
bayramovfe3f3c92016-10-04 07:53:41 +04001096
kate15f1c382016-12-15 01:12:40 -08001097 result = self.upload_vimimage(vca=vca, catalog_name=catalog_md5_name,
bayramovfe3f3c92016-10-04 07:53:41 +04001098 media_name=filename, medial_file_name=path, progress=progress)
bayramov325fa1c2016-09-08 01:42:46 -07001099 if not result:
kate15f1c382016-12-15 01:12:40 -08001100 raise vimconn.vimconnException("Failed create vApp template for catalog {} ".format(catalog_md5_name))
bayramov325fa1c2016-09-08 01:42:46 -07001101
kate15f1c382016-12-15 01:12:40 -08001102 return self.get_catalogid(catalog_md5_name, vca.get_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001103
kate8fc61fc2017-01-23 19:57:06 -08001104 def get_image_list(self, filter_dict={}):
1105 '''Obtain tenant images from VIM
1106 Filter_dict can be:
1107 name: image name
1108 id: image uuid
1109 checksum: image checksum
1110 location: image path
1111 Returns the image list of dictionaries:
1112 [{<the fields at Filter_dict plus some VIM specific>}, ...]
1113 List can be empty
1114 '''
1115 vca = self.connect()
1116 if not vca:
1117 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1118 try:
1119 image_list = []
1120 catalogs = vca.get_catalogs()
1121 if len(catalogs) == 0:
1122 return image_list
1123 else:
1124 for catalog in catalogs:
1125 catalog_uuid = catalog.get_id().split(":")[3]
1126 name = catalog.name
1127 filtered_dict = {}
kate34718682017-01-24 03:20:43 -08001128 if filter_dict.get("name") and filter_dict["name"] != name:
1129 continue
1130 if filter_dict.get("id") and filter_dict["id"] != catalog_uuid:
1131 continue
1132 filtered_dict ["name"] = name
1133 filtered_dict ["id"] = catalog_uuid
1134 image_list.append(filtered_dict)
kate8fc61fc2017-01-23 19:57:06 -08001135
1136 self.logger.debug("List of already created catalog items: {}".format(image_list))
1137 return image_list
1138 except Exception as exp:
kated63062f2017-01-24 07:26:52 -08001139 raise vimconn.vimconnException("Exception occured while retriving catalog items {}".format(exp))
kate8fc61fc2017-01-23 19:57:06 -08001140
bayramovef390722016-09-27 03:34:46 -07001141 def get_vappid(self, vdc=None, vapp_name=None):
1142 """ Method takes vdc object and vApp name and returns vapp uuid or None
1143
1144 Args:
bayramovef390722016-09-27 03:34:46 -07001145 vdc: The VDC object.
1146 vapp_name: is application vappp name identifier
1147
bayramovb6ffe792016-09-28 11:50:56 +04001148 Returns:
bayramovef390722016-09-27 03:34:46 -07001149 The return vApp name otherwise None
1150 """
bayramovef390722016-09-27 03:34:46 -07001151 if vdc is None or vapp_name is None:
1152 return None
1153 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
bayramov325fa1c2016-09-08 01:42:46 -07001154 try:
1155 refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
bayramovef390722016-09-27 03:34:46 -07001156 vdc.ResourceEntities.ResourceEntity)
bayramov325fa1c2016-09-08 01:42:46 -07001157 if len(refs) == 1:
1158 return refs[0].href.split("vapp")[1][1:]
bayramovef390722016-09-27 03:34:46 -07001159 except Exception as e:
1160 self.logger.exception(e)
1161 return False
1162 return None
1163
bayramovfe3f3c92016-10-04 07:53:41 +04001164 def check_vapp(self, vdc=None, vapp_uuid=None):
1165 """ Method Method returns True or False if vapp deployed in vCloud director
bayramovef390722016-09-27 03:34:46 -07001166
1167 Args:
1168 vca: Connector to VCA
1169 vdc: The VDC object.
1170 vappid: vappid is application identifier
1171
1172 Returns:
bayramovfe3f3c92016-10-04 07:53:41 +04001173 The return True if vApp deployed
bayramov5761ad12016-10-04 09:00:30 +04001174 :param vdc:
1175 :param vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001176 """
1177 try:
1178 refs = filter(lambda ref:
1179 ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1180 vdc.ResourceEntities.ResourceEntity)
1181 for ref in refs:
1182 vappid = ref.href.split("vapp")[1][1:]
1183 # find vapp with respected vapp uuid
bayramovfe3f3c92016-10-04 07:53:41 +04001184 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001185 return True
1186 except Exception as e:
1187 self.logger.exception(e)
1188 return False
1189 return False
1190
bayramovfe3f3c92016-10-04 07:53:41 +04001191 def get_namebyvappid(self, vca=None, vdc=None, vapp_uuid=None):
bayramovef390722016-09-27 03:34:46 -07001192 """Method returns vApp name from vCD and lookup done by vapp_id.
1193
1194 Args:
1195 vca: Connector to VCA
1196 vdc: The VDC object.
bayramovfe3f3c92016-10-04 07:53:41 +04001197 vapp_uuid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001198
1199 Returns:
1200 The return vApp name otherwise None
1201 """
1202
1203 try:
1204 refs = filter(lambda ref: ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',
1205 vdc.ResourceEntities.ResourceEntity)
1206 for ref in refs:
1207 # we care only about UUID the rest doesn't matter
1208 vappid = ref.href.split("vapp")[1][1:]
bayramovfe3f3c92016-10-04 07:53:41 +04001209 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001210 response = Http.get(ref.href, headers=vca.vcloud_session.get_vcloud_headers(), verify=vca.verify,
1211 logger=self.logger)
1212 tree = XmlElementTree.fromstring(response.content)
1213 return tree.attrib['name']
1214 except Exception as e:
1215 self.logger.exception(e)
bayramov325fa1c2016-09-08 01:42:46 -07001216 return None
1217 return None
1218
bayramovfe3f3c92016-10-04 07:53:41 +04001219 def new_vminstance(self, name=None, description="", start=False, image_id=None, flavor_id=None, net_list={},
montesmoreno0c8def02016-12-22 12:16:23 +00001220 cloud_config=None, disk_list=None):
bayramov325fa1c2016-09-08 01:42:46 -07001221 """Adds a VM instance to VIM
1222 Params:
1223 start: indicates if VM must start or boot in pause mode. Ignored
1224 image_id,flavor_id: image and flavor uuid
1225 net_list: list of interfaces, each one is a dictionary with:
1226 name:
1227 net_id: network uuid to connect
1228 vpci: virtual vcpi to assign
1229 model: interface model, virtio, e2000, ...
1230 mac_address:
1231 use: 'data', 'bridge', 'mgmt'
1232 type: 'virtual', 'PF', 'VF', 'VFnotShared'
1233 vim_id: filled/added by this function
1234 cloud_config: can be a text script to be passed directly to cloud-init,
1235 or an object to inject users and ssh keys with format:
1236 key-pairs: [] list of keys to install to the default user
1237 users: [{ name, key-pairs: []}] list of users to add with their key-pair
1238 #TODO ip, security groups
1239 Returns >=0, the instance identifier
1240 <0, error_text
1241 """
1242
kate15f1c382016-12-15 01:12:40 -08001243 self.logger.info("Creating new instance for entry {}".format(name))
kateeb044522017-03-06 23:54:39 -08001244 self.logger.debug("desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {}".format(
1245 description, start, image_id, flavor_id, net_list, cloud_config))
bayramov325fa1c2016-09-08 01:42:46 -07001246 vca = self.connect()
1247 if not vca:
1248 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1249
bayramov5761ad12016-10-04 09:00:30 +04001250 #new vm name = vmname + tenant_id + uuid
1251 new_vm_name = [name, '-', str(uuid.uuid4())]
kate15f1c382016-12-15 01:12:40 -08001252 vmname_andid = ''.join(new_vm_name)
bayramov5761ad12016-10-04 09:00:30 +04001253
bayramovef390722016-09-27 03:34:46 -07001254 # if vm already deployed we return existing uuid
bayramov5761ad12016-10-04 09:00:30 +04001255 # vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), name)
1256 # if vapp_uuid is not None:
1257 # return vapp_uuid
bayramov325fa1c2016-09-08 01:42:46 -07001258
bayramovef390722016-09-27 03:34:46 -07001259 # we check for presence of VDC, Catalog entry and Flavor.
1260 vdc = vca.get_vdc(self.tenant_name)
1261 if vdc is None:
bayramovfe3f3c92016-10-04 07:53:41 +04001262 raise vimconn.vimconnNotFoundException(
bayramovb6ffe792016-09-28 11:50:56 +04001263 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(name))
bayramov325fa1c2016-09-08 01:42:46 -07001264 catalogs = vca.get_catalogs()
bayramovef390722016-09-27 03:34:46 -07001265 if catalogs is None:
bayramovfe3f3c92016-10-04 07:53:41 +04001266 raise vimconn.vimconnNotFoundException(
kate15f1c382016-12-15 01:12:40 -08001267 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(name))
bayramovbd6160f2016-09-28 04:12:05 +04001268
kate15f1c382016-12-15 01:12:40 -08001269 catalog_hash_name = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
1270 if catalog_hash_name:
1271 self.logger.info("Found catalog entry {} for image id {}".format(catalog_hash_name, image_id))
1272 else:
1273 raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
1274 "(Failed retrieve catalog information {})".format(name, image_id))
1275
1276
1277 # Set vCPU and Memory based on flavor.
1278 #
bayramovb6ffe792016-09-28 11:50:56 +04001279 vm_cpus = None
1280 vm_memory = None
bhangarea92ae392017-01-12 22:30:29 -08001281 vm_disk = None
bhangarefda5f7c2017-01-12 23:50:34 -08001282 pci_devices_info = []
bayramovb6ffe792016-09-28 11:50:56 +04001283 if flavor_id is not None:
kateeb044522017-03-06 23:54:39 -08001284 if flavor_id not in vimconnector.flavorlist:
kate15f1c382016-12-15 01:12:40 -08001285 raise vimconn.vimconnNotFoundException("new_vminstance(): Failed create vApp {}: "
1286 "Failed retrieve flavor information "
1287 "flavor id {}".format(name, flavor_id))
bayramovb6ffe792016-09-28 11:50:56 +04001288 else:
1289 try:
kateeb044522017-03-06 23:54:39 -08001290 flavor = vimconnector.flavorlist[flavor_id]
kate15f1c382016-12-15 01:12:40 -08001291 vm_cpus = flavor[FLAVOR_VCPUS_KEY]
1292 vm_memory = flavor[FLAVOR_RAM_KEY]
bhangarea92ae392017-01-12 22:30:29 -08001293 vm_disk = flavor[FLAVOR_DISK_KEY]
bhangarefda5f7c2017-01-12 23:50:34 -08001294 extended = flavor.get("extended", None)
1295 if extended:
1296 numas=extended.get("numas", None)
1297 if numas:
1298 for numa in numas:
1299 for interface in numa.get("interfaces",() ):
1300 if interface["dedicated"].strip()=="yes":
1301 pci_devices_info.append(interface)
kateeb044522017-03-06 23:54:39 -08001302 except Exception as exp:
1303 raise vimconn.vimconnException("Corrupted flavor. {}.Exception: {}".format(flavor_id, exp))
bayramov325fa1c2016-09-08 01:42:46 -07001304
bayramovef390722016-09-27 03:34:46 -07001305 # image upload creates template name as catalog name space Template.
kate15f1c382016-12-15 01:12:40 -08001306 templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
bayramovef390722016-09-27 03:34:46 -07001307 power_on = 'false'
1308 if start:
1309 power_on = 'true'
1310
1311 # client must provide at least one entry in net_list if not we report error
bhangare0e571a92017-01-12 04:02:23 -08001312 #If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
1313 #If no mgmt, then the 1st NN in netlist is considered as primary net.
1314 primary_net = None
kate15f1c382016-12-15 01:12:40 -08001315 primary_netname = None
1316 network_mode = 'bridged'
bayramovb6ffe792016-09-28 11:50:56 +04001317 if net_list is not None and len(net_list) > 0:
bhangare0e571a92017-01-12 04:02:23 -08001318 for net in net_list:
1319 if 'use' in net and net['use'] == 'mgmt':
1320 primary_net = net
bayramovb6ffe792016-09-28 11:50:56 +04001321 if primary_net is None:
bhangare0e571a92017-01-12 04:02:23 -08001322 primary_net = net_list[0]
1323
1324 try:
1325 primary_net_id = primary_net['net_id']
1326 network_dict = self.get_vcd_network(network_uuid=primary_net_id)
1327 if 'name' in network_dict:
1328 primary_netname = network_dict['name']
1329
1330 except KeyError:
1331 raise vimconn.vimconnException("Corrupted flavor. {}".format(primary_net))
1332 else:
1333 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed network list is empty.".format(name))
bayramovef390722016-09-27 03:34:46 -07001334
1335 # use: 'data', 'bridge', 'mgmt'
1336 # create vApp. Set vcpu and ram based on flavor id.
bhangarebfdca492017-03-11 01:32:46 -08001337 try:
1338 vapptask = vca.create_vapp(self.tenant_name, vmname_andid, templateName,
1339 self.get_catalogbyid(image_id, catalogs),
1340 network_name=None, # None while creating vapp
1341 network_mode=network_mode,
1342 vm_name=vmname_andid,
1343 vm_cpus=vm_cpus, # can be None if flavor is None
1344 vm_memory=vm_memory) # can be None if flavor is None
bayramovef390722016-09-27 03:34:46 -07001345
bhangarebfdca492017-03-11 01:32:46 -08001346 if vapptask is None or vapptask is False:
1347 raise vimconn.vimconnUnexpectedResponse(
1348 "new_vminstance(): failed to create vApp {}".format(vmname_andid))
1349 if type(vapptask) is VappTask:
1350 vca.block_until_completed(vapptask)
1351
1352 except Exception as exp:
1353 raise vimconn.vimconnUnexpectedResponse(
1354 "new_vminstance(): failed to create vApp {} with Exception:{}".format(vmname_andid, exp))
bayramovef390722016-09-27 03:34:46 -07001355
1356 # we should have now vapp in undeployed state.
bhangarebfdca492017-03-11 01:32:46 -08001357 try:
1358 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
1359 vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
1360 except Exception as exp:
1361 raise vimconn.vimconnUnexpectedResponse(
1362 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}"
1363 .format(vmname_andid, exp))
1364
bayramovef390722016-09-27 03:34:46 -07001365 if vapp is None:
bayramovbd6160f2016-09-28 04:12:05 +04001366 raise vimconn.vimconnUnexpectedResponse(
bhangarebfdca492017-03-11 01:32:46 -08001367 "new_vminstance(): Failed to retrieve vApp {} after creation".format(
bhangarea92ae392017-01-12 22:30:29 -08001368 vmname_andid))
1369
bhangarefda5f7c2017-01-12 23:50:34 -08001370 #Add PCI passthrough configrations
1371 PCI_devices_status = False
1372 vm_obj = None
1373 si = None
1374 if len(pci_devices_info) > 0:
1375 self.logger.info("Need to add PCI devices {} into VM {}".format(pci_devices_info,
1376 vmname_andid ))
1377 PCI_devices_status, vm_obj, vcenter_conect = self.add_pci_devices(vapp_uuid,
1378 pci_devices_info,
1379 vmname_andid)
1380 if PCI_devices_status:
1381 self.logger.info("Added PCI devives {} to VM {}".format(
1382 pci_devices_info,
1383 vmname_andid)
1384 )
1385 else:
1386 self.logger.info("Fail to add PCI devives {} to VM {}".format(
1387 pci_devices_info,
1388 vmname_andid)
1389 )
bhangarea92ae392017-01-12 22:30:29 -08001390 # add vm disk
1391 if vm_disk:
1392 #Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
1393 result = self.modify_vm_disk(vapp_uuid, vm_disk)
1394 if result :
1395 self.logger.debug("Modified Disk size of VM {} ".format(vmname_andid))
bayramovef390722016-09-27 03:34:46 -07001396
kasarde691232017-03-25 03:37:31 -07001397 if numas:
1398 # Assigning numa affinity setting
1399 for numa in numas:
1400 if 'paired-threads-id' in numa:
1401 paired_threads_id = numa['paired-threads-id']
1402 self.set_numa_affinity(vapp_uuid, paired_threads_id)
1403
bhangare0e571a92017-01-12 04:02:23 -08001404 # add NICs & connect to networks in netlist
bayramovef390722016-09-27 03:34:46 -07001405 try:
kate15f1c382016-12-15 01:12:40 -08001406 self.logger.info("Request to connect VM to a network: {}".format(net_list))
bayramovef390722016-09-27 03:34:46 -07001407 nicIndex = 0
bhangare0e571a92017-01-12 04:02:23 -08001408 primary_nic_index = 0
bayramovef390722016-09-27 03:34:46 -07001409 for net in net_list:
1410 # openmano uses network id in UUID format.
1411 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
kate15f1c382016-12-15 01:12:40 -08001412 # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
1413 # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
1414
1415 if 'net_id' not in net:
1416 continue
1417
bayramovef390722016-09-27 03:34:46 -07001418 interface_net_id = net['net_id']
kate15f1c382016-12-15 01:12:40 -08001419 interface_net_name = self.get_network_name_by_id(network_uuid=interface_net_id)
bayramovef390722016-09-27 03:34:46 -07001420 interface_network_mode = net['use']
1421
bhangare0e571a92017-01-12 04:02:23 -08001422 if interface_network_mode == 'mgmt':
1423 primary_nic_index = nicIndex
1424
kate15f1c382016-12-15 01:12:40 -08001425 """- POOL (A static IP address is allocated automatically from a pool of addresses.)
1426 - DHCP (The IP address is obtained from a DHCP service.)
1427 - MANUAL (The IP address is assigned manually in the IpAddress element.)
1428 - NONE (No IP addressing mode specified.)"""
1429
1430 if primary_netname is not None:
bayramovef390722016-09-27 03:34:46 -07001431 nets = filter(lambda n: n.name == interface_net_name, vca.get_networks(self.tenant_name))
1432 if len(nets) == 1:
bhangare0e571a92017-01-12 04:02:23 -08001433 self.logger.info("new_vminstance(): Found requested network: {}".format(nets[0].name))
bayramovef390722016-09-27 03:34:46 -07001434 task = vapp.connect_to_network(nets[0].name, nets[0].href)
1435 if type(task) is GenericTask:
1436 vca.block_until_completed(task)
bhangare0e571a92017-01-12 04:02:23 -08001437 # connect network to VM - with all DHCP by default
kasar3ac5dc42017-03-15 06:28:22 -07001438
1439 type_list = ['PF','VF','VFnotShared']
1440 if 'type' in net and net['type'] not in type_list:
1441 # fetching nic type from vnf
1442 if 'model' in net:
1443 nic_type = net['model']
1444 self.logger.info("new_vminstance(): adding network adapter "\
1445 "to a network {}".format(nets[0].name))
1446 self.add_network_adapter_to_vms(vapp, nets[0].name,
1447 primary_nic_index,
1448 nicIndex,
kasardc1f02e2017-03-25 07:20:30 -07001449 net,
kasar3ac5dc42017-03-15 06:28:22 -07001450 nic_type=nic_type)
1451 else:
1452 self.logger.info("new_vminstance(): adding network adapter "\
1453 "to a network {}".format(nets[0].name))
1454 self.add_network_adapter_to_vms(vapp, nets[0].name,
1455 primary_nic_index,
kasardc1f02e2017-03-25 07:20:30 -07001456 nicIndex,
1457 net)
bhangare0e571a92017-01-12 04:02:23 -08001458 nicIndex += 1
bayramovef390722016-09-27 03:34:46 -07001459
kasardc1f02e2017-03-25 07:20:30 -07001460 # cloud-init for ssh-key injection
1461 if cloud_config:
1462 self.cloud_init(vapp,cloud_config)
1463
bhangarebfdca492017-03-11 01:32:46 -08001464 # deploy and power on vm
1465 self.logger.debug("new_vminstance(): Deploying vApp {} ".format(name))
1466 deploytask = vapp.deploy(powerOn=False)
1467 if type(deploytask) is GenericTask:
1468 vca.block_until_completed(deploytask)
bayramovef390722016-09-27 03:34:46 -07001469
bhangarebfdca492017-03-11 01:32:46 -08001470 # If VM has PCI devices reserve memory for VM
1471 if PCI_devices_status and vm_obj and vcenter_conect:
1472 memReserve = vm_obj.config.hardware.memoryMB
1473 spec = vim.vm.ConfigSpec()
1474 spec.memoryAllocation = vim.ResourceAllocationInfo(reservation=memReserve)
1475 task = vm_obj.ReconfigVM_Task(spec=spec)
1476 if task:
1477 result = self.wait_for_vcenter_task(task, vcenter_conect)
1478 self.logger.info("Reserved memmoery {} MB for "\
1479 "VM VM status: {}".format(str(memReserve),result))
1480 else:
1481 self.logger.info("Fail to reserved memmoery {} to VM {}".format(
1482 str(memReserve),str(vm_obj)))
bhangarefda5f7c2017-01-12 23:50:34 -08001483
bhangarebfdca492017-03-11 01:32:46 -08001484 self.logger.debug("new_vminstance(): power on vApp {} ".format(name))
1485 poweron_task = vapp.poweron()
1486 if type(poweron_task) is GenericTask:
1487 vca.block_until_completed(poweron_task)
1488
1489 except Exception as exp :
1490 # it might be a case if specific mandatory entry in dict is empty or some other pyVcloud exception
1491 self.logger.debug("new_vminstance(): Failed create new vm instance {}".format(name, exp))
1492 raise vimconn.vimconnException("new_vminstance(): Failed create new vm instance {}".format(name, exp))
bhangarefda5f7c2017-01-12 23:50:34 -08001493
bayramovef390722016-09-27 03:34:46 -07001494 # check if vApp deployed and if that the case return vApp UUID otherwise -1
kate13ab2c42016-12-23 01:34:24 -08001495 wait_time = 0
1496 vapp_uuid = None
1497 while wait_time <= MAX_WAIT_TIME:
bhangarebfdca492017-03-11 01:32:46 -08001498 try:
1499 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vmname_andid)
1500 except Exception as exp:
1501 raise vimconn.vimconnUnexpectedResponse(
1502 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}"
1503 .format(vmname_andid, exp))
1504
kate13ab2c42016-12-23 01:34:24 -08001505 if vapp and vapp.me.deployed:
1506 vapp_uuid = self.get_vappid(vca.get_vdc(self.tenant_name), vmname_andid)
1507 break
1508 else:
1509 self.logger.debug("new_vminstance(): Wait for vApp {} to deploy".format(name))
1510 time.sleep(INTERVAL_TIME)
1511
1512 wait_time +=INTERVAL_TIME
1513
bayramovef390722016-09-27 03:34:46 -07001514 if vapp_uuid is not None:
1515 return vapp_uuid
bayramovbd6160f2016-09-28 04:12:05 +04001516 else:
1517 raise vimconn.vimconnUnexpectedResponse("new_vminstance(): Failed create new vm instance {}".format(name))
bayramov325fa1c2016-09-08 01:42:46 -07001518
bayramovef390722016-09-27 03:34:46 -07001519 ##
1520 ##
1521 ## based on current discussion
1522 ##
1523 ##
1524 ## server:
1525 # created: '2016-09-08T11:51:58'
1526 # description: simple-instance.linux1.1
1527 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
1528 # hostId: e836c036-74e7-11e6-b249-0800273e724c
1529 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
1530 # status: ACTIVE
1531 # error_msg:
1532 # interfaces: …
1533 #
bayramovfe3f3c92016-10-04 07:53:41 +04001534 def get_vminstance(self, vim_vm_uuid=None):
bayramov5761ad12016-10-04 09:00:30 +04001535 """Returns the VM instance information from VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07001536
bayramovef390722016-09-27 03:34:46 -07001537 self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001538 vca = self.connect()
1539 if not vca:
1540 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1541
bayramovef390722016-09-27 03:34:46 -07001542 vdc = vca.get_vdc(self.tenant_name)
1543 if vdc is None:
bayramovfe3f3c92016-10-04 07:53:41 +04001544 raise vimconn.vimconnConnectionException(
1545 "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -07001546
bayramovfe3f3c92016-10-04 07:53:41 +04001547 vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
1548 if not vm_info_dict:
bayramovef390722016-09-27 03:34:46 -07001549 self.logger.debug("get_vminstance(): Failed to get vApp name by UUID {}".format(vim_vm_uuid))
bayramovfe3f3c92016-10-04 07:53:41 +04001550 raise vimconn.vimconnNotFoundException("Failed to get vApp name by UUID {}".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001551
bayramovfe3f3c92016-10-04 07:53:41 +04001552 status_key = vm_info_dict['status']
1553 error = ''
bayramovef390722016-09-27 03:34:46 -07001554 try:
bayramovfe3f3c92016-10-04 07:53:41 +04001555 vm_dict = {'created': vm_info_dict['created'],
1556 'description': vm_info_dict['name'],
1557 'status': vcdStatusCode2manoFormat[int(status_key)],
1558 'hostId': vm_info_dict['vmuuid'],
1559 'error_msg': error,
1560 'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
bayramovef390722016-09-27 03:34:46 -07001561
bayramov5761ad12016-10-04 09:00:30 +04001562 if 'interfaces' in vm_info_dict:
bayramovfe3f3c92016-10-04 07:53:41 +04001563 vm_dict['interfaces'] = vm_info_dict['interfaces']
1564 else:
1565 vm_dict['interfaces'] = []
1566 except KeyError:
1567 vm_dict = {'created': '',
1568 'description': '',
1569 'status': vcdStatusCode2manoFormat[int(-1)],
1570 'hostId': vm_info_dict['vmuuid'],
1571 'error_msg': "Inconsistency state",
1572 'vim_info': yaml.safe_dump(vm_info_dict), 'interfaces': []}
bayramovef390722016-09-27 03:34:46 -07001573
1574 return vm_dict
1575
1576 def delete_vminstance(self, vm__vim_uuid):
1577 """Method poweroff and remove VM instance from vcloud director network.
1578
1579 Args:
1580 vm__vim_uuid: VM UUID
1581
1582 Returns:
1583 Returns the instance identifier
1584 """
1585
1586 self.logger.debug("Client requesting delete vm instance {} ".format(vm__vim_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001587 vca = self.connect()
1588 if not vca:
1589 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1590
bayramovef390722016-09-27 03:34:46 -07001591 vdc = vca.get_vdc(self.tenant_name)
1592 if vdc is None:
1593 self.logger.debug("delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
1594 self.tenant_name))
bayramovbd6160f2016-09-28 04:12:05 +04001595 raise vimconn.vimconnException(
1596 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
bayramov325fa1c2016-09-08 01:42:46 -07001597
bayramovef390722016-09-27 03:34:46 -07001598 try:
1599 vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
1600 if vapp_name is None:
1601 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1602 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1603 else:
1604 self.logger.info("Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001605
bayramovef390722016-09-27 03:34:46 -07001606 # Delete vApp and wait for status change if task executed and vApp is None.
bayramovef390722016-09-27 03:34:46 -07001607 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
bayramov325fa1c2016-09-08 01:42:46 -07001608
kate13ab2c42016-12-23 01:34:24 -08001609 if vapp:
1610 if vapp.me.deployed:
1611 self.logger.info("Powering off vApp {}".format(vapp_name))
1612 #Power off vApp
1613 powered_off = False
1614 wait_time = 0
1615 while wait_time <= MAX_WAIT_TIME:
1616 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1617 if not vapp:
1618 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1619 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
bayramovef390722016-09-27 03:34:46 -07001620
kate13ab2c42016-12-23 01:34:24 -08001621 power_off_task = vapp.poweroff()
1622 if type(power_off_task) is GenericTask:
1623 result = vca.block_until_completed(power_off_task)
1624 if result:
1625 powered_off = True
1626 break
1627 else:
1628 self.logger.info("Wait for vApp {} to power off".format(vapp_name))
1629 time.sleep(INTERVAL_TIME)
1630
1631 wait_time +=INTERVAL_TIME
1632 if not powered_off:
1633 self.logger.debug("delete_vminstance(): Failed to power off VM instance {} ".format(vm__vim_uuid))
1634 else:
1635 self.logger.info("delete_vminstance(): Powered off VM instance {} ".format(vm__vim_uuid))
1636
1637 #Undeploy vApp
1638 self.logger.info("Undeploy vApp {}".format(vapp_name))
1639 wait_time = 0
1640 undeployed = False
1641 while wait_time <= MAX_WAIT_TIME:
1642 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1643 if not vapp:
1644 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1645 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1646 undeploy_task = vapp.undeploy(action='powerOff')
1647
1648 if type(undeploy_task) is GenericTask:
1649 result = vca.block_until_completed(undeploy_task)
1650 if result:
1651 undeployed = True
1652 break
1653 else:
1654 self.logger.debug("Wait for vApp {} to undeploy".format(vapp_name))
1655 time.sleep(INTERVAL_TIME)
1656
1657 wait_time +=INTERVAL_TIME
1658
1659 if not undeployed:
1660 self.logger.debug("delete_vminstance(): Failed to undeploy vApp {} ".format(vm__vim_uuid))
1661
1662 # delete vapp
1663 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
1664 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1665
1666 if vapp is not None:
1667 wait_time = 0
1668 result = False
1669
1670 while wait_time <= MAX_WAIT_TIME:
1671 vapp = vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name)
1672 if not vapp:
1673 self.logger.debug("delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
1674 return -1, "delete_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
1675
1676 delete_task = vapp.delete()
1677
1678 if type(delete_task) is GenericTask:
1679 vca.block_until_completed(delete_task)
1680 result = vca.block_until_completed(delete_task)
1681 if result:
1682 break
1683 else:
1684 self.logger.debug("Wait for vApp {} to delete".format(vapp_name))
1685 time.sleep(INTERVAL_TIME)
1686
1687 wait_time +=INTERVAL_TIME
1688
1689 if not result:
bayramovbd6160f2016-09-28 04:12:05 +04001690 self.logger.debug("delete_vminstance(): Failed delete uuid {} ".format(vm__vim_uuid))
bayramovef390722016-09-27 03:34:46 -07001691
bayramovef390722016-09-27 03:34:46 -07001692 except:
1693 self.logger.debug(traceback.format_exc())
bayramovbd6160f2016-09-28 04:12:05 +04001694 raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
bayramovef390722016-09-27 03:34:46 -07001695
bayramovbd6160f2016-09-28 04:12:05 +04001696 if vca.get_vapp(vca.get_vdc(self.tenant_name), vapp_name) is None:
kate13ab2c42016-12-23 01:34:24 -08001697 self.logger.info("Deleted vm instance {} sccessfully".format(vm__vim_uuid))
bayramovbd6160f2016-09-28 04:12:05 +04001698 return vm__vim_uuid
1699 else:
1700 raise vimconn.vimconnException("delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07001701
1702 def refresh_vms_status(self, vm_list):
bayramovef390722016-09-27 03:34:46 -07001703 """Get the status of the virtual machines and their interfaces/ports
bayramov325fa1c2016-09-08 01:42:46 -07001704 Params: the list of VM identifiers
1705 Returns a dictionary with:
1706 vm_id: #VIM id of this Virtual Machine
1707 status: #Mandatory. Text with one of:
1708 # DELETED (not found at vim)
bayramovef390722016-09-27 03:34:46 -07001709 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
bayramov325fa1c2016-09-08 01:42:46 -07001710 # OTHER (Vim reported other status not understood)
1711 # ERROR (VIM indicates an ERROR status)
bayramovef390722016-09-27 03:34:46 -07001712 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
bayramov325fa1c2016-09-08 01:42:46 -07001713 # CREATING (on building process), ERROR
1714 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
1715 #
bayramovef390722016-09-27 03:34:46 -07001716 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
bayramov325fa1c2016-09-08 01:42:46 -07001717 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1718 interfaces:
1719 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
1720 mac_address: #Text format XX:XX:XX:XX:XX:XX
1721 vim_net_id: #network id where this interface is connected
1722 vim_interface_id: #interface/port VIM id
1723 ip_address: #null, or text with IPv4, IPv6 address
bayramovef390722016-09-27 03:34:46 -07001724 """
bayramov325fa1c2016-09-08 01:42:46 -07001725
bayramovef390722016-09-27 03:34:46 -07001726 self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
bhangare985a1fd2017-01-31 01:53:21 -08001727
bayramovef390722016-09-27 03:34:46 -07001728 vca = self.connect()
1729 if not vca:
1730 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramov325fa1c2016-09-08 01:42:46 -07001731
bayramovef390722016-09-27 03:34:46 -07001732 vdc = vca.get_vdc(self.tenant_name)
1733 if vdc is None:
bayramovbd6160f2016-09-28 04:12:05 +04001734 raise vimconn.vimconnException("Failed to get a reference of VDC for a tenant {}".format(self.tenant_name))
bayramovef390722016-09-27 03:34:46 -07001735
1736 vms_dict = {}
kasarde691232017-03-25 03:37:31 -07001737 nsx_edge_list = []
bayramovef390722016-09-27 03:34:46 -07001738 for vmuuid in vm_list:
1739 vmname = self.get_namebyvappid(vca, vdc, vmuuid)
1740 if vmname is not None:
1741
bayramovef390722016-09-27 03:34:46 -07001742 try:
bhangarebfdca492017-03-11 01:32:46 -08001743 the_vapp = vca.get_vapp(vdc, vmname)
1744 vm_info = the_vapp.get_vms_details()
1745 vm_status = vm_info[0]['status']
1746 vm_pci_details = self.get_vm_pci_details(vmuuid)
1747 vm_info[0].update(vm_pci_details)
1748
1749 vm_dict = {'status': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
1750 'error_msg': vcdStatusCode2manoFormat[the_vapp.me.get_status()],
1751 'vim_info': yaml.safe_dump(vm_info), 'interfaces': []}
1752
1753 # get networks
bayramovef390722016-09-27 03:34:46 -07001754 vm_app_networks = the_vapp.get_vms_network_info()
1755 for vapp_network in vm_app_networks:
1756 for vm_network in vapp_network:
1757 if vm_network['name'] == vmname:
bhangare985a1fd2017-01-31 01:53:21 -08001758 #Assign IP Address based on MAC Address in NSX DHCP lease info
kasarde691232017-03-25 03:37:31 -07001759 if vm_network['ip'] is None:
1760 if not nsx_edge_list:
1761 nsx_edge_list = self.get_edge_details()
1762 if nsx_edge_list is None:
1763 raise vimconn.vimconnException("refresh_vms_status:"\
1764 "Failed to get edge details from NSX Manager")
1765 if vm_network['mac'] is not None:
1766 vm_network['ip'] = self.get_ipaddr_from_NSXedge(nsx_edge_list, vm_network['mac'])
1767
1768 vm_net_id = self.get_network_id_by_name(vm_network['network_name'])
bayramov5761ad12016-10-04 09:00:30 +04001769 interface = {"mac_address": vm_network['mac'],
kasarde691232017-03-25 03:37:31 -07001770 "vim_net_id": vm_net_id,
1771 "vim_interface_id": vm_net_id,
bayramov5761ad12016-10-04 09:00:30 +04001772 'ip_address': vm_network['ip']}
bayramovef390722016-09-27 03:34:46 -07001773 # interface['vim_info'] = yaml.safe_dump(vm_network)
bayramovef390722016-09-27 03:34:46 -07001774 vm_dict["interfaces"].append(interface)
1775 # add a vm to vm dict
1776 vms_dict.setdefault(vmuuid, vm_dict)
bhangarebfdca492017-03-11 01:32:46 -08001777 except Exception as exp:
1778 self.logger.debug("Error in response {}".format(exp))
bayramovef390722016-09-27 03:34:46 -07001779 self.logger.debug(traceback.format_exc())
1780
1781 return vms_dict
1782
kasarde691232017-03-25 03:37:31 -07001783
1784 def get_edge_details(self):
1785 """Get the NSX edge list from NSX Manager
1786 Returns list of NSX edges
1787 """
1788 edge_list = []
1789 rheaders = {'Content-Type': 'application/xml'}
1790 nsx_api_url = '/api/4.0/edges'
1791
1792 self.logger.debug("Get edge details from NSX Manager {} {}".format(self.nsx_manager, nsx_api_url))
1793
1794 try:
1795 resp = requests.get(self.nsx_manager + nsx_api_url,
1796 auth = (self.nsx_user, self.nsx_password),
1797 verify = False, headers = rheaders)
1798 if resp.status_code == requests.codes.ok:
1799 paged_Edge_List = XmlElementTree.fromstring(resp.text)
1800 for edge_pages in paged_Edge_List:
1801 if edge_pages.tag == 'edgePage':
1802 for edge_summary in edge_pages:
1803 if edge_summary.tag == 'pagingInfo':
1804 for element in edge_summary:
1805 if element.tag == 'totalCount' and element.text == '0':
1806 raise vimconn.vimconnException("get_edge_details: No NSX edges details found: {}"
1807 .format(self.nsx_manager))
1808
1809 if edge_summary.tag == 'edgeSummary':
1810 for element in edge_summary:
1811 if element.tag == 'id':
1812 edge_list.append(element.text)
1813 else:
1814 raise vimconn.vimconnException("get_edge_details: No NSX edge details found: {}"
1815 .format(self.nsx_manager))
1816
1817 if not edge_list:
1818 raise vimconn.vimconnException("get_edge_details: "\
1819 "No NSX edge details found: {}"
1820 .format(self.nsx_manager))
1821 else:
1822 self.logger.debug("get_edge_details: Found NSX edges {}".format(edge_list))
1823 return edge_list
1824 else:
1825 self.logger.debug("get_edge_details: "
1826 "Failed to get NSX edge details from NSX Manager: {}"
1827 .format(resp.content))
1828 return None
1829
1830 except Exception as exp:
1831 self.logger.debug("get_edge_details: "\
1832 "Failed to get NSX edge details from NSX Manager: {}"
1833 .format(exp))
1834 raise vimconn.vimconnException("get_edge_details: "\
1835 "Failed to get NSX edge details from NSX Manager: {}"
1836 .format(exp))
1837
1838
1839 def get_ipaddr_from_NSXedge(self, nsx_edges, mac_address):
1840 """Get IP address details from NSX edges, using the MAC address
1841 PARAMS: nsx_edges : List of NSX edges
1842 mac_address : Find IP address corresponding to this MAC address
1843 Returns: IP address corrresponding to the provided MAC address
1844 """
1845
1846 ip_addr = None
1847 rheaders = {'Content-Type': 'application/xml'}
1848
1849 self.logger.debug("get_ipaddr_from_NSXedge: Finding IP addr from NSX edge")
1850
1851 try:
1852 for edge in nsx_edges:
1853 nsx_api_url = '/api/4.0/edges/'+ edge +'/dhcp/leaseInfo'
1854
1855 resp = requests.get(self.nsx_manager + nsx_api_url,
1856 auth = (self.nsx_user, self.nsx_password),
1857 verify = False, headers = rheaders)
1858
1859 if resp.status_code == requests.codes.ok:
1860 dhcp_leases = XmlElementTree.fromstring(resp.text)
1861 for child in dhcp_leases:
1862 if child.tag == 'dhcpLeaseInfo':
1863 dhcpLeaseInfo = child
1864 for leaseInfo in dhcpLeaseInfo:
1865 for elem in leaseInfo:
1866 if (elem.tag)=='macAddress':
1867 edge_mac_addr = elem.text
1868 if (elem.tag)=='ipAddress':
1869 ip_addr = elem.text
1870 if edge_mac_addr is not None:
1871 if edge_mac_addr == mac_address:
1872 self.logger.debug("Found ip addr {} for mac {} at NSX edge {}"
1873 .format(ip_addr, mac_address,edge))
1874 return ip_addr
1875 else:
1876 self.logger.debug("get_ipaddr_from_NSXedge: "\
1877 "Error occurred while getting DHCP lease info from NSX Manager: {}"
1878 .format(resp.content))
1879
1880 self.logger.debug("get_ipaddr_from_NSXedge: No IP addr found in any NSX edge")
1881 return None
1882
1883 except XmlElementTree.ParseError as Err:
1884 self.logger.debug("ParseError in response from NSX Manager {}".format(Err.message), exc_info=True)
1885
1886
bayramovef390722016-09-27 03:34:46 -07001887 def action_vminstance(self, vm__vim_uuid=None, action_dict=None):
1888 """Send and action over a VM instance from VIM
1889 Returns the vm_id if the action was successfully sent to the VIM"""
1890
1891 self.logger.debug("Received action for vm {} and action dict {}".format(vm__vim_uuid, action_dict))
1892 if vm__vim_uuid is None or action_dict is None:
bayramovbd6160f2016-09-28 04:12:05 +04001893 raise vimconn.vimconnException("Invalid request. VM id or action is None.")
bayramovef390722016-09-27 03:34:46 -07001894
1895 vca = self.connect()
1896 if not vca:
1897 raise vimconn.vimconnConnectionException("self.connect() is failed.")
1898
1899 vdc = vca.get_vdc(self.tenant_name)
1900 if vdc is None:
1901 return -1, "Failed to get a reference of VDC for a tenant {}".format(self.tenant_name)
1902
1903 vapp_name = self.get_namebyvappid(vca, vdc, vm__vim_uuid)
1904 if vapp_name is None:
1905 self.logger.debug("action_vminstance(): Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
bayramovbd6160f2016-09-28 04:12:05 +04001906 raise vimconn.vimconnException("Failed to get vm by given {} vm uuid".format(vm__vim_uuid))
bayramovef390722016-09-27 03:34:46 -07001907 else:
1908 self.logger.info("Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid))
1909
1910 try:
1911 the_vapp = vca.get_vapp(vdc, vapp_name)
1912 # TODO fix all status
1913 if "start" in action_dict:
bhangare985a1fd2017-01-31 01:53:21 -08001914 vm_info = the_vapp.get_vms_details()
1915 vm_status = vm_info[0]['status']
kasar3ac5dc42017-03-15 06:28:22 -07001916 self.logger.info("action_vminstance: Power on vApp: {}".format(vapp_name))
bhangare985a1fd2017-01-31 01:53:21 -08001917 if vm_status == "Suspended" or vm_status == "Powered off":
1918 power_on_task = the_vapp.poweron()
bhangare985a1fd2017-01-31 01:53:21 -08001919 result = vca.block_until_completed(power_on_task)
kasar3ac5dc42017-03-15 06:28:22 -07001920 self.instance_actions_result("start", result, vapp_name)
1921 elif "rebuild" in action_dict:
1922 self.logger.info("action_vminstance: Rebuild vApp: {}".format(vapp_name))
1923 rebuild_task = the_vapp.deploy(powerOn=True)
1924 result = vca.block_until_completed(rebuild_task)
1925 self.instance_actions_result("rebuild", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07001926 elif "pause" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07001927 self.logger.info("action_vminstance: pause vApp: {}".format(vapp_name))
1928 pause_task = the_vapp.undeploy(action='suspend')
1929 result = vca.block_until_completed(pause_task)
1930 self.instance_actions_result("pause", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07001931 elif "resume" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07001932 self.logger.info("action_vminstance: resume vApp: {}".format(vapp_name))
1933 power_task = the_vapp.poweron()
1934 result = vca.block_until_completed(power_task)
1935 self.instance_actions_result("resume", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07001936 elif "shutoff" in action_dict or "shutdown" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07001937 action_name , value = action_dict.items()[0]
1938 self.logger.info("action_vminstance: {} vApp: {}".format(action_name, vapp_name))
bhangare985a1fd2017-01-31 01:53:21 -08001939 power_off_task = the_vapp.undeploy(action='powerOff')
kasar3ac5dc42017-03-15 06:28:22 -07001940 result = vca.block_until_completed(power_off_task)
1941 if action_name == "shutdown":
1942 self.instance_actions_result("shutdown", result, vapp_name)
bhangare985a1fd2017-01-31 01:53:21 -08001943 else:
kasar3ac5dc42017-03-15 06:28:22 -07001944 self.instance_actions_result("shutoff", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07001945 elif "forceOff" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07001946 result = the_vapp.undeploy(action='force')
1947 self.instance_actions_result("forceOff", result, vapp_name)
1948 elif "reboot" in action_dict:
1949 self.logger.info("action_vminstance: reboot vApp: {}".format(vapp_name))
1950 reboot_task = the_vapp.reboot()
bayramovef390722016-09-27 03:34:46 -07001951 else:
kasar3ac5dc42017-03-15 06:28:22 -07001952 raise vimconn.vimconnException("action_vminstance: Invalid action {} or action is None.".format(action_dict))
1953 return vm__vim_uuid
bhangarebfdca492017-03-11 01:32:46 -08001954 except Exception as exp :
1955 self.logger.debug("action_vminstance: Failed with Exception {}".format(exp))
1956 raise vimconn.vimconnException("action_vminstance: Failed with Exception {}".format(exp))
bayramovef390722016-09-27 03:34:46 -07001957
kasar3ac5dc42017-03-15 06:28:22 -07001958 def instance_actions_result(self, action, result, vapp_name):
1959 if result:
1960 self.logger.info("action_vminstance: Sucessfully {} the vApp: {}".format(action, vapp_name))
1961 else:
1962 self.logger.error("action_vminstance: Failed to {} vApp: {}".format(action, vapp_name))
1963
bayramovef390722016-09-27 03:34:46 -07001964 def get_vminstance_console(self, vm_id, console_type="vnc"):
1965 """
bayramov325fa1c2016-09-08 01:42:46 -07001966 Get a console for the virtual machine
1967 Params:
1968 vm_id: uuid of the VM
1969 console_type, can be:
bayramovef390722016-09-27 03:34:46 -07001970 "novnc" (by default), "xvpvnc" for VNC types,
bayramov325fa1c2016-09-08 01:42:46 -07001971 "rdp-html5" for RDP types, "spice-html5" for SPICE types
1972 Returns dict with the console parameters:
1973 protocol: ssh, ftp, http, https, ...
bayramovef390722016-09-27 03:34:46 -07001974 server: usually ip address
1975 port: the http, ssh, ... port
1976 suffix: extra text, e.g. the http path and query string
1977 """
bayramovbd6160f2016-09-28 04:12:05 +04001978 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001979
bayramovef390722016-09-27 03:34:46 -07001980 # NOT USED METHODS in current version
bayramov325fa1c2016-09-08 01:42:46 -07001981
1982 def host_vim2gui(self, host, server_dict):
bayramov5761ad12016-10-04 09:00:30 +04001983 """Transform host dictionary from VIM format to GUI format,
bayramov325fa1c2016-09-08 01:42:46 -07001984 and append to the server_dict
bayramov5761ad12016-10-04 09:00:30 +04001985 """
bayramovbd6160f2016-09-28 04:12:05 +04001986 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001987
1988 def get_hosts_info(self):
bayramov5761ad12016-10-04 09:00:30 +04001989 """Get the information of deployed hosts
1990 Returns the hosts content"""
bayramovbd6160f2016-09-28 04:12:05 +04001991 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001992
1993 def get_hosts(self, vim_tenant):
bayramov5761ad12016-10-04 09:00:30 +04001994 """Get the hosts and deployed instances
1995 Returns the hosts content"""
bayramovbd6160f2016-09-28 04:12:05 +04001996 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07001997
1998 def get_processor_rankings(self):
bayramov5761ad12016-10-04 09:00:30 +04001999 """Get the processor rankings in the VIM database"""
bayramovbd6160f2016-09-28 04:12:05 +04002000 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07002001
2002 def new_host(self, host_data):
bayramov5761ad12016-10-04 09:00:30 +04002003 """Adds a new host to VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07002004 '''Returns status code of the VIM response'''
bayramovbd6160f2016-09-28 04:12:05 +04002005 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07002006
2007 def new_external_port(self, port_data):
bayramov5761ad12016-10-04 09:00:30 +04002008 """Adds a external port to VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07002009 '''Returns the port identifier'''
bayramovbd6160f2016-09-28 04:12:05 +04002010 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07002011
bayramovef390722016-09-27 03:34:46 -07002012 def new_external_network(self, net_name, net_type):
bayramov5761ad12016-10-04 09:00:30 +04002013 """Adds a external network to VIM (shared)"""
bayramov325fa1c2016-09-08 01:42:46 -07002014 '''Returns the network identifier'''
bayramovbd6160f2016-09-28 04:12:05 +04002015 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07002016
2017 def connect_port_network(self, port_id, network_id, admin=False):
bayramov5761ad12016-10-04 09:00:30 +04002018 """Connects a external port to a network"""
bayramov325fa1c2016-09-08 01:42:46 -07002019 '''Returns status code of the VIM response'''
bayramovbd6160f2016-09-28 04:12:05 +04002020 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07002021
2022 def new_vminstancefromJSON(self, vm_data):
bayramov5761ad12016-10-04 09:00:30 +04002023 """Adds a VM instance to VIM"""
bayramov325fa1c2016-09-08 01:42:46 -07002024 '''Returns the instance identifier'''
bayramovbd6160f2016-09-28 04:12:05 +04002025 raise vimconn.vimconnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07002026
kate15f1c382016-12-15 01:12:40 -08002027 def get_network_name_by_id(self, network_uuid=None):
bayramovef390722016-09-27 03:34:46 -07002028 """Method gets vcloud director network named based on supplied uuid.
2029
2030 Args:
kate15f1c382016-12-15 01:12:40 -08002031 network_uuid: network_id
bayramovef390722016-09-27 03:34:46 -07002032
2033 Returns:
2034 The return network name.
2035 """
2036
2037 vca = self.connect()
2038 if not vca:
kate15f1c382016-12-15 01:12:40 -08002039 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramovef390722016-09-27 03:34:46 -07002040
kate15f1c382016-12-15 01:12:40 -08002041 if not network_uuid:
bayramovef390722016-09-27 03:34:46 -07002042 return None
2043
2044 try:
kate15f1c382016-12-15 01:12:40 -08002045 org_dict = self.get_org(self.org_uuid)
2046 if 'networks' in org_dict:
2047 org_network_dict = org_dict['networks']
2048 for net_uuid in org_network_dict:
2049 if net_uuid == network_uuid:
2050 return org_network_dict[net_uuid]
bayramovef390722016-09-27 03:34:46 -07002051 except:
2052 self.logger.debug("Exception in get_network_name_by_id")
2053 self.logger.debug(traceback.format_exc())
2054
2055 return None
2056
bhangare2c855072016-12-27 01:41:28 -08002057 def get_network_id_by_name(self, network_name=None):
2058 """Method gets vcloud director network uuid based on supplied name.
2059
2060 Args:
2061 network_name: network_name
2062 Returns:
2063 The return network uuid.
2064 network_uuid: network_id
2065 """
2066
2067 vca = self.connect()
2068 if not vca:
2069 raise vimconn.vimconnConnectionException("self.connect() is failed.")
2070
2071 if not network_name:
2072 self.logger.debug("get_network_id_by_name() : Network name is empty")
2073 return None
2074
2075 try:
2076 org_dict = self.get_org(self.org_uuid)
2077 if org_dict and 'networks' in org_dict:
2078 org_network_dict = org_dict['networks']
2079 for net_uuid,net_name in org_network_dict.iteritems():
2080 if net_name == network_name:
2081 return net_uuid
2082
2083 except KeyError as exp:
2084 self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
2085
2086 return None
2087
bayramovef390722016-09-27 03:34:46 -07002088 def list_org_action(self):
2089 """
2090 Method leverages vCloud director and query for available organization for particular user
2091
2092 Args:
2093 vca - is active VCA connection.
2094 vdc_name - is a vdc name that will be used to query vms action
2095
2096 Returns:
2097 The return XML respond
2098 """
2099
2100 vca = self.connect()
2101 if not vca:
2102 raise vimconn.vimconnConnectionException("self.connect() is failed")
2103
2104 url_list = [vca.host, '/api/org']
2105 vm_list_rest_call = ''.join(url_list)
2106
2107 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2108 response = Http.get(url=vm_list_rest_call,
2109 headers=vca.vcloud_session.get_vcloud_headers(),
2110 verify=vca.verify,
2111 logger=vca.logger)
2112 if response.status_code == requests.codes.ok:
2113 return response.content
2114
2115 return None
2116
2117 def get_org_action(self, org_uuid=None):
2118 """
2119 Method leverages vCloud director and retrieve available object fdr organization.
2120
2121 Args:
2122 vca - is active VCA connection.
2123 vdc_name - is a vdc name that will be used to query vms action
2124
2125 Returns:
2126 The return XML respond
2127 """
2128
2129 vca = self.connect()
2130 if not vca:
2131 raise vimconn.vimconnConnectionException("self.connect() is failed")
2132
2133 if org_uuid is None:
2134 return None
2135
2136 url_list = [vca.host, '/api/org/', org_uuid]
2137 vm_list_rest_call = ''.join(url_list)
2138
2139 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2140 response = Http.get(url=vm_list_rest_call,
2141 headers=vca.vcloud_session.get_vcloud_headers(),
2142 verify=vca.verify,
2143 logger=vca.logger)
2144 if response.status_code == requests.codes.ok:
2145 return response.content
2146
2147 return None
2148
2149 def get_org(self, org_uuid=None):
2150 """
2151 Method retrieves available organization in vCloud Director
2152
2153 Args:
bayramovb6ffe792016-09-28 11:50:56 +04002154 org_uuid - is a organization uuid.
bayramovef390722016-09-27 03:34:46 -07002155
2156 Returns:
bayramovb6ffe792016-09-28 11:50:56 +04002157 The return dictionary with following key
2158 "network" - for network list under the org
2159 "catalogs" - for network list under the org
2160 "vdcs" - for vdc list under org
bayramovef390722016-09-27 03:34:46 -07002161 """
2162
2163 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07002164 vca = self.connect()
2165 if not vca:
2166 raise vimconn.vimconnConnectionException("self.connect() is failed")
2167
2168 if org_uuid is None:
2169 return org_dict
2170
2171 content = self.get_org_action(org_uuid=org_uuid)
2172 try:
2173 vdc_list = {}
2174 network_list = {}
2175 catalog_list = {}
2176 vm_list_xmlroot = XmlElementTree.fromstring(content)
2177 for child in vm_list_xmlroot:
2178 if child.attrib['type'] == 'application/vnd.vmware.vcloud.vdc+xml':
2179 vdc_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
2180 org_dict['vdcs'] = vdc_list
2181 if child.attrib['type'] == 'application/vnd.vmware.vcloud.orgNetwork+xml':
2182 network_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
2183 org_dict['networks'] = network_list
2184 if child.attrib['type'] == 'application/vnd.vmware.vcloud.catalog+xml':
2185 catalog_list[child.attrib['href'].split("/")[-1:][0]] = child.attrib['name']
2186 org_dict['catalogs'] = catalog_list
2187 except:
2188 pass
2189
2190 return org_dict
2191
2192 def get_org_list(self):
2193 """
2194 Method retrieves available organization in vCloud Director
2195
2196 Args:
2197 vca - is active VCA connection.
2198
2199 Returns:
2200 The return dictionary and key for each entry VDC UUID
2201 """
2202
2203 org_dict = {}
2204 vca = self.connect()
2205 if not vca:
2206 raise vimconn.vimconnConnectionException("self.connect() is failed")
2207
2208 content = self.list_org_action()
2209 try:
2210 vm_list_xmlroot = XmlElementTree.fromstring(content)
2211 for vm_xml in vm_list_xmlroot:
2212 if vm_xml.tag.split("}")[1] == 'Org':
2213 org_uuid = vm_xml.attrib['href'].split('/')[-1:]
2214 org_dict[org_uuid[0]] = vm_xml.attrib['name']
2215 except:
2216 pass
2217
2218 return org_dict
2219
2220 def vms_view_action(self, vdc_name=None):
2221 """ Method leverages vCloud director vms query call
2222
2223 Args:
2224 vca - is active VCA connection.
2225 vdc_name - is a vdc name that will be used to query vms action
2226
2227 Returns:
2228 The return XML respond
2229 """
2230 vca = self.connect()
2231 if vdc_name is None:
2232 return None
2233
2234 url_list = [vca.host, '/api/vms/query']
2235 vm_list_rest_call = ''.join(url_list)
2236
2237 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2238 refs = filter(lambda ref: ref.name == vdc_name and ref.type_ == 'application/vnd.vmware.vcloud.vdc+xml',
2239 vca.vcloud_session.organization.Link)
2240 if len(refs) == 1:
2241 response = Http.get(url=vm_list_rest_call,
2242 headers=vca.vcloud_session.get_vcloud_headers(),
2243 verify=vca.verify,
2244 logger=vca.logger)
2245 if response.status_code == requests.codes.ok:
2246 return response.content
2247
2248 return None
2249
2250 def get_vapp_list(self, vdc_name=None):
2251 """
2252 Method retrieves vApp list deployed vCloud director and returns a dictionary
2253 contains a list of all vapp deployed for queried VDC.
2254 The key for a dictionary is vApp UUID
2255
2256
2257 Args:
2258 vca - is active VCA connection.
2259 vdc_name - is a vdc name that will be used to query vms action
2260
2261 Returns:
2262 The return dictionary and key for each entry vapp UUID
2263 """
2264
2265 vapp_dict = {}
2266 if vdc_name is None:
2267 return vapp_dict
2268
2269 content = self.vms_view_action(vdc_name=vdc_name)
2270 try:
2271 vm_list_xmlroot = XmlElementTree.fromstring(content)
2272 for vm_xml in vm_list_xmlroot:
2273 if vm_xml.tag.split("}")[1] == 'VMRecord':
2274 if vm_xml.attrib['isVAppTemplate'] == 'true':
2275 rawuuid = vm_xml.attrib['container'].split('/')[-1:]
2276 if 'vappTemplate-' in rawuuid[0]:
2277 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
2278 # vm and use raw UUID as key
2279 vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
2280 except:
2281 pass
2282
2283 return vapp_dict
2284
2285 def get_vm_list(self, vdc_name=None):
2286 """
2287 Method retrieves VM's list deployed vCloud director. It returns a dictionary
2288 contains a list of all VM's deployed for queried VDC.
2289 The key for a dictionary is VM UUID
2290
2291
2292 Args:
2293 vca - is active VCA connection.
2294 vdc_name - is a vdc name that will be used to query vms action
2295
2296 Returns:
2297 The return dictionary and key for each entry vapp UUID
2298 """
2299 vm_dict = {}
2300
2301 if vdc_name is None:
2302 return vm_dict
2303
2304 content = self.vms_view_action(vdc_name=vdc_name)
2305 try:
2306 vm_list_xmlroot = XmlElementTree.fromstring(content)
2307 for vm_xml in vm_list_xmlroot:
2308 if vm_xml.tag.split("}")[1] == 'VMRecord':
2309 if vm_xml.attrib['isVAppTemplate'] == 'false':
2310 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
2311 if 'vm-' in rawuuid[0]:
2312 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
2313 # vm and use raw UUID as key
2314 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
2315 except:
2316 pass
2317
2318 return vm_dict
2319
2320 def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
2321 """
bayramovb6ffe792016-09-28 11:50:56 +04002322 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
bayramovef390722016-09-27 03:34:46 -07002323 contains a list of all VM's deployed for queried VDC.
2324 The key for a dictionary is VM UUID
2325
2326
2327 Args:
2328 vca - is active VCA connection.
2329 vdc_name - is a vdc name that will be used to query vms action
2330
2331 Returns:
2332 The return dictionary and key for each entry vapp UUID
2333 """
2334 vm_dict = {}
2335 vca = self.connect()
2336 if not vca:
2337 raise vimconn.vimconnConnectionException("self.connect() is failed")
2338
2339 if vdc_name is None:
2340 return vm_dict
2341
2342 content = self.vms_view_action(vdc_name=vdc_name)
2343 try:
2344 vm_list_xmlroot = XmlElementTree.fromstring(content)
2345 for vm_xml in vm_list_xmlroot:
bayramovb6ffe792016-09-28 11:50:56 +04002346 if vm_xml.tag.split("}")[1] == 'VMRecord' and vm_xml.attrib['isVAppTemplate'] == 'false':
2347 # lookup done by UUID
bayramovef390722016-09-27 03:34:46 -07002348 if isuuid:
bayramovef390722016-09-27 03:34:46 -07002349 if vapp_name in vm_xml.attrib['container']:
2350 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
2351 if 'vm-' in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07002352 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
bayramovb6ffe792016-09-28 11:50:56 +04002353 break
2354 # lookup done by Name
2355 else:
2356 if vapp_name in vm_xml.attrib['name']:
2357 rawuuid = vm_xml.attrib['href'].split('/')[-1:]
2358 if 'vm-' in rawuuid[0]:
2359 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
2360 break
bayramovef390722016-09-27 03:34:46 -07002361 except:
2362 pass
2363
2364 return vm_dict
2365
2366 def get_network_action(self, network_uuid=None):
2367 """
2368 Method leverages vCloud director and query network based on network uuid
2369
2370 Args:
2371 vca - is active VCA connection.
2372 network_uuid - is a network uuid
2373
2374 Returns:
2375 The return XML respond
2376 """
2377
2378 vca = self.connect()
2379 if not vca:
2380 raise vimconn.vimconnConnectionException("self.connect() is failed")
2381
2382 if network_uuid is None:
2383 return None
2384
2385 url_list = [vca.host, '/api/network/', network_uuid]
2386 vm_list_rest_call = ''.join(url_list)
2387
2388 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2389 response = Http.get(url=vm_list_rest_call,
2390 headers=vca.vcloud_session.get_vcloud_headers(),
2391 verify=vca.verify,
2392 logger=vca.logger)
2393 if response.status_code == requests.codes.ok:
2394 return response.content
2395
2396 return None
2397
2398 def get_vcd_network(self, network_uuid=None):
2399 """
2400 Method retrieves available network from vCloud Director
2401
2402 Args:
2403 network_uuid - is VCD network UUID
2404
2405 Each element serialized as key : value pair
2406
2407 Following keys available for access. network_configuration['Gateway'}
2408 <Configuration>
2409 <IpScopes>
2410 <IpScope>
2411 <IsInherited>true</IsInherited>
2412 <Gateway>172.16.252.100</Gateway>
2413 <Netmask>255.255.255.0</Netmask>
2414 <Dns1>172.16.254.201</Dns1>
2415 <Dns2>172.16.254.202</Dns2>
2416 <DnsSuffix>vmwarelab.edu</DnsSuffix>
2417 <IsEnabled>true</IsEnabled>
2418 <IpRanges>
2419 <IpRange>
2420 <StartAddress>172.16.252.1</StartAddress>
2421 <EndAddress>172.16.252.99</EndAddress>
2422 </IpRange>
2423 </IpRanges>
2424 </IpScope>
2425 </IpScopes>
2426 <FenceMode>bridged</FenceMode>
2427
2428 Returns:
2429 The return dictionary and key for each entry vapp UUID
2430 """
2431
2432 network_configuration = {}
2433 if network_uuid is None:
2434 return network_uuid
2435
bayramovef390722016-09-27 03:34:46 -07002436 try:
bhangarebfdca492017-03-11 01:32:46 -08002437 content = self.get_network_action(network_uuid=network_uuid)
bayramovef390722016-09-27 03:34:46 -07002438 vm_list_xmlroot = XmlElementTree.fromstring(content)
2439
2440 network_configuration['status'] = vm_list_xmlroot.get("status")
2441 network_configuration['name'] = vm_list_xmlroot.get("name")
2442 network_configuration['uuid'] = vm_list_xmlroot.get("id").split(":")[3]
2443
2444 for child in vm_list_xmlroot:
2445 if child.tag.split("}")[1] == 'IsShared':
2446 network_configuration['isShared'] = child.text.strip()
2447 if child.tag.split("}")[1] == 'Configuration':
2448 for configuration in child.iter():
2449 tagKey = configuration.tag.split("}")[1].strip()
2450 if tagKey != "":
2451 network_configuration[tagKey] = configuration.text.strip()
2452 return network_configuration
bhangarebfdca492017-03-11 01:32:46 -08002453 except Exception as exp :
2454 self.logger.debug("get_vcd_network: Failed with Exception {}".format(exp))
2455 raise vimconn.vimconnException("get_vcd_network: Failed with Exception {}".format(exp))
bayramovef390722016-09-27 03:34:46 -07002456
2457 return network_configuration
2458
2459 def delete_network_action(self, network_uuid=None):
2460 """
2461 Method delete given network from vCloud director
2462
2463 Args:
2464 network_uuid - is a network uuid that client wish to delete
2465
2466 Returns:
2467 The return None or XML respond or false
2468 """
2469
2470 vca = self.connect_as_admin()
2471 if not vca:
2472 raise vimconn.vimconnConnectionException("self.connect() is failed")
2473 if network_uuid is None:
2474 return False
2475
2476 url_list = [vca.host, '/api/admin/network/', network_uuid]
2477 vm_list_rest_call = ''.join(url_list)
2478
2479 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2480 response = Http.delete(url=vm_list_rest_call,
2481 headers=vca.vcloud_session.get_vcloud_headers(),
2482 verify=vca.verify,
2483 logger=vca.logger)
2484
2485 if response.status_code == 202:
2486 return True
2487
2488 return False
2489
bhangare0e571a92017-01-12 04:02:23 -08002490 def create_network(self, network_name=None, net_type='bridge', parent_network_uuid=None,
2491 ip_profile=None, isshared='true'):
bayramovef390722016-09-27 03:34:46 -07002492 """
2493 Method create network in vCloud director
2494
2495 Args:
2496 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08002497 net_type - can be 'bridge','data','ptp','mgmt'.
2498 ip_profile is a dict containing the IP parameters of the network
2499 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07002500 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2501 It optional attribute. by default if no parent network indicate the first available will be used.
2502
2503 Returns:
2504 The return network uuid or return None
2505 """
2506
bayramov5761ad12016-10-04 09:00:30 +04002507 new_network_name = [network_name, '-', str(uuid.uuid4())]
2508 content = self.create_network_rest(network_name=''.join(new_network_name),
bhangare0e571a92017-01-12 04:02:23 -08002509 ip_profile=ip_profile,
2510 net_type=net_type,
bayramovef390722016-09-27 03:34:46 -07002511 parent_network_uuid=parent_network_uuid,
2512 isshared=isshared)
2513 if content is None:
2514 self.logger.debug("Failed create network {}.".format(network_name))
2515 return None
2516
2517 try:
2518 vm_list_xmlroot = XmlElementTree.fromstring(content)
2519 vcd_uuid = vm_list_xmlroot.get('id').split(":")
2520 if len(vcd_uuid) == 4:
bhangarebfdca492017-03-11 01:32:46 -08002521 self.logger.info("Created new network name: {} uuid: {}".format(network_name, vcd_uuid[3]))
bayramovef390722016-09-27 03:34:46 -07002522 return vcd_uuid[3]
2523 except:
2524 self.logger.debug("Failed create network {}".format(network_name))
2525 return None
2526
bhangare0e571a92017-01-12 04:02:23 -08002527 def create_network_rest(self, network_name=None, net_type='bridge', parent_network_uuid=None,
2528 ip_profile=None, isshared='true'):
bayramovef390722016-09-27 03:34:46 -07002529 """
2530 Method create network in vCloud director
2531
2532 Args:
2533 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08002534 net_type - can be 'bridge','data','ptp','mgmt'.
2535 ip_profile is a dict containing the IP parameters of the network
2536 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07002537 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2538 It optional attribute. by default if no parent network indicate the first available will be used.
2539
2540 Returns:
2541 The return network uuid or return None
2542 """
2543
2544 vca = self.connect_as_admin()
2545 if not vca:
bayramov5761ad12016-10-04 09:00:30 +04002546 raise vimconn.vimconnConnectionException("self.connect() is failed.")
bayramovef390722016-09-27 03:34:46 -07002547 if network_name is None:
2548 return None
2549
2550 url_list = [vca.host, '/api/admin/vdc/', self.tenant_id]
2551 vm_list_rest_call = ''.join(url_list)
2552 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2553 response = Http.get(url=vm_list_rest_call,
2554 headers=vca.vcloud_session.get_vcloud_headers(),
2555 verify=vca.verify,
2556 logger=vca.logger)
2557
2558 provider_network = None
2559 available_networks = None
2560 add_vdc_rest_url = None
2561
2562 if response.status_code != requests.codes.ok:
2563 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2564 response.status_code))
2565 return None
2566 else:
2567 try:
2568 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2569 for child in vm_list_xmlroot:
2570 if child.tag.split("}")[1] == 'ProviderVdcReference':
2571 provider_network = child.attrib.get('href')
2572 # application/vnd.vmware.admin.providervdc+xml
2573 if child.tag.split("}")[1] == 'Link':
2574 if child.attrib.get('type') == 'application/vnd.vmware.vcloud.orgVdcNetwork+xml' \
2575 and child.attrib.get('rel') == 'add':
2576 add_vdc_rest_url = child.attrib.get('href')
2577 except:
2578 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2579 self.logger.debug("Respond body {}".format(response.content))
2580 return None
2581
2582 # find pvdc provided available network
2583 response = Http.get(url=provider_network,
2584 headers=vca.vcloud_session.get_vcloud_headers(),
2585 verify=vca.verify,
2586 logger=vca.logger)
2587 if response.status_code != requests.codes.ok:
2588 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2589 response.status_code))
2590 return None
2591
2592 # available_networks.split("/")[-1]
2593
2594 if parent_network_uuid is None:
2595 try:
2596 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2597 for child in vm_list_xmlroot.iter():
2598 if child.tag.split("}")[1] == 'AvailableNetworks':
2599 for networks in child.iter():
2600 # application/vnd.vmware.admin.network+xml
2601 if networks.attrib.get('href') is not None:
2602 available_networks = networks.attrib.get('href')
2603 break
2604 except:
2605 return None
2606
bhangarebfdca492017-03-11 01:32:46 -08002607 try:
2608 #Configure IP profile of the network
2609 ip_profile = ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
bhangare0e571a92017-01-12 04:02:23 -08002610
kasarde691232017-03-25 03:37:31 -07002611 if 'subnet_address' not in ip_profile or ip_profile['subnet_address'] is None:
2612 subnet_rand = random.randint(0, 255)
2613 ip_base = "192.168.{}.".format(subnet_rand)
2614 ip_profile['subnet_address'] = ip_base + "0/24"
2615 else:
2616 ip_base = ip_profile['subnet_address'].rsplit('.',1)[0] + '.'
2617
bhangarebfdca492017-03-11 01:32:46 -08002618 if 'gateway_address' not in ip_profile or ip_profile['gateway_address'] is None:
kasarde691232017-03-25 03:37:31 -07002619 ip_profile['gateway_address']=ip_base + "1"
bhangarebfdca492017-03-11 01:32:46 -08002620 if 'dhcp_count' not in ip_profile or ip_profile['dhcp_count'] is None:
2621 ip_profile['dhcp_count']=DEFAULT_IP_PROFILE['dhcp_count']
bhangarebfdca492017-03-11 01:32:46 -08002622 if 'dhcp_enabled' not in ip_profile or ip_profile['dhcp_enabled'] is None:
2623 ip_profile['dhcp_enabled']=DEFAULT_IP_PROFILE['dhcp_enabled']
2624 if 'dhcp_start_address' not in ip_profile or ip_profile['dhcp_start_address'] is None:
kasarde691232017-03-25 03:37:31 -07002625 ip_profile['dhcp_start_address']=ip_base + "3"
bhangarebfdca492017-03-11 01:32:46 -08002626 if 'ip_version' not in ip_profile or ip_profile['ip_version'] is None:
2627 ip_profile['ip_version']=DEFAULT_IP_PROFILE['ip_version']
2628 if 'dns_address' not in ip_profile or ip_profile['dns_address'] is None:
kasarde691232017-03-25 03:37:31 -07002629 ip_profile['dns_address']=ip_base + "2"
bhangare0e571a92017-01-12 04:02:23 -08002630
bhangarebfdca492017-03-11 01:32:46 -08002631 gateway_address=ip_profile['gateway_address']
2632 dhcp_count=int(ip_profile['dhcp_count'])
2633 subnet_address=self.convert_cidr_to_netmask(ip_profile['subnet_address'])
bhangare0e571a92017-01-12 04:02:23 -08002634
bhangarebfdca492017-03-11 01:32:46 -08002635 if ip_profile['dhcp_enabled']==True:
2636 dhcp_enabled='true'
2637 else:
2638 dhcp_enabled='false'
2639 dhcp_start_address=ip_profile['dhcp_start_address']
bhangare0e571a92017-01-12 04:02:23 -08002640
bhangarebfdca492017-03-11 01:32:46 -08002641 #derive dhcp_end_address from dhcp_start_address & dhcp_count
2642 end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
2643 end_ip_int += dhcp_count - 1
2644 dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
2645
2646 ip_version=ip_profile['ip_version']
2647 dns_address=ip_profile['dns_address']
2648 except KeyError as exp:
2649 self.logger.debug("Create Network REST: Key error {}".format(exp))
2650 raise vimconn.vimconnException("Create Network REST: Key error{}".format(exp))
bhangare0e571a92017-01-12 04:02:23 -08002651
bayramovef390722016-09-27 03:34:46 -07002652 # either use client provided UUID or search for a first available
2653 # if both are not defined we return none
2654 if parent_network_uuid is not None:
2655 url_list = [vca.host, '/api/admin/network/', parent_network_uuid]
2656 add_vdc_rest_url = ''.join(url_list)
2657
bhangare0e571a92017-01-12 04:02:23 -08002658 if net_type=='ptp':
2659 fence_mode="isolated"
2660 isshared='false'
2661 is_inherited='false'
2662 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2663 <Description>Openmano created</Description>
2664 <Configuration>
2665 <IpScopes>
2666 <IpScope>
2667 <IsInherited>{1:s}</IsInherited>
2668 <Gateway>{2:s}</Gateway>
2669 <Netmask>{3:s}</Netmask>
2670 <Dns1>{4:s}</Dns1>
2671 <IsEnabled>{5:s}</IsEnabled>
2672 <IpRanges>
2673 <IpRange>
2674 <StartAddress>{6:s}</StartAddress>
2675 <EndAddress>{7:s}</EndAddress>
2676 </IpRange>
2677 </IpRanges>
2678 </IpScope>
2679 </IpScopes>
2680 <FenceMode>{8:s}</FenceMode>
2681 </Configuration>
2682 <IsShared>{9:s}</IsShared>
2683 </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
2684 subnet_address, dns_address, dhcp_enabled,
2685 dhcp_start_address, dhcp_end_address, fence_mode, isshared)
2686
2687 else:
2688 fence_mode="bridged"
2689 is_inherited='false'
2690 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2691 <Description>Openmano created</Description>
2692 <Configuration>
2693 <IpScopes>
2694 <IpScope>
2695 <IsInherited>{1:s}</IsInherited>
2696 <Gateway>{2:s}</Gateway>
2697 <Netmask>{3:s}</Netmask>
2698 <Dns1>{4:s}</Dns1>
2699 <IsEnabled>{5:s}</IsEnabled>
2700 <IpRanges>
2701 <IpRange>
2702 <StartAddress>{6:s}</StartAddress>
2703 <EndAddress>{7:s}</EndAddress>
2704 </IpRange>
2705 </IpRanges>
2706 </IpScope>
2707 </IpScopes>
2708 <ParentNetwork href="{8:s}"/>
2709 <FenceMode>{9:s}</FenceMode>
2710 </Configuration>
2711 <IsShared>{10:s}</IsShared>
2712 </OrgVdcNetwork> """.format(escape(network_name), is_inherited, gateway_address,
2713 subnet_address, dns_address, dhcp_enabled,
2714 dhcp_start_address, dhcp_end_address, available_networks,
2715 fence_mode, isshared)
bayramovef390722016-09-27 03:34:46 -07002716
2717 headers = vca.vcloud_session.get_vcloud_headers()
2718 headers['Content-Type'] = 'application/vnd.vmware.vcloud.orgVdcNetwork+xml'
bhangare0e571a92017-01-12 04:02:23 -08002719 try:
2720 response = Http.post(url=add_vdc_rest_url,
2721 headers=headers,
2722 data=data,
2723 verify=vca.verify,
2724 logger=vca.logger)
bayramovef390722016-09-27 03:34:46 -07002725
bhangare0e571a92017-01-12 04:02:23 -08002726 if response.status_code != 201:
bhangarebfdca492017-03-11 01:32:46 -08002727 self.logger.debug("Create Network POST REST API call failed. Return status code {}, Response content: {}"
2728 .format(response.status_code,response.content))
bhangare0e571a92017-01-12 04:02:23 -08002729 else:
2730 network = networkType.parseString(response.content, True)
2731 create_nw_task = network.get_Tasks().get_Task()[0]
2732
2733 # if we all ok we respond with content after network creation completes
2734 # otherwise by default return None
2735 if create_nw_task is not None:
bhangarebfdca492017-03-11 01:32:46 -08002736 self.logger.debug("Create Network REST : Waiting for Network creation complete")
bhangare0e571a92017-01-12 04:02:23 -08002737 status = vca.block_until_completed(create_nw_task)
2738 if status:
2739 return response.content
2740 else:
2741 self.logger.debug("create_network_rest task failed. Network Create response : {}"
2742 .format(response.content))
2743 except Exception as exp:
2744 self.logger.debug("create_network_rest : Exception : {} ".format(exp))
2745
2746 return None
2747
2748 def convert_cidr_to_netmask(self, cidr_ip=None):
2749 """
2750 Method sets convert CIDR netmask address to normal IP format
2751 Args:
2752 cidr_ip : CIDR IP address
2753 Returns:
2754 netmask : Converted netmask
2755 """
2756 if cidr_ip is not None:
2757 if '/' in cidr_ip:
2758 network, net_bits = cidr_ip.split('/')
2759 netmask = socket.inet_ntoa(struct.pack(">I", (0xffffffff << (32 - int(net_bits))) & 0xffffffff))
2760 else:
2761 netmask = cidr_ip
2762 return netmask
bayramovef390722016-09-27 03:34:46 -07002763 return None
2764
2765 def get_provider_rest(self, vca=None):
2766 """
2767 Method gets provider vdc view from vcloud director
2768
2769 Args:
2770 network_name - is network name to be created.
2771 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2772 It optional attribute. by default if no parent network indicate the first available will be used.
2773
2774 Returns:
2775 The return xml content of respond or None
2776 """
2777
2778 url_list = [vca.host, '/api/admin']
2779 response = Http.get(url=''.join(url_list),
2780 headers=vca.vcloud_session.get_vcloud_headers(),
2781 verify=vca.verify,
2782 logger=vca.logger)
2783
2784 if response.status_code == requests.codes.ok:
2785 return response.content
2786 return None
2787
2788 def create_vdc(self, vdc_name=None):
2789
2790 vdc_dict = {}
2791
2792 xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
2793 if xml_content is not None:
bayramovef390722016-09-27 03:34:46 -07002794 try:
2795 task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
2796 for child in task_resp_xmlroot:
2797 if child.tag.split("}")[1] == 'Owner':
2798 vdc_id = child.attrib.get('href').split("/")[-1]
2799 vdc_dict[vdc_id] = task_resp_xmlroot.get('href')
2800 return vdc_dict
2801 except:
2802 self.logger.debug("Respond body {}".format(xml_content))
2803
2804 return None
2805
2806 def create_vdc_from_tmpl_rest(self, vdc_name=None):
2807 """
2808 Method create vdc in vCloud director based on VDC template.
2809 it uses pre-defined template that must be named openmano
2810
2811 Args:
2812 vdc_name - name of a new vdc.
2813
2814 Returns:
2815 The return xml content of respond or None
2816 """
2817
2818 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07002819 vca = self.connect()
2820 if not vca:
2821 raise vimconn.vimconnConnectionException("self.connect() is failed")
2822 if vdc_name is None:
2823 return None
2824
2825 url_list = [vca.host, '/api/vdcTemplates']
2826 vm_list_rest_call = ''.join(url_list)
2827 response = Http.get(url=vm_list_rest_call,
2828 headers=vca.vcloud_session.get_vcloud_headers(),
2829 verify=vca.verify,
2830 logger=vca.logger)
2831
2832 # container url to a template
2833 vdc_template_ref = None
2834 try:
2835 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2836 for child in vm_list_xmlroot:
2837 # application/vnd.vmware.admin.providervdc+xml
2838 # we need find a template from witch we instantiate VDC
2839 if child.tag.split("}")[1] == 'VdcTemplate':
2840 if child.attrib.get('type') == 'application/vnd.vmware.admin.vdcTemplate+xml' and child.attrib.get(
2841 'name') == 'openmano':
2842 vdc_template_ref = child.attrib.get('href')
2843 except:
2844 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2845 self.logger.debug("Respond body {}".format(response.content))
2846 return None
2847
2848 # if we didn't found required pre defined template we return None
2849 if vdc_template_ref is None:
2850 return None
2851
2852 try:
2853 # instantiate vdc
2854 url_list = [vca.host, '/api/org/', self.org_uuid, '/action/instantiate']
2855 vm_list_rest_call = ''.join(url_list)
2856 data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
2857 <Source href="{1:s}"></Source>
2858 <Description>opnemano</Description>
2859 </InstantiateVdcTemplateParams>""".format(vdc_name, vdc_template_ref)
2860 headers = vca.vcloud_session.get_vcloud_headers()
2861 headers['Content-Type'] = 'application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml'
2862 response = Http.post(url=vm_list_rest_call, headers=headers, data=data, verify=vca.verify,
2863 logger=vca.logger)
2864 # if we all ok we respond with content otherwise by default None
2865 if response.status_code >= 200 and response.status_code < 300:
2866 return response.content
2867 return None
2868 except:
2869 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2870 self.logger.debug("Respond body {}".format(response.content))
2871
2872 return None
2873
2874 def create_vdc_rest(self, vdc_name=None):
2875 """
2876 Method create network in vCloud director
2877
2878 Args:
2879 network_name - is network name to be created.
2880 parent_network_uuid - is parent provider vdc network that will be used for mapping.
2881 It optional attribute. by default if no parent network indicate the first available will be used.
2882
2883 Returns:
2884 The return network uuid or return None
2885 """
2886
2887 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07002888
2889 vca = self.connect_as_admin()
2890 if not vca:
2891 raise vimconn.vimconnConnectionException("self.connect() is failed")
2892 if vdc_name is None:
2893 return None
2894
2895 url_list = [vca.host, '/api/admin/org/', self.org_uuid]
2896 vm_list_rest_call = ''.join(url_list)
2897 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
2898 response = Http.get(url=vm_list_rest_call,
2899 headers=vca.vcloud_session.get_vcloud_headers(),
2900 verify=vca.verify,
2901 logger=vca.logger)
2902
2903 provider_vdc_ref = None
2904 add_vdc_rest_url = None
2905 available_networks = None
2906
2907 if response.status_code != requests.codes.ok:
2908 self.logger.debug("REST API call {} failed. Return status code {}".format(vm_list_rest_call,
2909 response.status_code))
2910 return None
2911 else:
2912 try:
2913 vm_list_xmlroot = XmlElementTree.fromstring(response.content)
2914 for child in vm_list_xmlroot:
2915 # application/vnd.vmware.admin.providervdc+xml
2916 if child.tag.split("}")[1] == 'Link':
2917 if child.attrib.get('type') == 'application/vnd.vmware.admin.createVdcParams+xml' \
2918 and child.attrib.get('rel') == 'add':
2919 add_vdc_rest_url = child.attrib.get('href')
2920 except:
2921 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2922 self.logger.debug("Respond body {}".format(response.content))
2923 return None
2924
2925 response = self.get_provider_rest(vca=vca)
bayramovef390722016-09-27 03:34:46 -07002926 try:
2927 vm_list_xmlroot = XmlElementTree.fromstring(response)
2928 for child in vm_list_xmlroot:
2929 if child.tag.split("}")[1] == 'ProviderVdcReferences':
2930 for sub_child in child:
2931 provider_vdc_ref = sub_child.attrib.get('href')
2932 except:
2933 self.logger.debug("Failed parse respond for rest api call {}".format(vm_list_rest_call))
2934 self.logger.debug("Respond body {}".format(response))
2935 return None
2936
bayramovef390722016-09-27 03:34:46 -07002937 if add_vdc_rest_url is not None and provider_vdc_ref is not None:
2938 data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
2939 <AllocationModel>ReservationPool</AllocationModel>
2940 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
2941 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
2942 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
2943 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
2944 <ProviderVdcReference
2945 name="Main Provider"
2946 href="{2:s}" />
2947 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(escape(vdc_name),
2948 escape(vdc_name),
2949 provider_vdc_ref)
2950
bayramovef390722016-09-27 03:34:46 -07002951 headers = vca.vcloud_session.get_vcloud_headers()
2952 headers['Content-Type'] = 'application/vnd.vmware.admin.createVdcParams+xml'
2953 response = Http.post(url=add_vdc_rest_url, headers=headers, data=data, verify=vca.verify,
2954 logger=vca.logger)
2955
bayramovef390722016-09-27 03:34:46 -07002956 # if we all ok we respond with content otherwise by default None
2957 if response.status_code == 201:
2958 return response.content
2959 return None
bayramovfe3f3c92016-10-04 07:53:41 +04002960
bhangarefda5f7c2017-01-12 23:50:34 -08002961 def get_vapp_details_rest(self, vapp_uuid=None, need_admin_access=False):
bayramovfe3f3c92016-10-04 07:53:41 +04002962 """
2963 Method retrieve vapp detail from vCloud director
2964
2965 Args:
2966 vapp_uuid - is vapp identifier.
2967
2968 Returns:
2969 The return network uuid or return None
2970 """
2971
2972 parsed_respond = {}
bhangarefda5f7c2017-01-12 23:50:34 -08002973 vca = None
bayramovfe3f3c92016-10-04 07:53:41 +04002974
bhangarefda5f7c2017-01-12 23:50:34 -08002975 if need_admin_access:
2976 vca = self.connect_as_admin()
2977 else:
2978 vca = self.connect()
2979
bayramovfe3f3c92016-10-04 07:53:41 +04002980 if not vca:
2981 raise vimconn.vimconnConnectionException("self.connect() is failed")
2982 if vapp_uuid is None:
2983 return None
2984
2985 url_list = [vca.host, '/api/vApp/vapp-', vapp_uuid]
2986 get_vapp_restcall = ''.join(url_list)
bhangarefda5f7c2017-01-12 23:50:34 -08002987
2988 if vca.vcloud_session and vca.vcloud_session.organization:
bayramovfe3f3c92016-10-04 07:53:41 +04002989 response = Http.get(url=get_vapp_restcall,
2990 headers=vca.vcloud_session.get_vcloud_headers(),
2991 verify=vca.verify,
2992 logger=vca.logger)
2993
2994 if response.status_code != requests.codes.ok:
2995 self.logger.debug("REST API call {} failed. Return status code {}".format(get_vapp_restcall,
2996 response.status_code))
2997 return parsed_respond
2998
2999 try:
3000 xmlroot_respond = XmlElementTree.fromstring(response.content)
3001 parsed_respond['ovfDescriptorUploaded'] = xmlroot_respond.attrib['ovfDescriptorUploaded']
3002
bhangarea92ae392017-01-12 22:30:29 -08003003 namespaces = {"vssd":"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" ,
3004 'ovf': 'http://schemas.dmtf.org/ovf/envelope/1',
3005 'vmw': 'http://www.vmware.com/schema/ovf',
3006 'vm': 'http://www.vmware.com/vcloud/v1.5',
3007 'rasd':"http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
3008 "vmext":"http://www.vmware.com/vcloud/extension/v1.5",
3009 "xmlns":"http://www.vmware.com/vcloud/v1.5"
3010 }
bayramovfe3f3c92016-10-04 07:53:41 +04003011
bhangarea92ae392017-01-12 22:30:29 -08003012 created_section = xmlroot_respond.find('vm:DateCreated', namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04003013 if created_section is not None:
3014 parsed_respond['created'] = created_section.text
3015
bhangarea92ae392017-01-12 22:30:29 -08003016 network_section = xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig', namespaces)
bayramov5761ad12016-10-04 09:00:30 +04003017 if network_section is not None and 'networkName' in network_section.attrib:
bayramovfe3f3c92016-10-04 07:53:41 +04003018 parsed_respond['networkname'] = network_section.attrib['networkName']
3019
3020 ipscopes_section = \
3021 xmlroot_respond.find('vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes',
bhangarea92ae392017-01-12 22:30:29 -08003022 namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04003023 if ipscopes_section is not None:
3024 for ipscope in ipscopes_section:
3025 for scope in ipscope:
3026 tag_key = scope.tag.split("}")[1]
3027 if tag_key == 'IpRanges':
3028 ip_ranges = scope.getchildren()
3029 for ipblock in ip_ranges:
3030 for block in ipblock:
3031 parsed_respond[block.tag.split("}")[1]] = block.text
3032 else:
3033 parsed_respond[tag_key] = scope.text
3034
3035 # parse children section for other attrib
bhangarea92ae392017-01-12 22:30:29 -08003036 children_section = xmlroot_respond.find('vm:Children/', namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04003037 if children_section is not None:
3038 parsed_respond['name'] = children_section.attrib['name']
bhangarea92ae392017-01-12 22:30:29 -08003039 parsed_respond['nestedHypervisorEnabled'] = children_section.attrib['nestedHypervisorEnabled'] \
3040 if "nestedHypervisorEnabled" in children_section.attrib else None
bayramovfe3f3c92016-10-04 07:53:41 +04003041 parsed_respond['deployed'] = children_section.attrib['deployed']
3042 parsed_respond['status'] = children_section.attrib['status']
3043 parsed_respond['vmuuid'] = children_section.attrib['id'].split(":")[-1]
bhangarea92ae392017-01-12 22:30:29 -08003044 network_adapter = children_section.find('vm:NetworkConnectionSection', namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04003045 nic_list = []
3046 for adapters in network_adapter:
3047 adapter_key = adapters.tag.split("}")[1]
3048 if adapter_key == 'PrimaryNetworkConnectionIndex':
3049 parsed_respond['primarynetwork'] = adapters.text
3050 if adapter_key == 'NetworkConnection':
3051 vnic = {}
bayramov5761ad12016-10-04 09:00:30 +04003052 if 'network' in adapters.attrib:
bayramovfe3f3c92016-10-04 07:53:41 +04003053 vnic['network'] = adapters.attrib['network']
3054 for adapter in adapters:
3055 setting_key = adapter.tag.split("}")[1]
3056 vnic[setting_key] = adapter.text
3057 nic_list.append(vnic)
3058
3059 for link in children_section:
bayramov5761ad12016-10-04 09:00:30 +04003060 if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
bayramovfe3f3c92016-10-04 07:53:41 +04003061 if link.attrib['rel'] == 'screen:acquireTicket':
3062 parsed_respond['acquireTicket'] = link.attrib
3063 if link.attrib['rel'] == 'screen:acquireMksTicket':
3064 parsed_respond['acquireMksTicket'] = link.attrib
3065
3066 parsed_respond['interfaces'] = nic_list
bhangarefda5f7c2017-01-12 23:50:34 -08003067 vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
3068 if vCloud_extension_section is not None:
3069 vm_vcenter_info = {}
3070 vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
3071 vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
3072 if vmext is not None:
3073 vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
bhangarefda5f7c2017-01-12 23:50:34 -08003074 parsed_respond["vm_vcenter_info"]= vm_vcenter_info
bayramovfe3f3c92016-10-04 07:53:41 +04003075
bhangarea92ae392017-01-12 22:30:29 -08003076 virtual_hardware_section = children_section.find('ovf:VirtualHardwareSection', namespaces)
3077 vm_virtual_hardware_info = {}
3078 if virtual_hardware_section is not None:
3079 for item in virtual_hardware_section.iterfind('ovf:Item',namespaces):
3080 if item.find("rasd:Description",namespaces).text == "Hard disk":
3081 disk_size = item.find("rasd:HostResource" ,namespaces
3082 ).attrib["{"+namespaces['vm']+"}capacity"]
3083
3084 vm_virtual_hardware_info["disk_size"]= disk_size
3085 break
3086
3087 for link in virtual_hardware_section:
3088 if link.tag.split("}")[1] == 'Link' and 'rel' in link.attrib:
3089 if link.attrib['rel'] == 'edit' and link.attrib['href'].endswith("/disks"):
3090 vm_virtual_hardware_info["disk_edit_href"] = link.attrib['href']
3091 break
3092
3093 parsed_respond["vm_virtual_hardware"]= vm_virtual_hardware_info
3094 except Exception as exp :
3095 self.logger.info("Error occurred calling rest api for getting vApp details {}".format(exp))
bayramovfe3f3c92016-10-04 07:53:41 +04003096 return parsed_respond
3097
bayramov5761ad12016-10-04 09:00:30 +04003098 def acuire_console(self, vm_uuid=None):
bayramovfe3f3c92016-10-04 07:53:41 +04003099
3100 vca = self.connect()
3101 if not vca:
3102 raise vimconn.vimconnConnectionException("self.connect() is failed")
3103 if vm_uuid is None:
3104 return None
3105
3106 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
bayramov5761ad12016-10-04 09:00:30 +04003107 vm_dict = self.get_vapp_details_rest(self, vapp_uuid=vm_uuid)
bayramovfe3f3c92016-10-04 07:53:41 +04003108 console_dict = vm_dict['acquireTicket']
3109 console_rest_call = console_dict['href']
3110
3111 response = Http.post(url=console_rest_call,
3112 headers=vca.vcloud_session.get_vcloud_headers(),
3113 verify=vca.verify,
3114 logger=vca.logger)
3115
bayramov5761ad12016-10-04 09:00:30 +04003116 if response.status_code == requests.codes.ok:
3117 return response.content
bayramovfe3f3c92016-10-04 07:53:41 +04003118
kate15f1c382016-12-15 01:12:40 -08003119 return None
kate13ab2c42016-12-23 01:34:24 -08003120
bhangarea92ae392017-01-12 22:30:29 -08003121 def modify_vm_disk(self, vapp_uuid, flavor_disk):
3122 """
3123 Method retrieve vm disk details
3124
3125 Args:
3126 vapp_uuid - is vapp identifier.
3127 flavor_disk - disk size as specified in VNFD (flavor)
3128
3129 Returns:
3130 The return network uuid or return None
3131 """
3132 status = None
3133 try:
3134 #Flavor disk is in GB convert it into MB
3135 flavor_disk = int(flavor_disk) * 1024
3136 vm_details = self.get_vapp_details_rest(vapp_uuid)
3137 if vm_details:
3138 vm_name = vm_details["name"]
3139 self.logger.info("VM: {} flavor_disk :{}".format(vm_name , flavor_disk))
3140
3141 if vm_details and "vm_virtual_hardware" in vm_details:
3142 vm_disk = int(vm_details["vm_virtual_hardware"]["disk_size"])
3143 disk_edit_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
3144
3145 self.logger.info("VM: {} VM_disk :{}".format(vm_name , vm_disk))
3146
3147 if flavor_disk > vm_disk:
3148 status = self.modify_vm_disk_rest(disk_edit_href ,flavor_disk)
3149 self.logger.info("Modify disk of VM {} from {} to {} MB".format(vm_name,
3150 vm_disk, flavor_disk ))
3151 else:
3152 status = True
3153 self.logger.info("No need to modify disk of VM {}".format(vm_name))
3154
3155 return status
3156 except Exception as exp:
3157 self.logger.info("Error occurred while modifing disk size {}".format(exp))
3158
3159
3160 def modify_vm_disk_rest(self, disk_href , disk_size):
3161 """
3162 Method retrieve modify vm disk size
3163
3164 Args:
3165 disk_href - vCD API URL to GET and PUT disk data
3166 disk_size - disk size as specified in VNFD (flavor)
3167
3168 Returns:
3169 The return network uuid or return None
3170 """
3171 vca = self.connect()
3172 if not vca:
3173 raise vimconn.vimconnConnectionException("self.connect() is failed")
3174 if disk_href is None or disk_size is None:
3175 return None
3176
3177 if vca.vcloud_session and vca.vcloud_session.organization:
3178 response = Http.get(url=disk_href,
3179 headers=vca.vcloud_session.get_vcloud_headers(),
3180 verify=vca.verify,
3181 logger=vca.logger)
3182
3183 if response.status_code != requests.codes.ok:
3184 self.logger.debug("GET REST API call {} failed. Return status code {}".format(disk_href,
3185 response.status_code))
3186 return None
3187 try:
3188 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
3189 namespaces = {prefix:uri for prefix,uri in lxmlroot_respond.nsmap.iteritems() if prefix}
3190 namespaces["xmlns"]= "http://www.vmware.com/vcloud/v1.5"
3191
3192 for item in lxmlroot_respond.iterfind('xmlns:Item',namespaces):
3193 if item.find("rasd:Description",namespaces).text == "Hard disk":
3194 disk_item = item.find("rasd:HostResource" ,namespaces )
3195 if disk_item is not None:
3196 disk_item.attrib["{"+namespaces['xmlns']+"}capacity"] = str(disk_size)
3197 break
3198
3199 data = lxmlElementTree.tostring(lxmlroot_respond, encoding='utf8', method='xml',
3200 xml_declaration=True)
3201
3202 #Send PUT request to modify disk size
3203 headers = vca.vcloud_session.get_vcloud_headers()
3204 headers['Content-Type'] = 'application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1'
3205
3206 response = Http.put(url=disk_href,
3207 data=data,
3208 headers=headers,
3209 verify=vca.verify, logger=self.logger)
3210
3211 if response.status_code != 202:
3212 self.logger.debug("PUT REST API call {} failed. Return status code {}".format(disk_href,
3213 response.status_code))
3214 else:
3215 modify_disk_task = taskType.parseString(response.content, True)
3216 if type(modify_disk_task) is GenericTask:
3217 status = vca.block_until_completed(modify_disk_task)
3218 return status
3219
3220 return None
3221
3222 except Exception as exp :
3223 self.logger.info("Error occurred calling rest api for modifing disk size {}".format(exp))
3224 return None
3225
bhangarefda5f7c2017-01-12 23:50:34 -08003226 def add_pci_devices(self, vapp_uuid , pci_devices , vmname_andid):
3227 """
3228 Method to attach pci devices to VM
3229
3230 Args:
3231 vapp_uuid - uuid of vApp/VM
3232 pci_devices - pci devices infromation as specified in VNFD (flavor)
3233
3234 Returns:
3235 The status of add pci device task , vm object and
3236 vcenter_conect object
3237 """
3238 vm_obj = None
3239 vcenter_conect = None
3240 self.logger.info("Add pci devices {} into vApp {}".format(pci_devices , vapp_uuid))
kateeb044522017-03-06 23:54:39 -08003241 try:
3242 vm_vcenter_info = self.get_vm_vcenter_info(vapp_uuid)
3243 except Exception as exp:
3244 self.logger.error("Error occurred while getting vCenter infromationn"\
3245 " for VM : {}".format(exp))
3246 raise vimconn.vimconnException(message=exp)
3247
3248 if vm_vcenter_info["vm_moref_id"]:
bhangarefda5f7c2017-01-12 23:50:34 -08003249 context = None
3250 if hasattr(ssl, '_create_unverified_context'):
3251 context = ssl._create_unverified_context()
3252 try:
3253 no_of_pci_devices = len(pci_devices)
3254 if no_of_pci_devices > 0:
kateeb044522017-03-06 23:54:39 -08003255 vcenter_conect = SmartConnect(
3256 host=vm_vcenter_info["vm_vcenter_ip"],
3257 user=vm_vcenter_info["vm_vcenter_user"],
3258 pwd=vm_vcenter_info["vm_vcenter_password"],
3259 port=int(vm_vcenter_info["vm_vcenter_port"]),
3260 sslContext=context)
bhangarefda5f7c2017-01-12 23:50:34 -08003261 atexit.register(Disconnect, vcenter_conect)
3262 content = vcenter_conect.RetrieveContent()
3263
3264 #Get VM and its host
kateeb044522017-03-06 23:54:39 -08003265 host_obj, vm_obj = self.get_vm_obj(content ,vm_vcenter_info["vm_moref_id"])
bhangarefda5f7c2017-01-12 23:50:34 -08003266 self.logger.info("VM {} is currently on host {}".format(vm_obj, host_obj))
3267 if host_obj and vm_obj:
3268 #get PCI devies from host on which vapp is currently installed
3269 avilable_pci_devices = self.get_pci_devices(host_obj, no_of_pci_devices)
3270
3271 if avilable_pci_devices is None:
3272 #find other hosts with active pci devices
3273 new_host_obj , avilable_pci_devices = self.get_host_and_PCIdevices(
3274 content,
3275 no_of_pci_devices
3276 )
3277
3278 if new_host_obj is not None and avilable_pci_devices is not None and len(avilable_pci_devices)> 0:
3279 #Migrate vm to the host where PCI devices are availble
3280 self.logger.info("Relocate VM {} on new host {}".format(vm_obj, new_host_obj))
3281 task = self.relocate_vm(new_host_obj, vm_obj)
3282 if task is not None:
3283 result = self.wait_for_vcenter_task(task, vcenter_conect)
3284 self.logger.info("Migrate VM status: {}".format(result))
3285 host_obj = new_host_obj
3286 else:
3287 self.logger.info("Fail to migrate VM : {}".format(result))
3288 raise vimconn.vimconnNotFoundException(
3289 "Fail to migrate VM : {} to host {}".format(
3290 vmname_andid,
3291 new_host_obj)
3292 )
3293
3294 if host_obj is not None and avilable_pci_devices is not None and len(avilable_pci_devices)> 0:
3295 #Add PCI devices one by one
3296 for pci_device in avilable_pci_devices:
3297 task = self.add_pci_to_vm(host_obj, vm_obj, pci_device)
3298 if task:
3299 status= self.wait_for_vcenter_task(task, vcenter_conect)
3300 if status:
3301 self.logger.info("Added PCI device {} to VM {}".format(pci_device,str(vm_obj)))
3302 else:
kateeb044522017-03-06 23:54:39 -08003303 self.logger.error("Fail to add PCI device {} to VM {}".format(pci_device,str(vm_obj)))
bhangarefda5f7c2017-01-12 23:50:34 -08003304 return True, vm_obj, vcenter_conect
3305 else:
3306 self.logger.error("Currently there is no host with"\
3307 " {} number of avaialble PCI devices required for VM {}".format(
3308 no_of_pci_devices,
3309 vmname_andid)
3310 )
3311 raise vimconn.vimconnNotFoundException(
3312 "Currently there is no host with {} "\
3313 "number of avaialble PCI devices required for VM {}".format(
3314 no_of_pci_devices,
3315 vmname_andid))
3316 else:
3317 self.logger.debug("No infromation about PCI devices {} ",pci_devices)
3318
3319 except vmodl.MethodFault as error:
3320 self.logger.error("Error occurred while adding PCI devices {} ",error)
3321 return None, vm_obj, vcenter_conect
3322
3323 def get_vm_obj(self, content, mob_id):
3324 """
3325 Method to get the vsphere VM object associated with a given morf ID
3326 Args:
3327 vapp_uuid - uuid of vApp/VM
3328 content - vCenter content object
3329 mob_id - mob_id of VM
3330
3331 Returns:
3332 VM and host object
3333 """
3334 vm_obj = None
3335 host_obj = None
3336 try :
3337 container = content.viewManager.CreateContainerView(content.rootFolder,
3338 [vim.VirtualMachine], True
3339 )
3340 for vm in container.view:
3341 mobID = vm._GetMoId()
3342 if mobID == mob_id:
3343 vm_obj = vm
3344 host_obj = vm_obj.runtime.host
3345 break
3346 except Exception as exp:
3347 self.logger.error("Error occurred while finding VM object : {}".format(exp))
3348 return host_obj, vm_obj
3349
3350 def get_pci_devices(self, host, need_devices):
3351 """
3352 Method to get the details of pci devices on given host
3353 Args:
3354 host - vSphere host object
3355 need_devices - number of pci devices needed on host
3356
3357 Returns:
3358 array of pci devices
3359 """
3360 all_devices = []
3361 all_device_ids = []
3362 used_devices_ids = []
3363
3364 try:
3365 if host:
3366 pciPassthruInfo = host.config.pciPassthruInfo
3367 pciDevies = host.hardware.pciDevice
3368
3369 for pci_status in pciPassthruInfo:
3370 if pci_status.passthruActive:
3371 for device in pciDevies:
3372 if device.id == pci_status.id:
3373 all_device_ids.append(device.id)
3374 all_devices.append(device)
3375
3376 #check if devices are in use
3377 avalible_devices = all_devices
3378 for vm in host.vm:
3379 if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
3380 vm_devices = vm.config.hardware.device
3381 for device in vm_devices:
3382 if type(device) is vim.vm.device.VirtualPCIPassthrough:
3383 if device.backing.id in all_device_ids:
3384 for use_device in avalible_devices:
3385 if use_device.id == device.backing.id:
3386 avalible_devices.remove(use_device)
3387 used_devices_ids.append(device.backing.id)
3388 self.logger.debug("Device {} from devices {}"\
3389 "is in use".format(device.backing.id,
3390 device)
3391 )
3392 if len(avalible_devices) < need_devices:
3393 self.logger.debug("Host {} don't have {} number of active devices".format(host,
3394 need_devices))
3395 self.logger.debug("found only {} devives {}".format(len(avalible_devices),
3396 avalible_devices))
3397 return None
3398 else:
3399 required_devices = avalible_devices[:need_devices]
3400 self.logger.info("Found {} PCI devivces on host {} but required only {}".format(
3401 len(avalible_devices),
3402 host,
3403 need_devices))
3404 self.logger.info("Retruning {} devices as {}".format(need_devices,
3405 required_devices ))
3406 return required_devices
3407
3408 except Exception as exp:
3409 self.logger.error("Error {} occurred while finding pci devices on host: {}".format(exp, host))
3410
3411 return None
3412
3413 def get_host_and_PCIdevices(self, content, need_devices):
3414 """
3415 Method to get the details of pci devices infromation on all hosts
3416
3417 Args:
3418 content - vSphere host object
3419 need_devices - number of pci devices needed on host
3420
3421 Returns:
3422 array of pci devices and host object
3423 """
3424 host_obj = None
3425 pci_device_objs = None
3426 try:
3427 if content:
3428 container = content.viewManager.CreateContainerView(content.rootFolder,
3429 [vim.HostSystem], True)
3430 for host in container.view:
3431 devices = self.get_pci_devices(host, need_devices)
3432 if devices:
3433 host_obj = host
3434 pci_device_objs = devices
3435 break
3436 except Exception as exp:
3437 self.logger.error("Error {} occurred while finding pci devices on host: {}".format(exp, host_obj))
3438
3439 return host_obj,pci_device_objs
3440
3441 def relocate_vm(self, dest_host, vm) :
3442 """
3443 Method to get the relocate VM to new host
3444
3445 Args:
3446 dest_host - vSphere host object
3447 vm - vSphere VM object
3448
3449 Returns:
3450 task object
3451 """
3452 task = None
3453 try:
3454 relocate_spec = vim.vm.RelocateSpec(host=dest_host)
3455 task = vm.Relocate(relocate_spec)
3456 self.logger.info("Migrating {} to destination host {}".format(vm, dest_host))
3457 except Exception as exp:
3458 self.logger.error("Error occurred while relocate VM {} to new host {}: {}".format(
3459 dest_host, vm, exp))
3460 return task
3461
3462 def wait_for_vcenter_task(self, task, actionName='job', hideResult=False):
3463 """
3464 Waits and provides updates on a vSphere task
3465 """
3466 while task.info.state == vim.TaskInfo.State.running:
3467 time.sleep(2)
3468
3469 if task.info.state == vim.TaskInfo.State.success:
3470 if task.info.result is not None and not hideResult:
3471 self.logger.info('{} completed successfully, result: {}'.format(
3472 actionName,
3473 task.info.result))
3474 else:
3475 self.logger.info('Task {} completed successfully.'.format(actionName))
3476 else:
3477 self.logger.error('{} did not complete successfully: {} '.format(
3478 actionName,
3479 task.info.error)
3480 )
3481
3482 return task.info.result
3483
3484 def add_pci_to_vm(self,host_object, vm_object, host_pci_dev):
3485 """
3486 Method to add pci device in given VM
3487
3488 Args:
3489 host_object - vSphere host object
3490 vm_object - vSphere VM object
3491 host_pci_dev - host_pci_dev must be one of the devices from the
3492 host_object.hardware.pciDevice list
3493 which is configured as a PCI passthrough device
3494
3495 Returns:
3496 task object
3497 """
3498 task = None
3499 if vm_object and host_object and host_pci_dev:
3500 try :
3501 #Add PCI device to VM
3502 pci_passthroughs = vm_object.environmentBrowser.QueryConfigTarget(host=None).pciPassthrough
3503 systemid_by_pciid = {item.pciDevice.id: item.systemId for item in pci_passthroughs}
3504
3505 if host_pci_dev.id not in systemid_by_pciid:
3506 self.logger.error("Device {} is not a passthrough device ".format(host_pci_dev))
3507 return None
3508
3509 deviceId = hex(host_pci_dev.deviceId % 2**16).lstrip('0x')
3510 backing = vim.VirtualPCIPassthroughDeviceBackingInfo(deviceId=deviceId,
3511 id=host_pci_dev.id,
3512 systemId=systemid_by_pciid[host_pci_dev.id],
3513 vendorId=host_pci_dev.vendorId,
3514 deviceName=host_pci_dev.deviceName)
3515
3516 hba_object = vim.VirtualPCIPassthrough(key=-100, backing=backing)
3517
3518 new_device_config = vim.VirtualDeviceConfigSpec(device=hba_object)
3519 new_device_config.operation = "add"
3520 vmConfigSpec = vim.vm.ConfigSpec()
3521 vmConfigSpec.deviceChange = [new_device_config]
3522
3523 task = vm_object.ReconfigVM_Task(spec=vmConfigSpec)
3524 self.logger.info("Adding PCI device {} into VM {} from host {} ".format(
3525 host_pci_dev, vm_object, host_object)
3526 )
3527 except Exception as exp:
3528 self.logger.error("Error occurred while adding pci devive {} to VM {}: {}".format(
3529 host_pci_dev,
3530 vm_object,
3531 exp))
3532 return task
3533
kateeb044522017-03-06 23:54:39 -08003534 def get_vm_vcenter_info(self , vapp_uuid):
bhangarefda5f7c2017-01-12 23:50:34 -08003535 """
kateeb044522017-03-06 23:54:39 -08003536 Method to get details of vCenter and vm
bhangarefda5f7c2017-01-12 23:50:34 -08003537
3538 Args:
3539 vapp_uuid - uuid of vApp or VM
3540
3541 Returns:
3542 Moref Id of VM and deails of vCenter
3543 """
kateeb044522017-03-06 23:54:39 -08003544 vm_vcenter_info = {}
bhangarefda5f7c2017-01-12 23:50:34 -08003545
kateeb044522017-03-06 23:54:39 -08003546 if self.vcenter_ip is not None:
3547 vm_vcenter_info["vm_vcenter_ip"] = self.vcenter_ip
3548 else:
3549 raise vimconn.vimconnException(message="vCenter IP is not provided."\
3550 " Please provide vCenter IP while attaching datacenter to tenant in --config")
3551 if self.vcenter_port is not None:
3552 vm_vcenter_info["vm_vcenter_port"] = self.vcenter_port
3553 else:
3554 raise vimconn.vimconnException(message="vCenter port is not provided."\
3555 " Please provide vCenter port while attaching datacenter to tenant in --config")
3556 if self.vcenter_user is not None:
3557 vm_vcenter_info["vm_vcenter_user"] = self.vcenter_user
3558 else:
3559 raise vimconn.vimconnException(message="vCenter user is not provided."\
3560 " Please provide vCenter user while attaching datacenter to tenant in --config")
bhangarefda5f7c2017-01-12 23:50:34 -08003561
kateeb044522017-03-06 23:54:39 -08003562 if self.vcenter_password is not None:
3563 vm_vcenter_info["vm_vcenter_password"] = self.vcenter_password
3564 else:
3565 raise vimconn.vimconnException(message="vCenter user password is not provided."\
3566 " Please provide vCenter user password while attaching datacenter to tenant in --config")
3567 try:
3568 vm_details = self.get_vapp_details_rest(vapp_uuid, need_admin_access=True)
3569 if vm_details and "vm_vcenter_info" in vm_details:
3570 vm_vcenter_info["vm_moref_id"] = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
bhangarefda5f7c2017-01-12 23:50:34 -08003571
kateeb044522017-03-06 23:54:39 -08003572 return vm_vcenter_info
bhangarefda5f7c2017-01-12 23:50:34 -08003573
kateeb044522017-03-06 23:54:39 -08003574 except Exception as exp:
3575 self.logger.error("Error occurred while getting vCenter infromationn"\
3576 " for VM : {}".format(exp))
bhangarefda5f7c2017-01-12 23:50:34 -08003577
3578
3579 def get_vm_pci_details(self, vmuuid):
3580 """
3581 Method to get VM PCI device details from vCenter
3582
3583 Args:
3584 vm_obj - vSphere VM object
3585
3586 Returns:
3587 dict of PCI devives attached to VM
3588
3589 """
3590 vm_pci_devices_info = {}
3591 try:
kateeb044522017-03-06 23:54:39 -08003592 vm_vcenter_info = self.get_vm_vcenter_info(vmuuid)
3593 if vm_vcenter_info["vm_moref_id"]:
bhangarefda5f7c2017-01-12 23:50:34 -08003594 context = None
3595 if hasattr(ssl, '_create_unverified_context'):
3596 context = ssl._create_unverified_context()
kateeb044522017-03-06 23:54:39 -08003597 vcenter_conect = SmartConnect(host=vm_vcenter_info["vm_vcenter_ip"],
3598 user=vm_vcenter_info["vm_vcenter_user"],
3599 pwd=vm_vcenter_info["vm_vcenter_password"],
3600 port=int(vm_vcenter_info["vm_vcenter_port"]),
3601 sslContext=context
3602 )
bhangarefda5f7c2017-01-12 23:50:34 -08003603 atexit.register(Disconnect, vcenter_conect)
3604 content = vcenter_conect.RetrieveContent()
3605
3606 #Get VM and its host
kateeb044522017-03-06 23:54:39 -08003607 if content:
3608 host_obj, vm_obj = self.get_vm_obj(content ,vm_vcenter_info["vm_moref_id"])
3609 if host_obj and vm_obj:
3610 vm_pci_devices_info["host_name"]= host_obj.name
3611 vm_pci_devices_info["host_ip"]= host_obj.config.network.vnic[0].spec.ip.ipAddress
3612 for device in vm_obj.config.hardware.device:
3613 if type(device) == vim.vm.device.VirtualPCIPassthrough:
3614 device_details={'devide_id':device.backing.id,
3615 'pciSlotNumber':device.slotInfo.pciSlotNumber,
3616 }
3617 vm_pci_devices_info[device.deviceInfo.label] = device_details
3618 else:
3619 self.logger.error("Can not connect to vCenter while getting "\
3620 "PCI devices infromationn")
3621 return vm_pci_devices_info
bhangarefda5f7c2017-01-12 23:50:34 -08003622 except Exception as exp:
kateeb044522017-03-06 23:54:39 -08003623 self.logger.error("Error occurred while getting VM infromationn"\
3624 " for VM : {}".format(exp))
3625 raise vimconn.vimconnException(message=exp)
bhangare0e571a92017-01-12 04:02:23 -08003626
kasardc1f02e2017-03-25 07:20:30 -07003627 def add_network_adapter_to_vms(self, vapp, network_name, primary_nic_index, nicIndex, net, nic_type=None):
kasar3ac5dc42017-03-15 06:28:22 -07003628 """
3629 Method to add network adapter type to vm
3630 Args :
3631 network_name - name of network
3632 primary_nic_index - int value for primary nic index
3633 nicIndex - int value for nic index
3634 nic_type - specify model name to which add to vm
3635 Returns:
3636 None
3637 """
kasar4cb6e902017-03-18 00:17:27 -07003638 vca = self.connect()
3639 if not vca:
3640 raise vimconn.vimconnConnectionException("Failed to connect vCloud director")
kasar3ac5dc42017-03-15 06:28:22 -07003641
kasar4cb6e902017-03-18 00:17:27 -07003642 try:
kasardc1f02e2017-03-25 07:20:30 -07003643 floating_ip = False
3644 if 'floating_ip' in net: floating_ip = net['floating_ip']
3645 allocation_mode = "POOL" if floating_ip else "DHCP"
3646
kasar3ac5dc42017-03-15 06:28:22 -07003647 if not nic_type:
3648 for vms in vapp._get_vms():
3649 vm_id = (vms.id).split(':')[-1]
3650
3651 url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(vca.host, vm_id)
3652
3653 response = Http.get(url=url_rest_call,
3654 headers=vca.vcloud_session.get_vcloud_headers(),
3655 verify=vca.verify,
3656 logger=vca.logger)
3657 if response.status_code != 200:
kasar4cb6e902017-03-18 00:17:27 -07003658 self.logger.error("REST call {} failed reason : {}"\
3659 "status code : {}".format(url_rest_call,
3660 response.content,
3661 response.status_code))
3662 raise vimconn.vimconnException("add_network_adapter_to_vms : Failed to get "\
3663 "network connection section")
kasar3ac5dc42017-03-15 06:28:22 -07003664
3665 data = response.content
3666 if '<PrimaryNetworkConnectionIndex>' not in data:
3667 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
3668 <NetworkConnection network="{}">
3669 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
3670 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07003671 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
3672 </NetworkConnection>""".format(primary_nic_index, network_name, nicIndex,
3673 allocation_mode)
3674
kasar3ac5dc42017-03-15 06:28:22 -07003675 data = data.replace('</ovf:Info>\n','</ovf:Info>\n{}\n'.format(item))
3676 else:
3677 new_item = """<NetworkConnection network="{}">
3678 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
3679 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07003680 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
3681 </NetworkConnection>""".format(network_name, nicIndex,
3682 allocation_mode)
3683
kasar3ac5dc42017-03-15 06:28:22 -07003684 data = data.replace('</NetworkConnection>\n','</NetworkConnection>\n{}\n'.format(new_item))
3685
3686 headers = vca.vcloud_session.get_vcloud_headers()
3687 headers['Content-Type'] = 'application/vnd.vmware.vcloud.networkConnectionSection+xml'
3688 response = Http.put(url=url_rest_call, headers=headers, data=data,
3689 verify=vca.verify,
3690 logger=vca.logger)
kasar3ac5dc42017-03-15 06:28:22 -07003691 if response.status_code != 202:
kasar4cb6e902017-03-18 00:17:27 -07003692 self.logger.error("REST call {} failed reason : {}"\
3693 "status code : {} ".format(url_rest_call,
3694 response.content,
3695 response.status_code))
3696 raise vimconn.vimconnException("add_network_adapter_to_vms : Failed to update "\
3697 "network connection section")
kasar3ac5dc42017-03-15 06:28:22 -07003698 else:
3699 nic_task = taskType.parseString(response.content, True)
3700 if isinstance(nic_task, GenericTask):
3701 vca.block_until_completed(nic_task)
3702 self.logger.info("add_network_adapter_to_vms(): VM {} conneced to "\
3703 "default NIC type".format(vm_id))
3704 else:
3705 self.logger.error("add_network_adapter_to_vms(): VM {} failed to "\
3706 "connect NIC type".format(vm_id))
3707 else:
3708 for vms in vapp._get_vms():
3709 vm_id = (vms.id).split(':')[-1]
3710
3711 url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(vca.host, vm_id)
3712
3713 response = Http.get(url=url_rest_call,
3714 headers=vca.vcloud_session.get_vcloud_headers(),
3715 verify=vca.verify,
3716 logger=vca.logger)
3717 if response.status_code != 200:
kasar4cb6e902017-03-18 00:17:27 -07003718 self.logger.error("REST call {} failed reason : {}"\
3719 "status code : {}".format(url_rest_call,
3720 response.content,
3721 response.status_code))
3722 raise vimconn.vimconnException("add_network_adapter_to_vms : Failed to get "\
3723 "network connection section")
kasar3ac5dc42017-03-15 06:28:22 -07003724 data = response.content
3725 if '<PrimaryNetworkConnectionIndex>' not in data:
3726 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
3727 <NetworkConnection network="{}">
3728 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
3729 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07003730 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07003731 <NetworkAdapterType>{}</NetworkAdapterType>
kasardc1f02e2017-03-25 07:20:30 -07003732 </NetworkConnection>""".format(primary_nic_index, network_name, nicIndex,
3733 allocation_mode, nic_type)
3734
kasar3ac5dc42017-03-15 06:28:22 -07003735 data = data.replace('</ovf:Info>\n','</ovf:Info>\n{}\n'.format(item))
3736 else:
3737 new_item = """<NetworkConnection network="{}">
3738 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
3739 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07003740 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07003741 <NetworkAdapterType>{}</NetworkAdapterType>
kasardc1f02e2017-03-25 07:20:30 -07003742 </NetworkConnection>""".format(network_name, nicIndex,
3743 allocation_mode, nic_type)
3744
kasar3ac5dc42017-03-15 06:28:22 -07003745 data = data.replace('</NetworkConnection>\n','</NetworkConnection>\n{}\n'.format(new_item))
3746
3747 headers = vca.vcloud_session.get_vcloud_headers()
3748 headers['Content-Type'] = 'application/vnd.vmware.vcloud.networkConnectionSection+xml'
3749 response = Http.put(url=url_rest_call, headers=headers, data=data,
3750 verify=vca.verify,
3751 logger=vca.logger)
3752
3753 if response.status_code != 202:
kasar4cb6e902017-03-18 00:17:27 -07003754 self.logger.error("REST call {} failed reason : {}"\
3755 "status code : {}".format(url_rest_call,
3756 response.content,
3757 response.status_code))
3758 raise vimconn.vimconnException("add_network_adapter_to_vms : Failed to update "\
3759 "network connection section")
kasar3ac5dc42017-03-15 06:28:22 -07003760 else:
3761 nic_task = taskType.parseString(response.content, True)
3762 if isinstance(nic_task, GenericTask):
3763 vca.block_until_completed(nic_task)
3764 self.logger.info("add_network_adapter_to_vms(): VM {} "\
3765 "conneced to NIC type {}".format(vm_id, nic_type))
3766 else:
3767 self.logger.error("add_network_adapter_to_vms(): VM {} "\
3768 "failed to connect NIC type {}".format(vm_id, nic_type))
3769 except Exception as exp:
kasar4cb6e902017-03-18 00:17:27 -07003770 self.logger.error("add_network_adapter_to_vms() : exception occurred "\
3771 "while adding Network adapter")
3772 raise vimconn.vimconnException(message=exp)
kasarde691232017-03-25 03:37:31 -07003773
3774
3775 def set_numa_affinity(self, vmuuid, paired_threads_id):
3776 """
3777 Method to assign numa affinity in vm configuration parammeters
3778 Args :
3779 vmuuid - vm uuid
3780 paired_threads_id - one or more virtual processor
3781 numbers
3782 Returns:
3783 return if True
3784 """
3785 try:
3786 vm_moref_id , vm_vcenter_host , vm_vcenter_username, vm_vcenter_port = self.get_vcenter_info_rest(vmuuid)
3787 if vm_moref_id and vm_vcenter_host and vm_vcenter_username:
3788 context = None
3789 if hasattr(ssl, '_create_unverified_context'):
3790 context = ssl._create_unverified_context()
3791 vcenter_conect = SmartConnect(host=vm_vcenter_host, user=vm_vcenter_username,
3792 pwd=self.passwd, port=int(vm_vcenter_port),
3793 sslContext=context)
3794 atexit.register(Disconnect, vcenter_conect)
3795 content = vcenter_conect.RetrieveContent()
3796
3797 host_obj, vm_obj = self.get_vm_obj(content ,vm_moref_id)
3798 if vm_obj:
3799 config_spec = vim.vm.ConfigSpec()
3800 config_spec.extraConfig = []
3801 opt = vim.option.OptionValue()
3802 opt.key = 'numa.nodeAffinity'
3803 opt.value = str(paired_threads_id)
3804 config_spec.extraConfig.append(opt)
3805 task = vm_obj.ReconfigVM_Task(config_spec)
3806 if task:
3807 result = self.wait_for_vcenter_task(task, vcenter_conect)
3808 extra_config = vm_obj.config.extraConfig
3809 flag = False
3810 for opts in extra_config:
3811 if 'numa.nodeAffinity' in opts.key:
3812 flag = True
3813 self.logger.info("set_numa_affinity: Sucessfully assign numa affinity "\
3814 "value {} for vm {}".format(opt.value, vm_obj))
3815 if flag:
3816 return
3817 else:
3818 self.logger.error("set_numa_affinity: Failed to assign numa affinity")
3819 except Exception as exp:
3820 self.logger.error("set_numa_affinity : exception occurred while setting numa affinity "\
3821 "for VM {} : {}".format(vm_obj, vm_moref_id))
3822 raise vimconn.vimconnException("set_numa_affinity : Error {} failed to assign numa "\
3823 "affinity".format(exp))
kasardc1f02e2017-03-25 07:20:30 -07003824
3825
3826 def cloud_init(self, vapp, cloud_config):
3827 """
3828 Method to inject ssh-key
3829 vapp - vapp object
3830 cloud_config a dictionary with:
3831 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
3832 'users': (optional) list of users to be inserted, each item is a dict with:
3833 'name': (mandatory) user name,
3834 'key-pairs': (optional) list of strings with the public key to be inserted to the user
3835 'user-data': (optional) string is a text script to be passed directly to cloud-init
3836 'config-files': (optional). List of files to be transferred. Each item is a dict with:
3837 'dest': (mandatory) string with the destination absolute path
3838 'encoding': (optional, by default text). Can be one of:
3839 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
3840 'content' (mandatory): string with the content of the file
3841 'permissions': (optional) string with file permissions, typically octal notation '0644'
3842 'owner': (optional) file owner, string with the format 'owner:group'
3843 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk
3844 """
3845 vca = self.connect()
3846 if not vca:
3847 raise vimconn.vimconnConnectionException("Failed to connect vCloud director")
3848
3849 try:
3850 if isinstance(cloud_config, dict):
3851 key_pairs = []
3852 userdata = []
3853 if "key-pairs" in cloud_config:
3854 key_pairs = cloud_config["key-pairs"]
3855
3856 if "users" in cloud_config:
3857 userdata = cloud_config["users"]
3858
3859 for key in key_pairs:
3860 for user in userdata:
3861 if 'name' in user: user_name = user['name']
3862 if 'key-pairs' in user and len(user['key-pairs']) > 0:
3863 for user_key in user['key-pairs']:
3864 customize_script = """
3865 #!/bin/bash
3866 echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
3867 if [ "$1" = "precustomization" ];then
3868 echo performing precustomization tasks on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
3869 if [ ! -d /root/.ssh ];then
3870 mkdir /root/.ssh
3871 chown root:root /root/.ssh
3872 chmod 700 /root/.ssh
3873 touch /root/.ssh/authorized_keys
3874 chown root:root /root/.ssh/authorized_keys
3875 chmod 600 /root/.ssh/authorized_keys
3876 # make centos with selinux happy
3877 which restorecon && restorecon -Rv /root/.ssh
3878 echo '{key}' >> /root/.ssh/authorized_keys
3879 else
3880 touch /root/.ssh/authorized_keys
3881 chown root:root /root/.ssh/authorized_keys
3882 chmod 600 /root/.ssh/authorized_keys
3883 echo '{key}' >> /root/.ssh/authorized_keys
3884 fi
3885 if [ -d /home/{user_name} ];then
3886 if [ ! -d /home/{user_name}/.ssh ];then
3887 mkdir /home/{user_name}/.ssh
3888 chown {user_name}:{user_name} /home/{user_name}/.ssh
3889 chmod 700 /home/{user_name}/.ssh
3890 touch /home/{user_name}/.ssh/authorized_keys
3891 chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
3892 chmod 600 /home/{user_name}/.ssh/authorized_keys
3893 # make centos with selinux happy
3894 which restorecon && restorecon -Rv /home/{user_name}/.ssh
3895 echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
3896 else
3897 touch /home/{user_name}/.ssh/authorized_keys
3898 chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
3899 chmod 600 /home/{user_name}/.ssh/authorized_keys
3900 echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
3901 fi
3902 fi
3903 fi""".format(key=key, user_name=user_name, user_key=user_key)
3904
3905 for vm in vapp._get_vms():
3906 vm_name = vm.name
3907 task = vapp.customize_guest_os(vm_name, customization_script=customize_script)
3908 if isinstance(task, GenericTask):
3909 vca.block_until_completed(task)
3910 self.logger.info("cloud_init : customized guest os task "\
3911 "completed for VM {}".format(vm_name))
3912 else:
3913 self.logger.error("cloud_init : task for customized guest os"\
3914 "failed for VM {}".format(vm_name))
3915 except Exception as exp:
3916 self.logger.error("cloud_init : exception occurred while injecting "\
3917 "ssh-key")
3918 raise vimconn.vimconnException("cloud_init : Error {} failed to inject "\
3919 "ssh-key".format(exp))