blob: 5a58cf98ed90b2bc27da4f965265eff828f19622 [file] [log] [blame]
bayramov325fa1c2016-09-08 01:42:46 -07001# -*- coding: utf-8 -*-
2
beierlb22ce2d2019-12-12 12:09:51 -05003# #
kbsuba85c54d2019-10-17 16:30:32 +00004# Copyright 2016-2019 VMware Inc.
bhangare1a0b97c2017-06-21 02:20:15 -07005# This file is part of ETSI OSM
bayramov325fa1c2016-09-08 01:42:46 -07006# 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
bhangare1a0b97c2017-06-21 02:20:15 -070021# contact: osslegalrouting@vmware.com
beierlb22ce2d2019-12-12 12:09:51 -050022# #
bayramov325fa1c2016-09-08 01:42:46 -070023
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.
bayramov5761ad12016-10-04 09:00:30 +040026"""
bayramovbd6160f2016-09-28 04:12:05 +040027
beierlb22ce2d2019-12-12 12:09:51 -050028import atexit
29import hashlib
30import json
31import logging
bayramov325fa1c2016-09-08 01:42:46 -070032import os
beierlb22ce2d2019-12-12 12:09:51 -050033import random
34import re
Ananda Baitharu319c26f2019-03-05 17:34:31 +000035import shutil
beierlb22ce2d2019-12-12 12:09:51 -050036import socket
37import ssl
38import struct
Ananda Baitharu319c26f2019-03-05 17:34:31 +000039import subprocess
40import tempfile
bayramov325fa1c2016-09-08 01:42:46 -070041import time
beierlb22ce2d2019-12-12 12:09:51 -050042import traceback
bayramov325fa1c2016-09-08 01:42:46 -070043import uuid
sousaedu049cbb12022-01-05 11:39:35 +000044from xml.etree import ElementTree as XmlElementTree
45from xml.sax.saxutils import escape
46
47from lxml import etree as lxmlElementTree
48import netaddr
49from osm_ro_plugin import vimconn
50from progressbar import Bar, ETA, FileTransferSpeed, Percentage, ProgressBar
51from pyvcloud.vcd.client import BasicLoginCredentials, Client
52from pyvcloud.vcd.org import Org
53from pyvcloud.vcd.vapp import VApp
54from pyvcloud.vcd.vdc import VDC
55from pyVim.connect import Disconnect, SmartConnect
56from pyVmomi import vim, vmodl # @UnresolvedImport
57import requests
beierlb22ce2d2019-12-12 12:09:51 -050058import yaml
bayramov325fa1c2016-09-08 01:42:46 -070059
bayramovbd6160f2016-09-28 04:12:05 +040060# global variable for vcd connector type
sousaedu80135b92021-02-17 15:05:18 +010061STANDALONE = "standalone"
bayramovbd6160f2016-09-28 04:12:05 +040062
kate15f1c382016-12-15 01:12:40 -080063# key for flavor dicts
sousaedu80135b92021-02-17 15:05:18 +010064FLAVOR_RAM_KEY = "ram"
65FLAVOR_VCPUS_KEY = "vcpus"
66FLAVOR_DISK_KEY = "disk"
67DEFAULT_IP_PROFILE = {"dhcp_count": 50, "dhcp_enabled": True, "ip_version": "IPv4"}
bhangare0e571a92017-01-12 04:02:23 -080068# global variable for wait time
kate13ab2c42016-12-23 01:34:24 -080069INTERVAL_TIME = 5
70MAX_WAIT_TIME = 1800
bayramov325fa1c2016-09-08 01:42:46 -070071
sousaedu80135b92021-02-17 15:05:18 +010072API_VERSION = "27.0"
bayramovbd6160f2016-09-28 04:12:05 +040073
bayramovef390722016-09-27 03:34:46 -070074# -1: "Could not be created",
75# 0: "Unresolved",
76# 1: "Resolved",
77# 2: "Deployed",
78# 3: "Suspended",
79# 4: "Powered on",
80# 5: "Waiting for user input",
81# 6: "Unknown state",
82# 7: "Unrecognized state",
83# 8: "Powered off",
84# 9: "Inconsistent state",
85# 10: "Children do not all have the same status",
86# 11: "Upload initiated, OVF descriptor pending",
87# 12: "Upload initiated, copying contents",
88# 13: "Upload initiated , disk contents pending",
89# 14: "Upload has been quarantined",
90# 15: "Upload quarantine period has expired"
91
92# mapping vCD status to MANO
sousaedu80135b92021-02-17 15:05:18 +010093vcdStatusCode2manoFormat = {
94 4: "ACTIVE",
95 7: "PAUSED",
96 3: "SUSPENDED",
97 8: "INACTIVE",
98 12: "BUILD",
99 -1: "ERROR",
100 14: "DELETED",
101}
bayramovef390722016-09-27 03:34:46 -0700102
103#
sousaedu80135b92021-02-17 15:05:18 +0100104netStatus2manoFormat = {
105 "ACTIVE": "ACTIVE",
106 "PAUSED": "PAUSED",
107 "INACTIVE": "INACTIVE",
108 "BUILD": "BUILD",
109 "ERROR": "ERROR",
110 "DELETED": "DELETED",
111}
bayramovef390722016-09-27 03:34:46 -0700112
beierl26fec002019-12-06 17:06:40 -0500113
tierno72774862020-05-04 11:44:15 +0000114class vimconnector(vimconn.VimConnector):
kateeb044522017-03-06 23:54:39 -0800115 # dict used to store flavor in memory
116 flavorlist = {}
117
sousaedu80135b92021-02-17 15:05:18 +0100118 def __init__(
119 self,
120 uuid=None,
121 name=None,
122 tenant_id=None,
123 tenant_name=None,
124 url=None,
125 url_admin=None,
126 user=None,
127 passwd=None,
128 log_level=None,
129 config={},
130 persistent_info={},
131 ):
bayramovb6ffe792016-09-28 11:50:56 +0400132 """
133 Constructor create vmware connector to vCloud director.
134
135 By default construct doesn't validate connection state. So client can create object with None arguments.
136 If client specified username , password and host and VDC name. Connector initialize other missing attributes.
137
138 a) It initialize organization UUID
139 b) Initialize tenant_id/vdc ID. (This information derived from tenant name)
140
141 Args:
142 uuid - is organization uuid.
143 name - is organization name that must be presented in vCloud director.
144 tenant_id - is VDC uuid it must be presented in vCloud director
145 tenant_name - is VDC name.
146 url - is hostname or ip address of vCloud director
147 url_admin - same as above.
148 user - is user that administrator for organization. Caller must make sure that
149 username has right privileges.
150
151 password - is password for a user.
152
153 VMware connector also requires PVDC administrative privileges and separate account.
154 This variables must be passed via config argument dict contains keys
155
156 dict['admin_username']
157 dict['admin_password']
kateeb044522017-03-06 23:54:39 -0800158 config - Provide NSX and vCenter information
bayramovb6ffe792016-09-28 11:50:56 +0400159
160 Returns:
161 Nothing.
162 """
163
sousaedu80135b92021-02-17 15:05:18 +0100164 vimconn.VimConnector.__init__(
165 self,
166 uuid,
167 name,
168 tenant_id,
169 tenant_name,
170 url,
171 url_admin,
172 user,
173 passwd,
174 log_level,
175 config,
176 )
kate15f1c382016-12-15 01:12:40 -0800177
sousaedu80135b92021-02-17 15:05:18 +0100178 self.logger = logging.getLogger("ro.vim.vmware")
kate15f1c382016-12-15 01:12:40 -0800179 self.logger.setLevel(10)
tiernob3d36742017-03-03 23:51:05 +0100180 self.persistent_info = persistent_info
kate15f1c382016-12-15 01:12:40 -0800181
bayramovef390722016-09-27 03:34:46 -0700182 self.name = name
kate15f1c382016-12-15 01:12:40 -0800183 self.id = uuid
bayramovef390722016-09-27 03:34:46 -0700184 self.url = url
bayramov325fa1c2016-09-08 01:42:46 -0700185 self.url_admin = url_admin
186 self.tenant_id = tenant_id
187 self.tenant_name = tenant_name
bayramovef390722016-09-27 03:34:46 -0700188 self.user = user
189 self.passwd = passwd
190 self.config = config
191 self.admin_password = None
192 self.admin_user = None
kate15f1c382016-12-15 01:12:40 -0800193 self.org_name = ""
bhangare985a1fd2017-01-31 01:53:21 -0800194 self.nsx_manager = None
195 self.nsx_user = None
196 self.nsx_password = None
sbhangarea8e5b782018-06-21 02:10:03 -0700197 self.availability_zone = None
bayramovef390722016-09-27 03:34:46 -0700198
kasarc5bf2932018-03-09 04:15:22 -0800199 # Disable warnings from self-signed certificates.
200 requests.packages.urllib3.disable_warnings()
201
kate15f1c382016-12-15 01:12:40 -0800202 if tenant_name is not None:
203 orgnameandtenant = tenant_name.split(":")
sousaedu80135b92021-02-17 15:05:18 +0100204
kate15f1c382016-12-15 01:12:40 -0800205 if len(orgnameandtenant) == 2:
katec324e002016-12-23 00:54:47 -0800206 self.tenant_name = orgnameandtenant[1]
207 self.org_name = orgnameandtenant[0]
kate15f1c382016-12-15 01:12:40 -0800208 else:
209 self.tenant_name = tenant_name
sousaedu80135b92021-02-17 15:05:18 +0100210
bhangarea92ae392017-01-12 22:30:29 -0800211 if "orgname" in config:
sousaedu80135b92021-02-17 15:05:18 +0100212 self.org_name = config["orgname"]
katec324e002016-12-23 00:54:47 -0800213
tiernofe789902016-09-29 14:20:44 +0000214 if log_level:
bayramov5761ad12016-10-04 09:00:30 +0400215 self.logger.setLevel(getattr(logging, log_level))
bayramov325fa1c2016-09-08 01:42:46 -0700216
bayramovef390722016-09-27 03:34:46 -0700217 try:
sousaedu80135b92021-02-17 15:05:18 +0100218 self.admin_user = config["admin_username"]
219 self.admin_password = config["admin_password"]
bayramovef390722016-09-27 03:34:46 -0700220 except KeyError:
sousaedu80135b92021-02-17 15:05:18 +0100221 raise vimconn.VimConnException(
222 message="Error admin username or admin password is empty."
223 )
bayramov325fa1c2016-09-08 01:42:46 -0700224
bhangare985a1fd2017-01-31 01:53:21 -0800225 try:
sousaedu80135b92021-02-17 15:05:18 +0100226 self.nsx_manager = config["nsx_manager"]
227 self.nsx_user = config["nsx_user"]
228 self.nsx_password = config["nsx_password"]
bhangare985a1fd2017-01-31 01:53:21 -0800229 except KeyError:
sousaedu80135b92021-02-17 15:05:18 +0100230 raise vimconn.VimConnException(
231 message="Error: nsx manager or nsx user or nsx password is empty in Config"
232 )
bhangare985a1fd2017-01-31 01:53:21 -0800233
kateeb044522017-03-06 23:54:39 -0800234 self.vcenter_ip = config.get("vcenter_ip", None)
235 self.vcenter_port = config.get("vcenter_port", None)
236 self.vcenter_user = config.get("vcenter_user", None)
237 self.vcenter_password = config.get("vcenter_password", None)
238
beierlb22ce2d2019-12-12 12:09:51 -0500239 # Set availability zone for Affinity rules
sbhangarea8e5b782018-06-21 02:10:03 -0700240 self.availability_zone = self.set_availability_zones()
241
sousaedu80135b92021-02-17 15:05:18 +0100242 # ############# Stub code for SRIOV #################
243 # try:
244 # self.dvs_name = config['dv_switch_name']
245 # except KeyError:
246 # raise vimconn.VimConnException(message="Error:
247 # distributed virtaul switch name is empty in Config")
248 #
249 # self.vlanID_range = config.get("vlanID_range", None)
kateac1e3792017-04-01 02:16:39 -0700250
bayramovef390722016-09-27 03:34:46 -0700251 self.org_uuid = None
kasarc5bf2932018-03-09 04:15:22 -0800252 self.client = None
bayramov325fa1c2016-09-08 01:42:46 -0700253
254 if not url:
sousaedu80135b92021-02-17 15:05:18 +0100255 raise vimconn.VimConnException("url param can not be NoneType")
bayramov325fa1c2016-09-08 01:42:46 -0700256
bayramovef390722016-09-27 03:34:46 -0700257 if not self.url_admin: # try to use normal url
bayramov325fa1c2016-09-08 01:42:46 -0700258 self.url_admin = self.url
259
sousaedu80135b92021-02-17 15:05:18 +0100260 logging.debug(
261 "UUID: {} name: {} tenant_id: {} tenant name {}".format(
262 self.id, self.org_name, self.tenant_id, self.tenant_name
263 )
264 )
265 logging.debug(
266 "vcd url {} vcd username: {} vcd password: {}".format(
267 self.url, self.user, self.passwd
268 )
269 )
270 logging.debug(
271 "vcd admin username {} vcd admin passowrd {}".format(
272 self.admin_user, self.admin_password
273 )
274 )
bayramov325fa1c2016-09-08 01:42:46 -0700275
bayramovef390722016-09-27 03:34:46 -0700276 # initialize organization
bayramovbd6160f2016-09-28 04:12:05 +0400277 if self.user is not None and self.passwd is not None and self.url:
278 self.init_organization()
bayramovef390722016-09-27 03:34:46 -0700279
280 def __getitem__(self, index):
sousaedu80135b92021-02-17 15:05:18 +0100281 if index == "name":
kate15f1c382016-12-15 01:12:40 -0800282 return self.name
sousaedu80135b92021-02-17 15:05:18 +0100283
284 if index == "tenant_id":
bayramov325fa1c2016-09-08 01:42:46 -0700285 return self.tenant_id
sousaedu80135b92021-02-17 15:05:18 +0100286
287 if index == "tenant_name":
bayramov325fa1c2016-09-08 01:42:46 -0700288 return self.tenant_name
sousaedu80135b92021-02-17 15:05:18 +0100289 elif index == "id":
bayramov325fa1c2016-09-08 01:42:46 -0700290 return self.id
sousaedu80135b92021-02-17 15:05:18 +0100291 elif index == "org_name":
bayramovef390722016-09-27 03:34:46 -0700292 return self.org_name
sousaedu80135b92021-02-17 15:05:18 +0100293 elif index == "org_uuid":
bayramovef390722016-09-27 03:34:46 -0700294 return self.org_uuid
sousaedu80135b92021-02-17 15:05:18 +0100295 elif index == "user":
bayramov325fa1c2016-09-08 01:42:46 -0700296 return self.user
sousaedu80135b92021-02-17 15:05:18 +0100297 elif index == "passwd":
bayramov325fa1c2016-09-08 01:42:46 -0700298 return self.passwd
sousaedu80135b92021-02-17 15:05:18 +0100299 elif index == "url":
bayramov325fa1c2016-09-08 01:42:46 -0700300 return self.url
sousaedu80135b92021-02-17 15:05:18 +0100301 elif index == "url_admin":
bayramov325fa1c2016-09-08 01:42:46 -0700302 return self.url_admin
bayramovef390722016-09-27 03:34:46 -0700303 elif index == "config":
bayramov325fa1c2016-09-08 01:42:46 -0700304 return self.config
305 else:
tierno7d782ef2019-10-04 12:56:31 +0000306 raise KeyError("Invalid key '{}'".format(index))
bayramov325fa1c2016-09-08 01:42:46 -0700307
bayramovef390722016-09-27 03:34:46 -0700308 def __setitem__(self, index, value):
sousaedu80135b92021-02-17 15:05:18 +0100309 if index == "name":
kate15f1c382016-12-15 01:12:40 -0800310 self.name = value
sousaedu80135b92021-02-17 15:05:18 +0100311
312 if index == "tenant_id":
bayramov325fa1c2016-09-08 01:42:46 -0700313 self.tenant_id = value
sousaedu80135b92021-02-17 15:05:18 +0100314
315 if index == "tenant_name":
bayramov325fa1c2016-09-08 01:42:46 -0700316 self.tenant_name = value
sousaedu80135b92021-02-17 15:05:18 +0100317 elif index == "id":
bayramov325fa1c2016-09-08 01:42:46 -0700318 self.id = value
sousaedu80135b92021-02-17 15:05:18 +0100319 elif index == "org_name":
bayramovef390722016-09-27 03:34:46 -0700320 self.org_name = value
sousaedu80135b92021-02-17 15:05:18 +0100321 elif index == "org_uuid":
kate15f1c382016-12-15 01:12:40 -0800322 self.org_uuid = value
sousaedu80135b92021-02-17 15:05:18 +0100323 elif index == "user":
bayramov325fa1c2016-09-08 01:42:46 -0700324 self.user = value
sousaedu80135b92021-02-17 15:05:18 +0100325 elif index == "passwd":
bayramov325fa1c2016-09-08 01:42:46 -0700326 self.passwd = value
sousaedu80135b92021-02-17 15:05:18 +0100327 elif index == "url":
bayramov325fa1c2016-09-08 01:42:46 -0700328 self.url = value
sousaedu80135b92021-02-17 15:05:18 +0100329 elif index == "url_admin":
bayramov325fa1c2016-09-08 01:42:46 -0700330 self.url_admin = value
331 else:
tierno7d782ef2019-10-04 12:56:31 +0000332 raise KeyError("Invalid key '{}'".format(index))
bayramov325fa1c2016-09-08 01:42:46 -0700333
bayramovef390722016-09-27 03:34:46 -0700334 def connect_as_admin(self):
sousaedu80135b92021-02-17 15:05:18 +0100335 """Method connect as pvdc admin user to vCloud director.
336 There are certain action that can be done only by provider vdc admin user.
337 Organization creation / provider network creation etc.
bayramovef390722016-09-27 03:34:46 -0700338
sousaedu80135b92021-02-17 15:05:18 +0100339 Returns:
340 The return client object that latter can be used to connect to vcloud director as admin for provider vdc
bayramovef390722016-09-27 03:34:46 -0700341 """
kasarc5bf2932018-03-09 04:15:22 -0800342 self.logger.debug("Logging into vCD {} as admin.".format(self.org_name))
bayramov325fa1c2016-09-08 01:42:46 -0700343
kasarc5bf2932018-03-09 04:15:22 -0800344 try:
345 host = self.url
sousaedu80135b92021-02-17 15:05:18 +0100346 org = "System"
347 client_as_admin = Client(
348 host, verify_ssl_certs=False, api_version=API_VERSION
349 )
350 client_as_admin.set_credentials(
351 BasicLoginCredentials(self.admin_user, org, self.admin_password)
352 )
kasarc5bf2932018-03-09 04:15:22 -0800353 except Exception as e:
tierno72774862020-05-04 11:44:15 +0000354 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +0100355 "Can't connect to vCloud director as: {} with exception {}".format(
356 self.admin_user, e
357 )
358 )
bayramov325fa1c2016-09-08 01:42:46 -0700359
kasarc5bf2932018-03-09 04:15:22 -0800360 return client_as_admin
bayramov325fa1c2016-09-08 01:42:46 -0700361
bayramovef390722016-09-27 03:34:46 -0700362 def connect(self):
sousaedu80135b92021-02-17 15:05:18 +0100363 """Method connect as normal user to vCloud director.
bayramovef390722016-09-27 03:34:46 -0700364
sousaedu80135b92021-02-17 15:05:18 +0100365 Returns:
366 The return client object that latter can be used to connect to vCloud director as admin for VDC
bayramovef390722016-09-27 03:34:46 -0700367 """
bayramovb6ffe792016-09-28 11:50:56 +0400368 try:
sousaedu80135b92021-02-17 15:05:18 +0100369 self.logger.debug(
370 "Logging into vCD {} as {} to datacenter {}.".format(
371 self.org_name, self.user, self.org_name
372 )
373 )
kasarc5bf2932018-03-09 04:15:22 -0800374 host = self.url
beierl26fec002019-12-06 17:06:40 -0500375 client = Client(host, verify_ssl_certs=False, api_version=API_VERSION)
sousaedu80135b92021-02-17 15:05:18 +0100376 client.set_credentials(
377 BasicLoginCredentials(self.user, self.org_name, self.passwd)
378 )
beierl26fec002019-12-06 17:06:40 -0500379 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100380 raise vimconn.VimConnConnectionException(
381 "Can't connect to vCloud director org: "
382 "{} as user {} with exception: {}".format(self.org_name, self.user, e)
383 )
bayramov325fa1c2016-09-08 01:42:46 -0700384
kasarc5bf2932018-03-09 04:15:22 -0800385 return client
bayramov325fa1c2016-09-08 01:42:46 -0700386
bayramovbd6160f2016-09-28 04:12:05 +0400387 def init_organization(self):
sousaedu80135b92021-02-17 15:05:18 +0100388 """Method initialize organization UUID and VDC parameters.
bayramovbd6160f2016-09-28 04:12:05 +0400389
sousaedu80135b92021-02-17 15:05:18 +0100390 At bare minimum client must provide organization name that present in vCloud director and VDC.
bayramovbd6160f2016-09-28 04:12:05 +0400391
sousaedu80135b92021-02-17 15:05:18 +0100392 The VDC - UUID ( tenant_id) will be initialized at the run time if client didn't call constructor.
393 The Org - UUID will be initialized at the run time if data center present in vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -0700394
sousaedu80135b92021-02-17 15:05:18 +0100395 Returns:
396 The return vca object that letter can be used to connect to vcloud direct as admin
bayramovef390722016-09-27 03:34:46 -0700397 """
kasarc5bf2932018-03-09 04:15:22 -0800398 client = self.connect()
sousaedu80135b92021-02-17 15:05:18 +0100399
kasarc5bf2932018-03-09 04:15:22 -0800400 if not client:
tierno72774862020-05-04 11:44:15 +0000401 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
bhangare1a0b97c2017-06-21 02:20:15 -0700402
kasarc5bf2932018-03-09 04:15:22 -0800403 self.client = client
bayramovef390722016-09-27 03:34:46 -0700404 try:
405 if self.org_uuid is None:
kasarc5bf2932018-03-09 04:15:22 -0800406 org_list = client.get_org_list()
407 for org in org_list.Org:
bayramovbd6160f2016-09-28 04:12:05 +0400408 # we set org UUID at the init phase but we can do it only when we have valid credential.
sousaedu80135b92021-02-17 15:05:18 +0100409 if org.get("name") == self.org_name:
410 self.org_uuid = org.get("href").split("/")[-1]
411 self.logger.debug(
412 "Setting organization UUID {}".format(self.org_uuid)
413 )
bayramovbd6160f2016-09-28 04:12:05 +0400414 break
bayramovbd6160f2016-09-28 04:12:05 +0400415 else:
sousaedu80135b92021-02-17 15:05:18 +0100416 raise vimconn.VimConnException(
417 "Vcloud director organization {} not found".format(
418 self.org_name
419 )
420 )
bayramovbd6160f2016-09-28 04:12:05 +0400421
422 # if well good we require for org details
423 org_details_dict = self.get_org(org_uuid=self.org_uuid)
424
425 # we have two case if we want to initialize VDC ID or VDC name at run time
426 # tenant_name provided but no tenant id
sousaedu80135b92021-02-17 15:05:18 +0100427 if (
428 self.tenant_id is None
429 and self.tenant_name is not None
430 and "vdcs" in org_details_dict
431 ):
432 vdcs_dict = org_details_dict["vdcs"]
bayramovbd6160f2016-09-28 04:12:05 +0400433 for vdc in vdcs_dict:
434 if vdcs_dict[vdc] == self.tenant_name:
435 self.tenant_id = vdc
sousaedu80135b92021-02-17 15:05:18 +0100436 self.logger.debug(
437 "Setting vdc uuid {} for organization UUID {}".format(
438 self.tenant_id, self.org_name
439 )
440 )
bayramovbd6160f2016-09-28 04:12:05 +0400441 break
442 else:
sousaedu80135b92021-02-17 15:05:18 +0100443 raise vimconn.VimConnException(
444 "Tenant name indicated but not present in vcloud director."
445 )
446
bayramovbd6160f2016-09-28 04:12:05 +0400447 # case two we have tenant_id but we don't have tenant name so we find and set it.
sousaedu80135b92021-02-17 15:05:18 +0100448 if (
449 self.tenant_id is not None
450 and self.tenant_name is None
451 and "vdcs" in org_details_dict
452 ):
453 vdcs_dict = org_details_dict["vdcs"]
bayramovbd6160f2016-09-28 04:12:05 +0400454 for vdc in vdcs_dict:
455 if vdc == self.tenant_id:
456 self.tenant_name = vdcs_dict[vdc]
sousaedu80135b92021-02-17 15:05:18 +0100457 self.logger.debug(
458 "Setting vdc uuid {} for organization UUID {}".format(
459 self.tenant_id, self.org_name
460 )
461 )
bayramovbd6160f2016-09-28 04:12:05 +0400462 break
463 else:
sousaedu80135b92021-02-17 15:05:18 +0100464 raise vimconn.VimConnException(
465 "Tenant id indicated but not present in vcloud director"
466 )
467
bayramovef390722016-09-27 03:34:46 -0700468 self.logger.debug("Setting organization uuid {}".format(self.org_uuid))
beierl26fec002019-12-06 17:06:40 -0500469 except Exception as e:
sousaedu80135b92021-02-17 15:05:18 +0100470 self.logger.debug(
471 "Failed initialize organization UUID for org {}: {}".format(
472 self.org_name, e
473 ),
474 )
bayramovef390722016-09-27 03:34:46 -0700475 self.logger.debug(traceback.format_exc())
476 self.org_uuid = None
bayramov325fa1c2016-09-08 01:42:46 -0700477
bayramovef390722016-09-27 03:34:46 -0700478 def new_tenant(self, tenant_name=None, tenant_description=None):
sousaedu80135b92021-02-17 15:05:18 +0100479 """Method adds a new tenant to VIM with this name.
480 This action requires access to create VDC action in vCloud director.
bayramovef390722016-09-27 03:34:46 -0700481
sousaedu80135b92021-02-17 15:05:18 +0100482 Args:
483 tenant_name is tenant_name to be created.
484 tenant_description not used for this call
bayramovb6ffe792016-09-28 11:50:56 +0400485
sousaedu80135b92021-02-17 15:05:18 +0100486 Return:
487 returns the tenant identifier in UUID format.
488 If action is failed method will throw vimconn.VimConnException method
489 """
bayramovef390722016-09-27 03:34:46 -0700490 vdc_task = self.create_vdc(vdc_name=tenant_name)
491 if vdc_task is not None:
beierlb22ce2d2019-12-12 12:09:51 -0500492 vdc_uuid, _ = vdc_task.popitem()
sousaedu80135b92021-02-17 15:05:18 +0100493 self.logger.info(
494 "Created new vdc {} and uuid: {}".format(tenant_name, vdc_uuid)
495 )
496
bayramovef390722016-09-27 03:34:46 -0700497 return vdc_uuid
498 else:
sousaedu80135b92021-02-17 15:05:18 +0100499 raise vimconn.VimConnException(
500 "Failed create tenant {}".format(tenant_name)
501 )
bayramovef390722016-09-27 03:34:46 -0700502
bayramov163f1ae2016-09-28 17:16:55 +0400503 def delete_tenant(self, tenant_id=None):
sousaedu80135b92021-02-17 15:05:18 +0100504 """Delete a tenant from VIM
505 Args:
506 tenant_id is tenant_id to be deleted.
kated47ad5f2017-08-03 02:16:13 -0700507
sousaedu80135b92021-02-17 15:05:18 +0100508 Return:
509 returns the tenant identifier in UUID format.
510 If action is failed method will throw exception
kated47ad5f2017-08-03 02:16:13 -0700511 """
512 vca = self.connect_as_admin()
513 if not vca:
tierno72774862020-05-04 11:44:15 +0000514 raise vimconn.VimConnConnectionException("Failed to connect vCD")
kated47ad5f2017-08-03 02:16:13 -0700515
516 if tenant_id is not None:
kasarc5bf2932018-03-09 04:15:22 -0800517 if vca._session:
beierlb22ce2d2019-12-12 12:09:51 -0500518 # Get OrgVDC
sousaedu80135b92021-02-17 15:05:18 +0100519 url_list = [self.url, "/api/vdc/", tenant_id]
520 orgvdc_herf = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -0800521
sousaedu80135b92021-02-17 15:05:18 +0100522 headers = {
523 "Accept": "application/*+xml;version=" + API_VERSION,
524 "x-vcloud-authorization": vca._session.headers[
525 "x-vcloud-authorization"
526 ],
527 }
528 response = self.perform_request(
529 req_type="GET", url=orgvdc_herf, headers=headers
530 )
kated47ad5f2017-08-03 02:16:13 -0700531
532 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +0100533 self.logger.debug(
534 "delete_tenant():GET REST API call {} failed. "
535 "Return status code {}".format(
536 orgvdc_herf, response.status_code
537 )
538 )
539
540 raise vimconn.VimConnNotFoundException(
541 "Fail to get tenant {}".format(tenant_id)
542 )
kated47ad5f2017-08-03 02:16:13 -0700543
beierl01bd6692019-12-09 17:06:20 -0500544 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +0100545 namespaces = {
546 prefix: uri
547 for prefix, uri in lxmlroot_respond.nsmap.items()
548 if prefix
549 }
beierlb22ce2d2019-12-12 12:09:51 -0500550 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
sousaedu80135b92021-02-17 15:05:18 +0100551 vdc_remove_href = lxmlroot_respond.find(
552 "xmlns:Link[@rel='remove']", namespaces
553 ).attrib["href"]
554 vdc_remove_href = vdc_remove_href + "?recursive=true&force=true"
kated47ad5f2017-08-03 02:16:13 -0700555
sousaedu80135b92021-02-17 15:05:18 +0100556 response = self.perform_request(
557 req_type="DELETE", url=vdc_remove_href, headers=headers
558 )
kated47ad5f2017-08-03 02:16:13 -0700559
560 if response.status_code == 202:
kasarc5bf2932018-03-09 04:15:22 -0800561 time.sleep(5)
sousaedu80135b92021-02-17 15:05:18 +0100562
kasarc5bf2932018-03-09 04:15:22 -0800563 return tenant_id
kated47ad5f2017-08-03 02:16:13 -0700564 else:
sousaedu80135b92021-02-17 15:05:18 +0100565 self.logger.debug(
566 "delete_tenant(): DELETE REST API call {} failed. "
567 "Return status code {}".format(
568 vdc_remove_href, response.status_code
569 )
570 )
571
572 raise vimconn.VimConnException(
573 "Fail to delete tenant with ID {}".format(tenant_id)
574 )
kated47ad5f2017-08-03 02:16:13 -0700575 else:
sousaedu80135b92021-02-17 15:05:18 +0100576 self.logger.debug(
577 "delete_tenant():Incorrect tenant ID {}".format(tenant_id)
578 )
579
580 raise vimconn.VimConnNotFoundException(
581 "Fail to get tenant {}".format(tenant_id)
582 )
kated47ad5f2017-08-03 02:16:13 -0700583
bayramov325fa1c2016-09-08 01:42:46 -0700584 def get_tenant_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400585 """Obtain tenants of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700586 filter_dict can contain the following keys:
587 name: filter by tenant name
588 id: filter by tenant uuid/id
589 <other VIM specific>
bayramovb6ffe792016-09-28 11:50:56 +0400590 Returns the tenant list of dictionaries:
bayramov325fa1c2016-09-08 01:42:46 -0700591 [{'name':'<name>, 'id':'<id>, ...}, ...]
bayramov325fa1c2016-09-08 01:42:46 -0700592
bayramovb6ffe792016-09-28 11:50:56 +0400593 """
bayramovef390722016-09-27 03:34:46 -0700594 org_dict = self.get_org(self.org_uuid)
sousaedu80135b92021-02-17 15:05:18 +0100595 vdcs_dict = org_dict["vdcs"]
bayramovef390722016-09-27 03:34:46 -0700596
597 vdclist = []
598 try:
599 for k in vdcs_dict:
sousaedu80135b92021-02-17 15:05:18 +0100600 entry = {"name": vdcs_dict[k], "id": k}
bayramovb6ffe792016-09-28 11:50:56 +0400601 # if caller didn't specify dictionary we return all tenants.
sousaedu80135b92021-02-17 15:05:18 +0100602
bayramovb6ffe792016-09-28 11:50:56 +0400603 if filter_dict is not None and filter_dict:
604 filtered_entry = entry.copy()
605 filtered_dict = set(entry.keys()) - set(filter_dict)
sousaedu80135b92021-02-17 15:05:18 +0100606
beierlb22ce2d2019-12-12 12:09:51 -0500607 for unwanted_key in filtered_dict:
608 del entry[unwanted_key]
sousaedu80135b92021-02-17 15:05:18 +0100609
bayramovb6ffe792016-09-28 11:50:56 +0400610 if filter_dict == entry:
611 vdclist.append(filtered_entry)
612 else:
613 vdclist.append(entry)
beierlb22ce2d2019-12-12 12:09:51 -0500614 except Exception:
bayramovef390722016-09-27 03:34:46 -0700615 self.logger.debug("Error in get_tenant_list()")
616 self.logger.debug(traceback.format_exc())
sousaedu80135b92021-02-17 15:05:18 +0100617
tierno72774862020-05-04 11:44:15 +0000618 raise vimconn.VimConnException("Incorrect state. {}")
bayramovef390722016-09-27 03:34:46 -0700619
620 return vdclist
621
sousaedu80135b92021-02-17 15:05:18 +0100622 def new_network(
623 self,
624 net_name,
625 net_type,
626 ip_profile=None,
627 shared=False,
628 provider_network_profile=None,
629 ):
bayramovb6ffe792016-09-28 11:50:56 +0400630 """Adds a tenant network to VIM
garciadeblasebd66722019-01-31 16:01:31 +0000631 Params:
632 'net_name': name of the network
633 'net_type': one of:
634 'bridge': overlay isolated network
635 'data': underlay E-LAN network for Passthrough and SRIOV interfaces
636 'ptp': underlay E-LINE network for Passthrough and SRIOV interfaces.
637 'ip_profile': is a dict containing the IP parameters of the network
638 'ip_version': can be "IPv4" or "IPv6" (Currently only IPv4 is implemented)
639 'subnet_address': ip_prefix_schema, that is X.X.X.X/Y
640 'gateway_address': (Optional) ip_schema, that is X.X.X.X
641 'dns_address': (Optional) comma separated list of ip_schema, e.g. X.X.X.X[,X,X,X,X]
642 'dhcp_enabled': True or False
643 'dhcp_start_address': ip_schema, first IP to grant
644 'dhcp_count': number of IPs to grant.
645 'shared': if this network can be seen/use by other tenants/organization
kbsuba85c54d2019-10-17 16:30:32 +0000646 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
garciadeblasebd66722019-01-31 16:01:31 +0000647 Returns a tuple with the network identifier and created_items, or raises an exception on error
648 created_items can be None or a dictionary where this method can include key-values that will be passed to
649 the method delete_network. Can be used to store created segments, created l2gw connections, etc.
650 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
651 as not present.
652 """
bayramov325fa1c2016-09-08 01:42:46 -0700653
sousaedu80135b92021-02-17 15:05:18 +0100654 self.logger.debug(
655 "new_network tenant {} net_type {} ip_profile {} shared {} provider_network_profile {}".format(
656 net_name, net_type, ip_profile, shared, provider_network_profile
657 )
658 )
659 # vlan = None
660 # if provider_network_profile:
661 # vlan = provider_network_profile.get("segmentation-id")
bayramov325fa1c2016-09-08 01:42:46 -0700662
garciadeblasebd66722019-01-31 16:01:31 +0000663 created_items = {}
sousaedu80135b92021-02-17 15:05:18 +0100664 isshared = "false"
bayramovef390722016-09-27 03:34:46 -0700665
sousaedu80135b92021-02-17 15:05:18 +0100666 if shared:
667 isshared = "true"
668
669 # ############# Stub code for SRIOV #################
670 # if net_type == "data" or net_type == "ptp":
671 # if self.config.get('dv_switch_name') == None:
672 # raise vimconn.VimConnConflictException("You must provide 'dv_switch_name' at config value")
673 # network_uuid = self.create_dvPort_group(net_name)
kbsuba85c54d2019-10-17 16:30:32 +0000674 parent_network_uuid = None
675
kbsuba85c54d2019-10-17 16:30:32 +0000676 if provider_network_profile is not None:
677 for k, v in provider_network_profile.items():
sousaedu80135b92021-02-17 15:05:18 +0100678 if k == "physical_network":
kbsuba85c54d2019-10-17 16:30:32 +0000679 parent_network_uuid = self.get_physical_network_by_name(v)
kateac1e3792017-04-01 02:16:39 -0700680
sousaedu80135b92021-02-17 15:05:18 +0100681 network_uuid = self.create_network(
682 network_name=net_name,
683 net_type=net_type,
684 ip_profile=ip_profile,
685 isshared=isshared,
686 parent_network_uuid=parent_network_uuid,
687 )
688
bayramovef390722016-09-27 03:34:46 -0700689 if network_uuid is not None:
garciadeblasebd66722019-01-31 16:01:31 +0000690 return network_uuid, created_items
bayramovef390722016-09-27 03:34:46 -0700691 else:
sousaedu80135b92021-02-17 15:05:18 +0100692 raise vimconn.VimConnUnexpectedResponse(
693 "Failed create a new network {}".format(net_name)
694 )
bayramovef390722016-09-27 03:34:46 -0700695
696 def get_vcd_network_list(self):
sousaedu80135b92021-02-17 15:05:18 +0100697 """Method available organization for a logged in tenant
bayramovef390722016-09-27 03:34:46 -0700698
sousaedu80135b92021-02-17 15:05:18 +0100699 Returns:
700 The return vca object that letter can be used to connect to vcloud direct as admin
bayramovef390722016-09-27 03:34:46 -0700701 """
702
sousaedu80135b92021-02-17 15:05:18 +0100703 self.logger.debug(
704 "get_vcd_network_list(): retrieving network list for vcd {}".format(
705 self.tenant_name
706 )
707 )
bayramovef390722016-09-27 03:34:46 -0700708
kate15f1c382016-12-15 01:12:40 -0800709 if not self.tenant_name:
tierno72774862020-05-04 11:44:15 +0000710 raise vimconn.VimConnConnectionException("Tenant name is empty.")
kate15f1c382016-12-15 01:12:40 -0800711
beierlb22ce2d2019-12-12 12:09:51 -0500712 _, vdc = self.get_vdc_details()
kate15f1c382016-12-15 01:12:40 -0800713 if vdc is None:
sousaedu80135b92021-02-17 15:05:18 +0100714 raise vimconn.VimConnConnectionException(
715 "Can't retrieve information for a VDC {}".format(self.tenant_name)
716 )
kate15f1c382016-12-15 01:12:40 -0800717
sousaedu80135b92021-02-17 15:05:18 +0100718 vdc_uuid = vdc.get("id").split(":")[3]
kasarc5bf2932018-03-09 04:15:22 -0800719 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +0100720 headers = {
721 "Accept": "application/*+xml;version=" + API_VERSION,
722 "x-vcloud-authorization": self.client._session.headers[
723 "x-vcloud-authorization"
724 ],
725 }
726 response = self.perform_request(
727 req_type="GET", url=vdc.get("href"), headers=headers
728 )
729
kasarc5bf2932018-03-09 04:15:22 -0800730 if response.status_code != 200:
731 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000732 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800733 else:
beierl26fec002019-12-06 17:06:40 -0500734 content = XmlElementTree.fromstring(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -0700735
bayramovef390722016-09-27 03:34:46 -0700736 network_list = []
737 try:
kasarc5bf2932018-03-09 04:15:22 -0800738 for item in content:
sousaedu80135b92021-02-17 15:05:18 +0100739 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800740 for net in item:
sousaedu80135b92021-02-17 15:05:18 +0100741 response = self.perform_request(
742 req_type="GET", url=net.get("href"), headers=headers
743 )
bayramovef390722016-09-27 03:34:46 -0700744
kasarc5bf2932018-03-09 04:15:22 -0800745 if response.status_code != 200:
746 self.logger.error("Failed to get network content")
sousaedu80135b92021-02-17 15:05:18 +0100747 raise vimconn.VimConnNotFoundException(
748 "Failed to get network content"
749 )
kasarc5bf2932018-03-09 04:15:22 -0800750 else:
beierl26fec002019-12-06 17:06:40 -0500751 net_details = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800752
753 filter_dict = {}
sousaedu80135b92021-02-17 15:05:18 +0100754 net_uuid = net_details.get("id").split(":")
755
kasarc5bf2932018-03-09 04:15:22 -0800756 if len(net_uuid) != 4:
757 continue
758 else:
759 net_uuid = net_uuid[3]
760 # create dict entry
sousaedu80135b92021-02-17 15:05:18 +0100761 self.logger.debug(
762 "get_vcd_network_list(): Adding network {} "
763 "to a list vcd id {} network {}".format(
764 net_uuid, vdc_uuid, net_details.get("name")
765 )
766 )
767 filter_dict["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800768 filter_dict["id"] = net_uuid
sousaedu80135b92021-02-17 15:05:18 +0100769
770 if [
771 i.text
772 for i in net_details
773 if i.tag.split("}")[-1] == "IsShared"
774 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800775 shared = True
776 else:
777 shared = False
sousaedu80135b92021-02-17 15:05:18 +0100778
kasarc5bf2932018-03-09 04:15:22 -0800779 filter_dict["shared"] = shared
780 filter_dict["tenant_id"] = vdc_uuid
sousaedu80135b92021-02-17 15:05:18 +0100781
782 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800783 filter_dict["admin_state_up"] = True
784 else:
785 filter_dict["admin_state_up"] = False
sousaedu80135b92021-02-17 15:05:18 +0100786
kasarc5bf2932018-03-09 04:15:22 -0800787 filter_dict["status"] = "ACTIVE"
788 filter_dict["type"] = "bridge"
789 network_list.append(filter_dict)
sousaedu80135b92021-02-17 15:05:18 +0100790 self.logger.debug(
791 "get_vcd_network_list adding entry {}".format(
792 filter_dict
793 )
794 )
beierlb22ce2d2019-12-12 12:09:51 -0500795 except Exception:
kasarc5bf2932018-03-09 04:15:22 -0800796 self.logger.debug("Error in get_vcd_network_list", exc_info=True)
bayramovef390722016-09-27 03:34:46 -0700797 pass
798
799 self.logger.debug("get_vcd_network_list returning {}".format(network_list))
sousaedu80135b92021-02-17 15:05:18 +0100800
bayramovef390722016-09-27 03:34:46 -0700801 return network_list
bayramov325fa1c2016-09-08 01:42:46 -0700802
803 def get_network_list(self, filter_dict={}):
bayramovb6ffe792016-09-28 11:50:56 +0400804 """Obtain tenant networks of VIM
bayramov325fa1c2016-09-08 01:42:46 -0700805 Filter_dict can be:
bayramovef390722016-09-27 03:34:46 -0700806 name: network name OR/AND
807 id: network uuid OR/AND
808 shared: boolean OR/AND
809 tenant_id: tenant OR/AND
bayramov325fa1c2016-09-08 01:42:46 -0700810 admin_state_up: boolean
811 status: 'ACTIVE'
bayramovef390722016-09-27 03:34:46 -0700812
813 [{key : value , key : value}]
814
bayramov325fa1c2016-09-08 01:42:46 -0700815 Returns the network list of dictionaries:
816 [{<the fields at Filter_dict plus some VIM specific>}, ...]
817 List can be empty
bayramovb6ffe792016-09-28 11:50:56 +0400818 """
bayramov325fa1c2016-09-08 01:42:46 -0700819
sousaedu80135b92021-02-17 15:05:18 +0100820 self.logger.debug(
821 "get_network_list(): retrieving network list for vcd {}".format(
822 self.tenant_name
823 )
824 )
kate15f1c382016-12-15 01:12:40 -0800825
826 if not self.tenant_name:
tierno72774862020-05-04 11:44:15 +0000827 raise vimconn.VimConnConnectionException("Tenant name is empty.")
bayramov325fa1c2016-09-08 01:42:46 -0700828
beierlb22ce2d2019-12-12 12:09:51 -0500829 _, vdc = self.get_vdc_details()
kate15f1c382016-12-15 01:12:40 -0800830 if vdc is None:
tierno72774862020-05-04 11:44:15 +0000831 raise vimconn.VimConnConnectionException(
sousaedu80135b92021-02-17 15:05:18 +0100832 "Can't retrieve information for a VDC {}.".format(self.tenant_name)
833 )
bayramov325fa1c2016-09-08 01:42:46 -0700834
bayramovef390722016-09-27 03:34:46 -0700835 try:
sousaedu80135b92021-02-17 15:05:18 +0100836 vdcid = vdc.get("id").split(":")[3]
kasarc5bf2932018-03-09 04:15:22 -0800837
838 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +0100839 headers = {
840 "Accept": "application/*+xml;version=" + API_VERSION,
841 "x-vcloud-authorization": self.client._session.headers[
842 "x-vcloud-authorization"
843 ],
844 }
845 response = self.perform_request(
846 req_type="GET", url=vdc.get("href"), headers=headers
847 )
848
kasarc5bf2932018-03-09 04:15:22 -0800849 if response.status_code != 200:
850 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000851 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800852 else:
beierl26fec002019-12-06 17:06:40 -0500853 content = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800854
bhangarebfdca492017-03-11 01:32:46 -0800855 network_list = []
kasarc5bf2932018-03-09 04:15:22 -0800856 for item in content:
sousaedu80135b92021-02-17 15:05:18 +0100857 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800858 for net in item:
sousaedu80135b92021-02-17 15:05:18 +0100859 response = self.perform_request(
860 req_type="GET", url=net.get("href"), headers=headers
861 )
bhangarebfdca492017-03-11 01:32:46 -0800862
kasarc5bf2932018-03-09 04:15:22 -0800863 if response.status_code != 200:
864 self.logger.error("Failed to get network content")
sousaedu80135b92021-02-17 15:05:18 +0100865 raise vimconn.VimConnNotFoundException(
866 "Failed to get network content"
867 )
kasarc5bf2932018-03-09 04:15:22 -0800868 else:
beierl26fec002019-12-06 17:06:40 -0500869 net_details = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -0700870
kasarc5bf2932018-03-09 04:15:22 -0800871 filter_entry = {}
sousaedu80135b92021-02-17 15:05:18 +0100872 net_uuid = net_details.get("id").split(":")
873
kasarc5bf2932018-03-09 04:15:22 -0800874 if len(net_uuid) != 4:
875 continue
876 else:
sbhangarea8e5b782018-06-21 02:10:03 -0700877 net_uuid = net_uuid[3]
kasarc5bf2932018-03-09 04:15:22 -0800878 # create dict entry
sousaedu80135b92021-02-17 15:05:18 +0100879 self.logger.debug(
880 "get_network_list(): Adding net {}"
881 " to a list vcd id {} network {}".format(
882 net_uuid, vdcid, net_details.get("name")
883 )
884 )
885 filter_entry["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800886 filter_entry["id"] = net_uuid
sousaedu80135b92021-02-17 15:05:18 +0100887
888 if [
889 i.text
890 for i in net_details
891 if i.tag.split("}")[-1] == "IsShared"
892 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800893 shared = True
894 else:
895 shared = False
sousaedu80135b92021-02-17 15:05:18 +0100896
kasarc5bf2932018-03-09 04:15:22 -0800897 filter_entry["shared"] = shared
898 filter_entry["tenant_id"] = vdcid
sousaedu80135b92021-02-17 15:05:18 +0100899
900 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800901 filter_entry["admin_state_up"] = True
902 else:
903 filter_entry["admin_state_up"] = False
sousaedu80135b92021-02-17 15:05:18 +0100904
kasarc5bf2932018-03-09 04:15:22 -0800905 filter_entry["status"] = "ACTIVE"
906 filter_entry["type"] = "bridge"
907 filtered_entry = filter_entry.copy()
908
909 if filter_dict is not None and filter_dict:
910 # we remove all the key : value we don't care and match only
911 # respected field
sousaedu80135b92021-02-17 15:05:18 +0100912 filtered_dict = set(filter_entry.keys()) - set(
913 filter_dict
914 )
915
beierlb22ce2d2019-12-12 12:09:51 -0500916 for unwanted_key in filtered_dict:
917 del filter_entry[unwanted_key]
sousaedu80135b92021-02-17 15:05:18 +0100918
kasarc5bf2932018-03-09 04:15:22 -0800919 if filter_dict == filter_entry:
920 network_list.append(filtered_entry)
921 else:
922 network_list.append(filtered_entry)
923 except Exception as e:
beierlb22ce2d2019-12-12 12:09:51 -0500924 self.logger.debug("Error in get_network_list", exc_info=True)
sousaedu80135b92021-02-17 15:05:18 +0100925
tierno72774862020-05-04 11:44:15 +0000926 if isinstance(e, vimconn.VimConnException):
kasarc5bf2932018-03-09 04:15:22 -0800927 raise
928 else:
sousaedu80135b92021-02-17 15:05:18 +0100929 raise vimconn.VimConnNotFoundException(
930 "Failed : Networks list not found {} ".format(e)
931 )
bayramov325fa1c2016-09-08 01:42:46 -0700932
933 self.logger.debug("Returning {}".format(network_list))
sousaedu80135b92021-02-17 15:05:18 +0100934
bayramov325fa1c2016-09-08 01:42:46 -0700935 return network_list
936
937 def get_network(self, net_id):
bayramovfe3f3c92016-10-04 07:53:41 +0400938 """Method obtains network details of net_id VIM network
sousaedu80135b92021-02-17 15:05:18 +0100939 Return a dict with the fields at filter_dict (see get_network_list) plus some VIM specific>}, ...]"""
bayramovef390722016-09-27 03:34:46 -0700940 try:
beierlb22ce2d2019-12-12 12:09:51 -0500941 _, vdc = self.get_vdc_details()
sousaedu80135b92021-02-17 15:05:18 +0100942 vdc_id = vdc.get("id").split(":")[3]
943
kasarc5bf2932018-03-09 04:15:22 -0800944 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +0100945 headers = {
946 "Accept": "application/*+xml;version=" + API_VERSION,
947 "x-vcloud-authorization": self.client._session.headers[
948 "x-vcloud-authorization"
949 ],
950 }
951 response = self.perform_request(
952 req_type="GET", url=vdc.get("href"), headers=headers
953 )
954
kasarc5bf2932018-03-09 04:15:22 -0800955 if response.status_code != 200:
956 self.logger.error("Failed to get vdc content")
tierno72774862020-05-04 11:44:15 +0000957 raise vimconn.VimConnNotFoundException("Failed to get vdc content")
kasarc5bf2932018-03-09 04:15:22 -0800958 else:
beierl26fec002019-12-06 17:06:40 -0500959 content = XmlElementTree.fromstring(response.text)
bhangarebfdca492017-03-11 01:32:46 -0800960
bhangarebfdca492017-03-11 01:32:46 -0800961 filter_dict = {}
962
kasarc5bf2932018-03-09 04:15:22 -0800963 for item in content:
sousaedu80135b92021-02-17 15:05:18 +0100964 if item.tag.split("}")[-1] == "AvailableNetworks":
kasarc5bf2932018-03-09 04:15:22 -0800965 for net in item:
sousaedu80135b92021-02-17 15:05:18 +0100966 response = self.perform_request(
967 req_type="GET", url=net.get("href"), headers=headers
968 )
kasarc30a04e2017-08-24 05:58:18 -0700969
kasarc5bf2932018-03-09 04:15:22 -0800970 if response.status_code != 200:
971 self.logger.error("Failed to get network content")
sousaedu80135b92021-02-17 15:05:18 +0100972 raise vimconn.VimConnNotFoundException(
973 "Failed to get network content"
974 )
kasarc5bf2932018-03-09 04:15:22 -0800975 else:
beierl26fec002019-12-06 17:06:40 -0500976 net_details = XmlElementTree.fromstring(response.text)
kasarc5bf2932018-03-09 04:15:22 -0800977
sousaedu80135b92021-02-17 15:05:18 +0100978 vdc_network_id = net_details.get("id").split(":")
kasarc5bf2932018-03-09 04:15:22 -0800979 if len(vdc_network_id) == 4 and vdc_network_id[3] == net_id:
sousaedu80135b92021-02-17 15:05:18 +0100980 filter_dict["name"] = net_details.get("name")
kasarc5bf2932018-03-09 04:15:22 -0800981 filter_dict["id"] = vdc_network_id[3]
sousaedu80135b92021-02-17 15:05:18 +0100982
983 if [
984 i.text
985 for i in net_details
986 if i.tag.split("}")[-1] == "IsShared"
987 ][0] == "true":
kasarc5bf2932018-03-09 04:15:22 -0800988 shared = True
989 else:
990 shared = False
sousaedu80135b92021-02-17 15:05:18 +0100991
kasarc5bf2932018-03-09 04:15:22 -0800992 filter_dict["shared"] = shared
993 filter_dict["tenant_id"] = vdc_id
sousaedu80135b92021-02-17 15:05:18 +0100994
995 if int(net_details.get("status")) == 1:
kasarc5bf2932018-03-09 04:15:22 -0800996 filter_dict["admin_state_up"] = True
997 else:
998 filter_dict["admin_state_up"] = False
sousaedu80135b92021-02-17 15:05:18 +0100999
kasarc5bf2932018-03-09 04:15:22 -08001000 filter_dict["status"] = "ACTIVE"
1001 filter_dict["type"] = "bridge"
1002 self.logger.debug("Returning {}".format(filter_dict))
sousaedu80135b92021-02-17 15:05:18 +01001003
kasarc5bf2932018-03-09 04:15:22 -08001004 return filter_dict
bayramovef390722016-09-27 03:34:46 -07001005 else:
sousaedu80135b92021-02-17 15:05:18 +01001006 raise vimconn.VimConnNotFoundException(
1007 "Network {} not found".format(net_id)
1008 )
kasarc30a04e2017-08-24 05:58:18 -07001009 except Exception as e:
bayramovef390722016-09-27 03:34:46 -07001010 self.logger.debug("Error in get_network")
1011 self.logger.debug(traceback.format_exc())
sousaedu80135b92021-02-17 15:05:18 +01001012
tierno72774862020-05-04 11:44:15 +00001013 if isinstance(e, vimconn.VimConnException):
kasarc30a04e2017-08-24 05:58:18 -07001014 raise
1015 else:
sousaedu80135b92021-02-17 15:05:18 +01001016 raise vimconn.VimConnNotFoundException(
1017 "Failed : Network not found {} ".format(e)
1018 )
bayramovef390722016-09-27 03:34:46 -07001019
1020 return filter_dict
bayramov325fa1c2016-09-08 01:42:46 -07001021
garciadeblasebd66722019-01-31 16:01:31 +00001022 def delete_network(self, net_id, created_items=None):
bayramovef390722016-09-27 03:34:46 -07001023 """
garciadeblasebd66722019-01-31 16:01:31 +00001024 Removes a tenant network from VIM and its associated elements
1025 :param net_id: VIM identifier of the network, provided by method new_network
1026 :param created_items: dictionary with extra items to be deleted. provided by method new_network
1027 Returns the network identifier or raises an exception upon error or when network is not found
bayramovef390722016-09-27 03:34:46 -07001028 """
1029
kateac1e3792017-04-01 02:16:39 -07001030 # ############# Stub code for SRIOV #################
sousaedu80135b92021-02-17 15:05:18 +01001031 # dvport_group = self.get_dvport_group(net_id)
1032 # if dvport_group:
1033 # #delete portgroup
1034 # status = self.destroy_dvport_group(net_id)
1035 # if status:
1036 # # Remove vlanID from persistent info
1037 # if net_id in self.persistent_info["used_vlanIDs"]:
1038 # del self.persistent_info["used_vlanIDs"][net_id]
1039 #
1040 # return net_id
kateac1e3792017-04-01 02:16:39 -07001041
bayramovfe3f3c92016-10-04 07:53:41 +04001042 vcd_network = self.get_vcd_network(network_uuid=net_id)
1043 if vcd_network is not None and vcd_network:
1044 if self.delete_network_action(network_uuid=net_id):
1045 return net_id
bayramovef390722016-09-27 03:34:46 -07001046 else:
sousaedu80135b92021-02-17 15:05:18 +01001047 raise vimconn.VimConnNotFoundException(
1048 "Network {} not found".format(net_id)
1049 )
bayramov325fa1c2016-09-08 01:42:46 -07001050
1051 def refresh_nets_status(self, net_list):
bayramovbd6160f2016-09-28 04:12:05 +04001052 """Get the status of the networks
sousaedu80135b92021-02-17 15:05:18 +01001053 Params: the list of network identifiers
1054 Returns a dictionary with:
1055 net_id: #VIM id of this network
1056 status: #Mandatory. Text with one of:
1057 # DELETED (not found at vim)
1058 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
1059 # OTHER (Vim reported other status not understood)
1060 # ERROR (VIM indicates an ERROR status)
1061 # ACTIVE, INACTIVE, DOWN (admin down),
1062 # BUILD (on building process)
1063 #
1064 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
1065 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
bayramov325fa1c2016-09-08 01:42:46 -07001066
bayramovbd6160f2016-09-28 04:12:05 +04001067 """
bayramovef390722016-09-27 03:34:46 -07001068 dict_entry = {}
1069 try:
1070 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01001071 errormsg = ""
bayramovef390722016-09-27 03:34:46 -07001072 vcd_network = self.get_vcd_network(network_uuid=net)
bayramovfe3f3c92016-10-04 07:53:41 +04001073 if vcd_network is not None and vcd_network:
sousaedu80135b92021-02-17 15:05:18 +01001074 if vcd_network["status"] == "1":
1075 status = "ACTIVE"
bayramovef390722016-09-27 03:34:46 -07001076 else:
sousaedu80135b92021-02-17 15:05:18 +01001077 status = "DOWN"
bayramovef390722016-09-27 03:34:46 -07001078 else:
sousaedu80135b92021-02-17 15:05:18 +01001079 status = "DELETED"
1080 errormsg = "Network not found."
bayramovfe3f3c92016-10-04 07:53:41 +04001081
sousaedu80135b92021-02-17 15:05:18 +01001082 dict_entry[net] = {
1083 "status": status,
1084 "error_msg": errormsg,
1085 "vim_info": yaml.safe_dump(vcd_network),
1086 }
beierlb22ce2d2019-12-12 12:09:51 -05001087 except Exception:
bayramovef390722016-09-27 03:34:46 -07001088 self.logger.debug("Error in refresh_nets_status")
1089 self.logger.debug(traceback.format_exc())
1090
1091 return dict_entry
1092
bayramovbd6160f2016-09-28 04:12:05 +04001093 def get_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -07001094 """Obtain flavor details from the VIM
sousaedu80135b92021-02-17 15:05:18 +01001095 Returns the flavor dict details {'id':<>, 'name':<>, other vim specific } #TODO to concrete
bayramovef390722016-09-27 03:34:46 -07001096 """
kateeb044522017-03-06 23:54:39 -08001097 if flavor_id not in vimconnector.flavorlist:
tierno72774862020-05-04 11:44:15 +00001098 raise vimconn.VimConnNotFoundException("Flavor not found.")
sousaedu80135b92021-02-17 15:05:18 +01001099
kateeb044522017-03-06 23:54:39 -08001100 return vimconnector.flavorlist[flavor_id]
bayramov325fa1c2016-09-08 01:42:46 -07001101
1102 def new_flavor(self, flavor_data):
bayramovef390722016-09-27 03:34:46 -07001103 """Adds a tenant flavor to VIM
bayramov325fa1c2016-09-08 01:42:46 -07001104 flavor_data contains a dictionary with information, keys:
1105 name: flavor name
1106 ram: memory (cloud type) in MBytes
1107 vpcus: cpus (cloud type)
1108 extended: EPA parameters
1109 - numas: #items requested in same NUMA
1110 memory: number of 1G huge pages memory
beierlb22ce2d2019-12-12 12:09:51 -05001111 paired-threads|cores|threads: number of paired hyperthreads, complete cores OR individual
1112 threads
bayramov325fa1c2016-09-08 01:42:46 -07001113 interfaces: # passthrough(PT) or SRIOV interfaces attached to this numa
1114 - name: interface name
1115 dedicated: yes|no|yes:sriov; for PT, SRIOV or only one SRIOV for the physical NIC
1116 bandwidth: X Gbps; requested guarantee bandwidth
bayramovef390722016-09-27 03:34:46 -07001117 vpci: requested virtual PCI address
bayramov325fa1c2016-09-08 01:42:46 -07001118 disk: disk size
1119 is_public:
bayramov325fa1c2016-09-08 01:42:46 -07001120 #TODO to concrete
bayramovef390722016-09-27 03:34:46 -07001121 Returns the flavor identifier"""
bayramov325fa1c2016-09-08 01:42:46 -07001122
bayramovef390722016-09-27 03:34:46 -07001123 # generate a new uuid put to internal dict and return it.
bhangarea92ae392017-01-12 22:30:29 -08001124 self.logger.debug("Creating new flavor - flavor_data: {}".format(flavor_data))
beierlb22ce2d2019-12-12 12:09:51 -05001125 new_flavor = flavor_data
bhangarea92ae392017-01-12 22:30:29 -08001126 ram = flavor_data.get(FLAVOR_RAM_KEY, 1024)
1127 cpu = flavor_data.get(FLAVOR_VCPUS_KEY, 1)
garciadeblas79d1a1a2017-12-11 16:07:07 +01001128 disk = flavor_data.get(FLAVOR_DISK_KEY, 0)
bhangarea92ae392017-01-12 22:30:29 -08001129
kasarfeaaa052017-06-08 03:46:18 -07001130 if not isinstance(ram, int):
tierno72774862020-05-04 11:44:15 +00001131 raise vimconn.VimConnException("Non-integer value for ram")
kasarfeaaa052017-06-08 03:46:18 -07001132 elif not isinstance(cpu, int):
tierno72774862020-05-04 11:44:15 +00001133 raise vimconn.VimConnException("Non-integer value for cpu")
kasarfeaaa052017-06-08 03:46:18 -07001134 elif not isinstance(disk, int):
tierno72774862020-05-04 11:44:15 +00001135 raise vimconn.VimConnException("Non-integer value for disk")
kasarfeaaa052017-06-08 03:46:18 -07001136
bhangarea92ae392017-01-12 22:30:29 -08001137 extended_flv = flavor_data.get("extended")
1138 if extended_flv:
beierlb22ce2d2019-12-12 12:09:51 -05001139 numas = extended_flv.get("numas")
bhangarea92ae392017-01-12 22:30:29 -08001140 if numas:
1141 for numa in numas:
beierlb22ce2d2019-12-12 12:09:51 -05001142 # overwrite ram and vcpus
sousaedu80135b92021-02-17 15:05:18 +01001143 if "memory" in numa:
1144 ram = numa["memory"] * 1024
1145
1146 if "paired-threads" in numa:
1147 cpu = numa["paired-threads"] * 2
1148 elif "cores" in numa:
1149 cpu = numa["cores"]
1150 elif "threads" in numa:
1151 cpu = numa["threads"]
bhangarea92ae392017-01-12 22:30:29 -08001152
1153 new_flavor[FLAVOR_RAM_KEY] = ram
1154 new_flavor[FLAVOR_VCPUS_KEY] = cpu
1155 new_flavor[FLAVOR_DISK_KEY] = disk
1156 # generate a new uuid put to internal dict and return it.
bayramovef390722016-09-27 03:34:46 -07001157 flavor_id = uuid.uuid4()
kateeb044522017-03-06 23:54:39 -08001158 vimconnector.flavorlist[str(flavor_id)] = new_flavor
bhangarea92ae392017-01-12 22:30:29 -08001159 self.logger.debug("Created flavor - {} : {}".format(flavor_id, new_flavor))
bayramov325fa1c2016-09-08 01:42:46 -07001160
bayramovef390722016-09-27 03:34:46 -07001161 return str(flavor_id)
bayramov325fa1c2016-09-08 01:42:46 -07001162
1163 def delete_flavor(self, flavor_id):
bayramovef390722016-09-27 03:34:46 -07001164 """Deletes a tenant flavor from VIM identify by its id
bayramov325fa1c2016-09-08 01:42:46 -07001165
sousaedu80135b92021-02-17 15:05:18 +01001166 Returns the used id or raise an exception
bayramovef390722016-09-27 03:34:46 -07001167 """
kateeb044522017-03-06 23:54:39 -08001168 if flavor_id not in vimconnector.flavorlist:
tierno72774862020-05-04 11:44:15 +00001169 raise vimconn.VimConnNotFoundException("Flavor not found.")
bayramovef390722016-09-27 03:34:46 -07001170
kateeb044522017-03-06 23:54:39 -08001171 vimconnector.flavorlist.pop(flavor_id, None)
sousaedu80135b92021-02-17 15:05:18 +01001172
bayramovef390722016-09-27 03:34:46 -07001173 return flavor_id
1174
1175 def new_image(self, image_dict):
bayramov5761ad12016-10-04 09:00:30 +04001176 """
bayramov325fa1c2016-09-08 01:42:46 -07001177 Adds a tenant image to VIM
1178 Returns:
1179 200, image-id if the image is created
1180 <0, message if there is an error
bayramov5761ad12016-10-04 09:00:30 +04001181 """
sousaedu80135b92021-02-17 15:05:18 +01001182 return self.get_image_id_from_path(image_dict["location"])
bayramov325fa1c2016-09-08 01:42:46 -07001183
1184 def delete_image(self, image_id):
bayramovfe3f3c92016-10-04 07:53:41 +04001185 """
sousaedu80135b92021-02-17 15:05:18 +01001186 Deletes a tenant image from VIM
1187 Args:
1188 image_id is ID of Image to be deleted
1189 Return:
1190 returns the image identifier in UUID format or raises an exception on error
bayramovfe3f3c92016-10-04 07:53:41 +04001191 """
kasarc5bf2932018-03-09 04:15:22 -08001192 conn = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01001193
kasarc5bf2932018-03-09 04:15:22 -08001194 if not conn:
tierno72774862020-05-04 11:44:15 +00001195 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu80135b92021-02-17 15:05:18 +01001196
kated47ad5f2017-08-03 02:16:13 -07001197 # Get Catalog details
sousaedu80135b92021-02-17 15:05:18 +01001198 url_list = [self.url, "/api/catalog/", image_id]
1199 catalog_herf = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08001200
sousaedu80135b92021-02-17 15:05:18 +01001201 headers = {
1202 "Accept": "application/*+xml;version=" + API_VERSION,
1203 "x-vcloud-authorization": conn._session.headers["x-vcloud-authorization"],
1204 }
kasarc5bf2932018-03-09 04:15:22 -08001205
sousaedu80135b92021-02-17 15:05:18 +01001206 response = self.perform_request(
1207 req_type="GET", url=catalog_herf, headers=headers
1208 )
bayramovfe3f3c92016-10-04 07:53:41 +04001209
kated47ad5f2017-08-03 02:16:13 -07001210 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001211 self.logger.debug(
1212 "delete_image():GET REST API call {} failed. "
1213 "Return status code {}".format(catalog_herf, response.status_code)
1214 )
1215
1216 raise vimconn.VimConnNotFoundException(
1217 "Fail to get image {}".format(image_id)
1218 )
kated47ad5f2017-08-03 02:16:13 -07001219
beierl01bd6692019-12-09 17:06:20 -05001220 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01001221 namespaces = {
1222 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
1223 }
beierl01bd6692019-12-09 17:06:20 -05001224 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
kated47ad5f2017-08-03 02:16:13 -07001225
beierl01bd6692019-12-09 17:06:20 -05001226 catalogItems_section = lxmlroot_respond.find("xmlns:CatalogItems", namespaces)
1227 catalogItems = catalogItems_section.iterfind("xmlns:CatalogItem", namespaces)
kated47ad5f2017-08-03 02:16:13 -07001228
sousaedu80135b92021-02-17 15:05:18 +01001229 for catalogItem in catalogItems:
1230 catalogItem_href = catalogItem.attrib["href"]
1231
1232 response = self.perform_request(
1233 req_type="GET", url=catalogItem_href, headers=headers
1234 )
kated47ad5f2017-08-03 02:16:13 -07001235
1236 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001237 self.logger.debug(
1238 "delete_image():GET REST API call {} failed. "
1239 "Return status code {}".format(catalog_herf, response.status_code)
1240 )
1241 raise vimconn.VimConnNotFoundException(
1242 "Fail to get catalogItem {} for catalog {}".format(
1243 catalogItem, image_id
1244 )
1245 )
kated47ad5f2017-08-03 02:16:13 -07001246
beierl01bd6692019-12-09 17:06:20 -05001247 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01001248 namespaces = {
1249 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
1250 }
beierl01bd6692019-12-09 17:06:20 -05001251 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
sousaedu80135b92021-02-17 15:05:18 +01001252 catalogitem_remove_href = lxmlroot_respond.find(
1253 "xmlns:Link[@rel='remove']", namespaces
1254 ).attrib["href"]
kated47ad5f2017-08-03 02:16:13 -07001255
beierl01bd6692019-12-09 17:06:20 -05001256 # Remove catalogItem
sousaedu80135b92021-02-17 15:05:18 +01001257 response = self.perform_request(
1258 req_type="DELETE", url=catalogitem_remove_href, headers=headers
1259 )
1260
kated47ad5f2017-08-03 02:16:13 -07001261 if response.status_code == requests.codes.no_content:
1262 self.logger.debug("Deleted Catalog item {}".format(catalogItem))
1263 else:
sousaedu80135b92021-02-17 15:05:18 +01001264 raise vimconn.VimConnException(
1265 "Fail to delete Catalog Item {}".format(catalogItem)
1266 )
kated47ad5f2017-08-03 02:16:13 -07001267
beierl01bd6692019-12-09 17:06:20 -05001268 # Remove catalog
sousaedu80135b92021-02-17 15:05:18 +01001269 url_list = [self.url, "/api/admin/catalog/", image_id]
1270 catalog_remove_herf = "".join(url_list)
1271 response = self.perform_request(
1272 req_type="DELETE", url=catalog_remove_herf, headers=headers
1273 )
kated47ad5f2017-08-03 02:16:13 -07001274
1275 if response.status_code == requests.codes.no_content:
1276 self.logger.debug("Deleted Catalog {}".format(image_id))
sousaedu80135b92021-02-17 15:05:18 +01001277
kated47ad5f2017-08-03 02:16:13 -07001278 return image_id
1279 else:
tierno72774862020-05-04 11:44:15 +00001280 raise vimconn.VimConnException("Fail to delete Catalog {}".format(image_id))
kated47ad5f2017-08-03 02:16:13 -07001281
bayramov325fa1c2016-09-08 01:42:46 -07001282 def catalog_exists(self, catalog_name, catalogs):
bayramovfe3f3c92016-10-04 07:53:41 +04001283 """
1284
1285 :param catalog_name:
1286 :param catalogs:
1287 :return:
1288 """
bayramov325fa1c2016-09-08 01:42:46 -07001289 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001290 if catalog["name"] == catalog_name:
1291 return catalog["id"]
bayramov325fa1c2016-09-08 01:42:46 -07001292
bayramovb6ffe792016-09-28 11:50:56 +04001293 def create_vimcatalog(self, vca=None, catalog_name=None):
sousaedu80135b92021-02-17 15:05:18 +01001294 """Create new catalog entry in vCloud director.
bayramovb6ffe792016-09-28 11:50:56 +04001295
sousaedu80135b92021-02-17 15:05:18 +01001296 Args
1297 vca: vCloud director.
1298 catalog_name catalog that client wish to create. Note no validation done for a name.
1299 Client must make sure that provide valid string representation.
bayramovb6ffe792016-09-28 11:50:56 +04001300
sousaedu80135b92021-02-17 15:05:18 +01001301 Returns catalog id if catalog created else None.
bayramovb6ffe792016-09-28 11:50:56 +04001302
1303 """
1304 try:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001305 lxml_catalog_element = vca.create_catalog(catalog_name, catalog_name)
sousaedu80135b92021-02-17 15:05:18 +01001306
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001307 if lxml_catalog_element:
sousaedu80135b92021-02-17 15:05:18 +01001308 id_attr_value = lxml_catalog_element.get("id")
1309 return id_attr_value.split(":")[-1]
1310
kasarc5bf2932018-03-09 04:15:22 -08001311 catalogs = vca.list_catalogs()
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001312 except Exception as ex:
1313 self.logger.error(
sousaedu80135b92021-02-17 15:05:18 +01001314 'create_vimcatalog(): Creation of catalog "{}" failed with error: {}'.format(
1315 catalog_name, ex
1316 )
1317 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001318 raise
bayramov325fa1c2016-09-08 01:42:46 -07001319 return self.catalog_exists(catalog_name, catalogs)
1320
bayramov5761ad12016-10-04 09:00:30 +04001321 # noinspection PyIncorrectDocstring
sousaedu80135b92021-02-17 15:05:18 +01001322 def upload_ovf(
1323 self,
1324 vca=None,
1325 catalog_name=None,
1326 image_name=None,
1327 media_file_name=None,
1328 description="",
1329 progress=False,
1330 chunk_bytes=128 * 1024,
1331 ):
bayramov325fa1c2016-09-08 01:42:46 -07001332 """
1333 Uploads a OVF file to a vCloud catalog
1334
bayramov5761ad12016-10-04 09:00:30 +04001335 :param chunk_bytes:
1336 :param progress:
1337 :param description:
1338 :param image_name:
1339 :param vca:
bayramov325fa1c2016-09-08 01:42:46 -07001340 :param catalog_name: (str): The name of the catalog to upload the media.
bayramov325fa1c2016-09-08 01:42:46 -07001341 :param media_file_name: (str): The name of the local media file to upload.
1342 :return: (bool) True if the media file was successfully uploaded, false otherwise.
1343 """
1344 os.path.isfile(media_file_name)
1345 statinfo = os.stat(media_file_name)
bayramov325fa1c2016-09-08 01:42:46 -07001346
1347 # find a catalog entry where we upload OVF.
1348 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
1349 # status change.
1350 # if VCD can parse OVF we upload VMDK file
bhangarebfdca492017-03-11 01:32:46 -08001351 try:
kasarc5bf2932018-03-09 04:15:22 -08001352 for catalog in vca.list_catalogs():
sousaedu80135b92021-02-17 15:05:18 +01001353 if catalog_name != catalog["name"]:
bhangarebfdca492017-03-11 01:32:46 -08001354 continue
sousaedu80135b92021-02-17 15:05:18 +01001355 catalog_href = "{}/api/catalog/{}/action/upload".format(
1356 self.url, catalog["id"]
1357 )
bhangarebfdca492017-03-11 01:32:46 -08001358 data = """
beierlb22ce2d2019-12-12 12:09:51 -05001359 <UploadVAppTemplateParams name="{}"
1360 xmlns="http://www.vmware.com/vcloud/v1.5"
1361 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1">
1362 <Description>{} vApp Template</Description>
1363 </UploadVAppTemplateParams>
sousaedu80135b92021-02-17 15:05:18 +01001364 """.format(
1365 catalog_name, description
1366 )
kasarc5bf2932018-03-09 04:15:22 -08001367
1368 if self.client:
sousaedu80135b92021-02-17 15:05:18 +01001369 headers = {
1370 "Accept": "application/*+xml;version=" + API_VERSION,
1371 "x-vcloud-authorization": self.client._session.headers[
1372 "x-vcloud-authorization"
1373 ],
1374 }
1375 headers[
1376 "Content-Type"
1377 ] = "application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml"
kasarc5bf2932018-03-09 04:15:22 -08001378
sousaedu80135b92021-02-17 15:05:18 +01001379 response = self.perform_request(
1380 req_type="POST", url=catalog_href, headers=headers, data=data
1381 )
kasarc5bf2932018-03-09 04:15:22 -08001382
bhangarebfdca492017-03-11 01:32:46 -08001383 if response.status_code == requests.codes.created:
beierl26fec002019-12-06 17:06:40 -05001384 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01001385 entity = [
1386 child
1387 for child in catalogItem
1388 if child.get("type")
1389 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
1390 ][0]
1391 href = entity.get("href")
bhangarebfdca492017-03-11 01:32:46 -08001392 template = href
kasarc5bf2932018-03-09 04:15:22 -08001393
sousaedu80135b92021-02-17 15:05:18 +01001394 response = self.perform_request(
1395 req_type="GET", url=href, headers=headers
1396 )
bhangarebfdca492017-03-11 01:32:46 -08001397
1398 if response.status_code == requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001399 headers["Content-Type"] = "Content-Type text/xml"
1400 result = re.search(
1401 'rel="upload:default"\shref="(.*?\/descriptor.ovf)"',
1402 response.text,
1403 )
1404
kasarc5bf2932018-03-09 04:15:22 -08001405 if result:
1406 transfer_href = result.group(1)
1407
sousaedu80135b92021-02-17 15:05:18 +01001408 response = self.perform_request(
1409 req_type="PUT",
1410 url=transfer_href,
1411 headers=headers,
1412 data=open(media_file_name, "rb"),
1413 )
1414
bhangarebfdca492017-03-11 01:32:46 -08001415 if response.status_code != requests.codes.ok:
1416 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01001417 "Failed create vApp template for catalog name {} and image {}".format(
1418 catalog_name, media_file_name
1419 )
1420 )
bhangarebfdca492017-03-11 01:32:46 -08001421 return False
1422
1423 # TODO fix this with aync block
1424 time.sleep(5)
1425
sousaedu80135b92021-02-17 15:05:18 +01001426 self.logger.debug(
1427 "vApp template for catalog name {} and image {}".format(
1428 catalog_name, media_file_name
1429 )
1430 )
bhangarebfdca492017-03-11 01:32:46 -08001431
1432 # uploading VMDK file
1433 # check status of OVF upload and upload remaining files.
sousaedu80135b92021-02-17 15:05:18 +01001434 response = self.perform_request(
1435 req_type="GET", url=template, headers=headers
1436 )
bhangarebfdca492017-03-11 01:32:46 -08001437
1438 if response.status_code == requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01001439 result = re.search(
1440 'rel="upload:default"\s*href="(.*?vmdk)"', response.text
1441 )
1442
kasarc5bf2932018-03-09 04:15:22 -08001443 if result:
1444 link_href = result.group(1)
sousaedu80135b92021-02-17 15:05:18 +01001445
kasarc5bf2932018-03-09 04:15:22 -08001446 # we skip ovf since it already uploaded.
sousaedu80135b92021-02-17 15:05:18 +01001447 if "ovf" in link_href:
kasarc5bf2932018-03-09 04:15:22 -08001448 continue
sousaedu80135b92021-02-17 15:05:18 +01001449
kasarc5bf2932018-03-09 04:15:22 -08001450 # The OVF file and VMDK must be in a same directory
beierlb22ce2d2019-12-12 12:09:51 -05001451 head, _ = os.path.split(media_file_name)
sousaedu80135b92021-02-17 15:05:18 +01001452 file_vmdk = head + "/" + link_href.split("/")[-1]
1453
kasarc5bf2932018-03-09 04:15:22 -08001454 if not os.path.isfile(file_vmdk):
1455 return False
sousaedu80135b92021-02-17 15:05:18 +01001456
kasarc5bf2932018-03-09 04:15:22 -08001457 statinfo = os.stat(file_vmdk)
1458 if statinfo.st_size == 0:
1459 return False
sousaedu80135b92021-02-17 15:05:18 +01001460
kasarc5bf2932018-03-09 04:15:22 -08001461 hrefvmdk = link_href
1462
1463 if progress:
sousaedu80135b92021-02-17 15:05:18 +01001464 widgets = [
1465 "Uploading file: ",
1466 Percentage(),
1467 " ",
1468 Bar(),
1469 " ",
1470 ETA(),
1471 " ",
1472 FileTransferSpeed(),
1473 ]
1474 progress_bar = ProgressBar(
1475 widgets=widgets, maxval=statinfo.st_size
1476 ).start()
kasarc5bf2932018-03-09 04:15:22 -08001477
1478 bytes_transferred = 0
sousaedu80135b92021-02-17 15:05:18 +01001479 f = open(file_vmdk, "rb")
1480
kasarc5bf2932018-03-09 04:15:22 -08001481 while bytes_transferred < statinfo.st_size:
1482 my_bytes = f.read(chunk_bytes)
1483 if len(my_bytes) <= chunk_bytes:
sousaedu80135b92021-02-17 15:05:18 +01001484 headers["Content-Range"] = "bytes {}-{}/{}".format(
1485 bytes_transferred,
1486 len(my_bytes) - 1,
1487 statinfo.st_size,
1488 )
1489 headers["Content-Length"] = str(len(my_bytes))
1490 response = requests.put(
1491 url=hrefvmdk,
1492 headers=headers,
1493 data=my_bytes,
1494 verify=False,
1495 )
1496
kasarc5bf2932018-03-09 04:15:22 -08001497 if response.status_code == requests.codes.ok:
1498 bytes_transferred += len(my_bytes)
1499 if progress:
1500 progress_bar.update(bytes_transferred)
1501 else:
1502 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01001503 "file upload failed with error: [{}] {}".format(
1504 response.status_code, response.text
1505 )
1506 )
kasarc5bf2932018-03-09 04:15:22 -08001507
1508 f.close()
sousaedu80135b92021-02-17 15:05:18 +01001509
bhangarebfdca492017-03-11 01:32:46 -08001510 return False
sousaedu80135b92021-02-17 15:05:18 +01001511
kasarc5bf2932018-03-09 04:15:22 -08001512 f.close()
1513 if progress:
1514 progress_bar.finish()
1515 time.sleep(10)
sousaedu80135b92021-02-17 15:05:18 +01001516
kasarc5bf2932018-03-09 04:15:22 -08001517 return True
1518 else:
sousaedu80135b92021-02-17 15:05:18 +01001519 self.logger.debug(
1520 "Failed retrieve vApp template for catalog name {} for OVF {}".format(
1521 catalog_name, media_file_name
1522 )
1523 )
kasarc5bf2932018-03-09 04:15:22 -08001524 return False
bhangarebfdca492017-03-11 01:32:46 -08001525 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01001526 self.logger.debug(
1527 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}".format(
1528 catalog_name, media_file_name, exp
1529 )
1530 )
bayramov325fa1c2016-09-08 01:42:46 -07001531
sousaedu80135b92021-02-17 15:05:18 +01001532 raise vimconn.VimConnException(
1533 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}".format(
1534 catalog_name, media_file_name, exp
1535 )
1536 )
1537
1538 self.logger.debug(
1539 "Failed retrieve catalog name {} for OVF file {}".format(
1540 catalog_name, media_file_name
1541 )
1542 )
1543
bayramov325fa1c2016-09-08 01:42:46 -07001544 return False
1545
sousaedu80135b92021-02-17 15:05:18 +01001546 def upload_vimimage(
1547 self,
1548 vca=None,
1549 catalog_name=None,
1550 media_name=None,
1551 medial_file_name=None,
1552 progress=False,
1553 ):
bayramov325fa1c2016-09-08 01:42:46 -07001554 """Upload media file"""
bayramovfe3f3c92016-10-04 07:53:41 +04001555 # TODO add named parameters for readability
sousaedu80135b92021-02-17 15:05:18 +01001556 return self.upload_ovf(
1557 vca=vca,
1558 catalog_name=catalog_name,
1559 image_name=media_name.split(".")[0],
1560 media_file_name=medial_file_name,
1561 description="medial_file_name",
1562 progress=progress,
1563 )
bayramov325fa1c2016-09-08 01:42:46 -07001564
bayramovb6ffe792016-09-28 11:50:56 +04001565 def validate_uuid4(self, uuid_string=None):
sousaedu80135b92021-02-17 15:05:18 +01001566 """Method validate correct format of UUID.
bayramovb6ffe792016-09-28 11:50:56 +04001567
1568 Return: true if string represent valid uuid
1569 """
1570 try:
beierlb22ce2d2019-12-12 12:09:51 -05001571 uuid.UUID(uuid_string, version=4)
bayramovb6ffe792016-09-28 11:50:56 +04001572 except ValueError:
1573 return False
sousaedu80135b92021-02-17 15:05:18 +01001574
bayramovb6ffe792016-09-28 11:50:56 +04001575 return True
1576
1577 def get_catalogid(self, catalog_name=None, catalogs=None):
sousaedu80135b92021-02-17 15:05:18 +01001578 """Method check catalog and return catalog ID in UUID format.
bayramovb6ffe792016-09-28 11:50:56 +04001579
1580 Args
1581 catalog_name: catalog name as string
1582 catalogs: list of catalogs.
1583
1584 Return: catalogs uuid
1585 """
bayramov325fa1c2016-09-08 01:42:46 -07001586 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001587 if catalog["name"] == catalog_name:
1588 catalog_id = catalog["id"]
kasarc5bf2932018-03-09 04:15:22 -08001589 return catalog_id
sousaedu80135b92021-02-17 15:05:18 +01001590
bayramov325fa1c2016-09-08 01:42:46 -07001591 return None
1592
bayramovb6ffe792016-09-28 11:50:56 +04001593 def get_catalogbyid(self, catalog_uuid=None, catalogs=None):
sousaedu80135b92021-02-17 15:05:18 +01001594 """Method check catalog and return catalog name lookup done by catalog UUID.
bayramovb6ffe792016-09-28 11:50:56 +04001595
1596 Args
1597 catalog_name: catalog name as string
1598 catalogs: list of catalogs.
1599
1600 Return: catalogs name or None
1601 """
bayramovb6ffe792016-09-28 11:50:56 +04001602 if not self.validate_uuid4(uuid_string=catalog_uuid):
1603 return None
1604
bayramov325fa1c2016-09-08 01:42:46 -07001605 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001606 catalog_id = catalog.get("id")
1607
bayramovb6ffe792016-09-28 11:50:56 +04001608 if catalog_id == catalog_uuid:
sousaedu80135b92021-02-17 15:05:18 +01001609 return catalog.get("name")
1610
bayramov325fa1c2016-09-08 01:42:46 -07001611 return None
1612
bhangare06312472017-03-30 05:49:07 -07001613 def get_catalog_obj(self, catalog_uuid=None, catalogs=None):
sousaedu80135b92021-02-17 15:05:18 +01001614 """Method check catalog and return catalog name lookup done by catalog UUID.
bhangare06312472017-03-30 05:49:07 -07001615
1616 Args
1617 catalog_name: catalog name as string
1618 catalogs: list of catalogs.
1619
1620 Return: catalogs name or None
1621 """
bhangare06312472017-03-30 05:49:07 -07001622 if not self.validate_uuid4(uuid_string=catalog_uuid):
1623 return None
1624
1625 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001626 catalog_id = catalog.get("id")
1627
bhangare06312472017-03-30 05:49:07 -07001628 if catalog_id == catalog_uuid:
1629 return catalog
sousaedu80135b92021-02-17 15:05:18 +01001630
bhangare06312472017-03-30 05:49:07 -07001631 return None
1632
bayramovfe3f3c92016-10-04 07:53:41 +04001633 def get_image_id_from_path(self, path=None, progress=False):
sousaedu80135b92021-02-17 15:05:18 +01001634 """Method upload OVF image to vCloud director.
bayramov325fa1c2016-09-08 01:42:46 -07001635
bayramovb6ffe792016-09-28 11:50:56 +04001636 Each OVF image represented as single catalog entry in vcloud director.
1637 The method check for existing catalog entry. The check done by file name without file extension.
1638
1639 if given catalog name already present method will respond with existing catalog uuid otherwise
1640 it will create new catalog entry and upload OVF file to newly created catalog.
1641
1642 If method can't create catalog entry or upload a file it will throw exception.
1643
bayramovfe3f3c92016-10-04 07:53:41 +04001644 Method accept boolean flag progress that will output progress bar. It useful method
1645 for standalone upload use case. In case to test large file upload.
1646
bayramovb6ffe792016-09-28 11:50:56 +04001647 Args
bayramovfe3f3c92016-10-04 07:53:41 +04001648 path: - valid path to OVF file.
1649 progress - boolean progress bar show progress bar.
bayramovb6ffe792016-09-28 11:50:56 +04001650
1651 Return: if image uploaded correct method will provide image catalog UUID.
1652 """
kate15f1c382016-12-15 01:12:40 -08001653 if not path:
tierno72774862020-05-04 11:44:15 +00001654 raise vimconn.VimConnException("Image path can't be None.")
bayramovfe3f3c92016-10-04 07:53:41 +04001655
1656 if not os.path.isfile(path):
tierno72774862020-05-04 11:44:15 +00001657 raise vimconn.VimConnException("Can't read file. File not found.")
bayramovfe3f3c92016-10-04 07:53:41 +04001658
1659 if not os.access(path, os.R_OK):
sousaedu80135b92021-02-17 15:05:18 +01001660 raise vimconn.VimConnException(
1661 "Can't read file. Check file permission to read."
1662 )
bayramovfe3f3c92016-10-04 07:53:41 +04001663
1664 self.logger.debug("get_image_id_from_path() client requesting {} ".format(path))
bayramov325fa1c2016-09-08 01:42:46 -07001665
beierlb22ce2d2019-12-12 12:09:51 -05001666 _, filename = os.path.split(path)
1667 _, file_extension = os.path.splitext(path)
sousaedu80135b92021-02-17 15:05:18 +01001668 if file_extension != ".ovf":
1669 self.logger.debug(
1670 "Wrong file extension {} connector support only OVF container.".format(
1671 file_extension
1672 )
1673 )
1674
1675 raise vimconn.VimConnException(
1676 "Wrong container. vCloud director supports only OVF."
1677 )
kate15f1c382016-12-15 01:12:40 -08001678
bayramov325fa1c2016-09-08 01:42:46 -07001679 catalog_name = os.path.splitext(filename)[0]
sousaedu80135b92021-02-17 15:05:18 +01001680 catalog_md5_name = hashlib.md5(path.encode("utf-8")).hexdigest()
1681 self.logger.debug(
1682 "File name {} Catalog Name {} file path {} "
1683 "vdc catalog name {}".format(filename, catalog_name, path, catalog_md5_name)
1684 )
bayramov325fa1c2016-09-08 01:42:46 -07001685
bhangarebfdca492017-03-11 01:32:46 -08001686 try:
beierlb22ce2d2019-12-12 12:09:51 -05001687 org, _ = self.get_vdc_details()
kasarc5bf2932018-03-09 04:15:22 -08001688 catalogs = org.list_catalogs()
bhangarebfdca492017-03-11 01:32:46 -08001689 except Exception as exp:
1690 self.logger.debug("Failed get catalogs() with Exception {} ".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01001691
1692 raise vimconn.VimConnException(
1693 "Failed get catalogs() with Exception {} ".format(exp)
1694 )
bhangarebfdca492017-03-11 01:32:46 -08001695
bayramov325fa1c2016-09-08 01:42:46 -07001696 if len(catalogs) == 0:
sousaedu80135b92021-02-17 15:05:18 +01001697 self.logger.info(
1698 "Creating a new catalog entry {} in vcloud director".format(
1699 catalog_name
1700 )
1701 )
kasarc5bf2932018-03-09 04:15:22 -08001702
sousaedu80135b92021-02-17 15:05:18 +01001703 if self.create_vimcatalog(org, catalog_md5_name) is None:
1704 raise vimconn.VimConnException(
1705 "Failed create new catalog {} ".format(catalog_md5_name)
1706 )
1707
1708 result = self.upload_vimimage(
1709 vca=org,
1710 catalog_name=catalog_md5_name,
1711 media_name=filename,
1712 medial_file_name=path,
1713 progress=progress,
1714 )
1715
bayramov325fa1c2016-09-08 01:42:46 -07001716 if not result:
sousaedu80135b92021-02-17 15:05:18 +01001717 raise vimconn.VimConnException(
1718 "Failed create vApp template for catalog {} ".format(catalog_name)
1719 )
1720
kasarc5bf2932018-03-09 04:15:22 -08001721 return self.get_catalogid(catalog_name, catalogs)
bayramov325fa1c2016-09-08 01:42:46 -07001722 else:
1723 for catalog in catalogs:
1724 # search for existing catalog if we find same name we return ID
1725 # TODO optimize this
sousaedu80135b92021-02-17 15:05:18 +01001726 if catalog["name"] == catalog_md5_name:
1727 self.logger.debug(
1728 "Found existing catalog entry for {} "
1729 "catalog id {}".format(
1730 catalog_name, self.get_catalogid(catalog_md5_name, catalogs)
1731 )
1732 )
1733
kasarc5bf2932018-03-09 04:15:22 -08001734 return self.get_catalogid(catalog_md5_name, catalogs)
bayramov325fa1c2016-09-08 01:42:46 -07001735
bayramovfe3f3c92016-10-04 07:53:41 +04001736 # if we didn't find existing catalog we create a new one and upload image.
sousaedu80135b92021-02-17 15:05:18 +01001737 self.logger.debug(
1738 "Creating new catalog entry {} - {}".format(catalog_name, catalog_md5_name)
1739 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00001740 if self.create_vimcatalog(org, catalog_md5_name) is None:
sousaedu80135b92021-02-17 15:05:18 +01001741 raise vimconn.VimConnException(
1742 "Failed create new catalog {} ".format(catalog_md5_name)
1743 )
bayramovfe3f3c92016-10-04 07:53:41 +04001744
sousaedu80135b92021-02-17 15:05:18 +01001745 result = self.upload_vimimage(
1746 vca=org,
1747 catalog_name=catalog_md5_name,
1748 media_name=filename,
1749 medial_file_name=path,
1750 progress=progress,
1751 )
bayramov325fa1c2016-09-08 01:42:46 -07001752 if not result:
sousaedu80135b92021-02-17 15:05:18 +01001753 raise vimconn.VimConnException(
1754 "Failed create vApp template for catalog {} ".format(catalog_md5_name)
1755 )
bayramov325fa1c2016-09-08 01:42:46 -07001756
kasarc5bf2932018-03-09 04:15:22 -08001757 return self.get_catalogid(catalog_md5_name, org.list_catalogs())
bayramov325fa1c2016-09-08 01:42:46 -07001758
kate8fc61fc2017-01-23 19:57:06 -08001759 def get_image_list(self, filter_dict={}):
sousaedu80135b92021-02-17 15:05:18 +01001760 """Obtain tenant images from VIM
kate8fc61fc2017-01-23 19:57:06 -08001761 Filter_dict can be:
1762 name: image name
1763 id: image uuid
1764 checksum: image checksum
1765 location: image path
1766 Returns the image list of dictionaries:
1767 [{<the fields at Filter_dict plus some VIM specific>}, ...]
1768 List can be empty
sousaedu80135b92021-02-17 15:05:18 +01001769 """
kate8fc61fc2017-01-23 19:57:06 -08001770 try:
beierlb22ce2d2019-12-12 12:09:51 -05001771 org, _ = self.get_vdc_details()
kate8fc61fc2017-01-23 19:57:06 -08001772 image_list = []
kasarc5bf2932018-03-09 04:15:22 -08001773 catalogs = org.list_catalogs()
sousaedu80135b92021-02-17 15:05:18 +01001774
kate8fc61fc2017-01-23 19:57:06 -08001775 if len(catalogs) == 0:
1776 return image_list
1777 else:
1778 for catalog in catalogs:
sousaedu80135b92021-02-17 15:05:18 +01001779 catalog_uuid = catalog.get("id")
1780 name = catalog.get("name")
kate8fc61fc2017-01-23 19:57:06 -08001781 filtered_dict = {}
sousaedu80135b92021-02-17 15:05:18 +01001782
kate34718682017-01-24 03:20:43 -08001783 if filter_dict.get("name") and filter_dict["name"] != name:
1784 continue
sousaedu80135b92021-02-17 15:05:18 +01001785
kate34718682017-01-24 03:20:43 -08001786 if filter_dict.get("id") and filter_dict["id"] != catalog_uuid:
1787 continue
sousaedu80135b92021-02-17 15:05:18 +01001788
beierlb22ce2d2019-12-12 12:09:51 -05001789 filtered_dict["name"] = name
1790 filtered_dict["id"] = catalog_uuid
kate34718682017-01-24 03:20:43 -08001791 image_list.append(filtered_dict)
kate8fc61fc2017-01-23 19:57:06 -08001792
sousaedu80135b92021-02-17 15:05:18 +01001793 self.logger.debug(
1794 "List of already created catalog items: {}".format(image_list)
1795 )
1796
kate8fc61fc2017-01-23 19:57:06 -08001797 return image_list
1798 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01001799 raise vimconn.VimConnException(
1800 "Exception occured while retriving catalog items {}".format(exp)
1801 )
kate8fc61fc2017-01-23 19:57:06 -08001802
bayramovef390722016-09-27 03:34:46 -07001803 def get_vappid(self, vdc=None, vapp_name=None):
sousaedu80135b92021-02-17 15:05:18 +01001804 """Method takes vdc object and vApp name and returns vapp uuid or None
bayramovef390722016-09-27 03:34:46 -07001805
1806 Args:
bayramovef390722016-09-27 03:34:46 -07001807 vdc: The VDC object.
1808 vapp_name: is application vappp name identifier
1809
bayramovb6ffe792016-09-28 11:50:56 +04001810 Returns:
bayramovef390722016-09-27 03:34:46 -07001811 The return vApp name otherwise None
1812 """
bayramovef390722016-09-27 03:34:46 -07001813 if vdc is None or vapp_name is None:
1814 return None
sousaedu80135b92021-02-17 15:05:18 +01001815
bayramovef390722016-09-27 03:34:46 -07001816 # UUID has following format https://host/api/vApp/vapp-30da58a3-e7c7-4d09-8f68-d4c8201169cf
bayramov325fa1c2016-09-08 01:42:46 -07001817 try:
sousaedu80135b92021-02-17 15:05:18 +01001818 refs = [
1819 ref
1820 for ref in vdc.ResourceEntities.ResourceEntity
1821 if ref.name == vapp_name
1822 and ref.type_ == "application/vnd.vmware.vcloud.vApp+xml"
1823 ]
1824
bayramov325fa1c2016-09-08 01:42:46 -07001825 if len(refs) == 1:
1826 return refs[0].href.split("vapp")[1][1:]
bayramovef390722016-09-27 03:34:46 -07001827 except Exception as e:
1828 self.logger.exception(e)
1829 return False
sousaedu80135b92021-02-17 15:05:18 +01001830
bayramovef390722016-09-27 03:34:46 -07001831 return None
1832
bayramovfe3f3c92016-10-04 07:53:41 +04001833 def check_vapp(self, vdc=None, vapp_uuid=None):
sousaedu80135b92021-02-17 15:05:18 +01001834 """Method Method returns True or False if vapp deployed in vCloud director
bayramovef390722016-09-27 03:34:46 -07001835
sousaedu80135b92021-02-17 15:05:18 +01001836 Args:
1837 vca: Connector to VCA
1838 vdc: The VDC object.
1839 vappid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001840
sousaedu80135b92021-02-17 15:05:18 +01001841 Returns:
1842 The return True if vApp deployed
1843 :param vdc:
1844 :param vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001845 """
1846 try:
sousaedu80135b92021-02-17 15:05:18 +01001847 refs = [
1848 ref
1849 for ref in vdc.ResourceEntities.ResourceEntity
1850 if ref.type_ == "application/vnd.vmware.vcloud.vApp+xml"
1851 ]
1852
bayramovef390722016-09-27 03:34:46 -07001853 for ref in refs:
1854 vappid = ref.href.split("vapp")[1][1:]
1855 # find vapp with respected vapp uuid
sousaedu80135b92021-02-17 15:05:18 +01001856
bayramovfe3f3c92016-10-04 07:53:41 +04001857 if vappid == vapp_uuid:
bayramovef390722016-09-27 03:34:46 -07001858 return True
1859 except Exception as e:
1860 self.logger.exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001861
bayramovef390722016-09-27 03:34:46 -07001862 return False
sousaedu80135b92021-02-17 15:05:18 +01001863
bayramovef390722016-09-27 03:34:46 -07001864 return False
1865
kasarc5bf2932018-03-09 04:15:22 -08001866 def get_namebyvappid(self, vapp_uuid=None):
bayramovef390722016-09-27 03:34:46 -07001867 """Method returns vApp name from vCD and lookup done by vapp_id.
1868
1869 Args:
bayramovfe3f3c92016-10-04 07:53:41 +04001870 vapp_uuid: vappid is application identifier
bayramovef390722016-09-27 03:34:46 -07001871
1872 Returns:
1873 The return vApp name otherwise None
1874 """
bayramovef390722016-09-27 03:34:46 -07001875 try:
kasarc5bf2932018-03-09 04:15:22 -08001876 if self.client and vapp_uuid:
1877 vapp_call = "{}/api/vApp/vapp-{}".format(self.url, vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01001878 headers = {
1879 "Accept": "application/*+xml;version=" + API_VERSION,
1880 "x-vcloud-authorization": self.client._session.headers[
1881 "x-vcloud-authorization"
1882 ],
1883 }
bhangare1a0b97c2017-06-21 02:20:15 -07001884
sousaedu80135b92021-02-17 15:05:18 +01001885 response = self.perform_request(
1886 req_type="GET", url=vapp_call, headers=headers
1887 )
1888
beierlb22ce2d2019-12-12 12:09:51 -05001889 # Retry login if session expired & retry sending request
kasarc5bf2932018-03-09 04:15:22 -08001890 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01001891 response = self.retry_rest("GET", vapp_call)
bhangare1a0b97c2017-06-21 02:20:15 -07001892
beierl26fec002019-12-06 17:06:40 -05001893 tree = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01001894
1895 return tree.attrib["name"] if "name" in tree.attrib else None
bayramovef390722016-09-27 03:34:46 -07001896 except Exception as e:
1897 self.logger.exception(e)
sousaedu80135b92021-02-17 15:05:18 +01001898
bayramov325fa1c2016-09-08 01:42:46 -07001899 return None
sousaedu80135b92021-02-17 15:05:18 +01001900
bayramov325fa1c2016-09-08 01:42:46 -07001901 return None
1902
sousaedu80135b92021-02-17 15:05:18 +01001903 def new_vminstance(
1904 self,
1905 name=None,
1906 description="",
1907 start=False,
1908 image_id=None,
1909 flavor_id=None,
1910 net_list=[],
1911 cloud_config=None,
1912 disk_list=None,
1913 availability_zone_index=None,
1914 availability_zone_list=None,
1915 ):
bayramov325fa1c2016-09-08 01:42:46 -07001916 """Adds a VM instance to VIM
1917 Params:
tierno19860412017-10-03 10:46:46 +02001918 'start': (boolean) indicates if VM must start or created in pause mode.
1919 'image_id','flavor_id': image and flavor VIM id to use for the VM
1920 'net_list': list of interfaces, each one is a dictionary with:
1921 'name': (optional) name for the interface.
1922 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual
beierlb22ce2d2019-12-12 12:09:51 -05001923 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM
1924 capabilities
garciadeblasc4f4d732018-10-25 18:17:24 +02001925 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ...
tierno19860412017-10-03 10:46:46 +02001926 'mac_address': (optional) mac address to assign to this interface
beierlb22ce2d2019-12-12 12:09:51 -05001927 #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not
1928 provided, the VLAN tag to be used. In case net_id is provided, the internal network vlan is used
1929 for tagging VF
tierno19860412017-10-03 10:46:46 +02001930 'type': (mandatory) can be one of:
1931 'virtual', in this case always connected to a network of type 'net_type=bridge'
beierlb22ce2d2019-12-12 12:09:51 -05001932 'PCI-PASSTHROUGH' or 'PF' (passthrough): depending on VIM capabilities it can be connected to a
1933 data/ptp network or it can created unconnected
tierno66eba6e2017-11-10 17:09:18 +01001934 'SR-IOV' or 'VF' (SRIOV with VLAN tag): same as PF for network connectivity.
tierno19860412017-10-03 10:46:46 +02001935 'VFnotShared'(SRIOV without VLAN tag) same as PF for network connectivity. VF where no other VFs
1936 are allocated on the same physical NIC
1937 'bw': (optional) only for PF/VF/VFnotShared. Minimal Bandwidth required for the interface in GBPS
1938 'port_security': (optional) If False it must avoid any traffic filtering at this interface. If missing
1939 or True, it must apply the default VIM behaviour
1940 After execution the method will add the key:
1941 'vim_id': must be filled/added by this method with the VIM identifier generated by the VIM for this
1942 interface. 'net_list' is modified
1943 'cloud_config': (optional) dictionary with:
1944 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
1945 'users': (optional) list of users to be inserted, each item is a dict with:
1946 'name': (mandatory) user name,
1947 'key-pairs': (optional) list of strings with the public key to be inserted to the user
1948 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
1949 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
1950 'config-files': (optional). List of files to be transferred. Each item is a dict with:
1951 'dest': (mandatory) string with the destination absolute path
1952 'encoding': (optional, by default text). Can be one of:
1953 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
1954 'content' (mandatory): string with the content of the file
1955 'permissions': (optional) string with file permissions, typically octal notation '0644'
1956 'owner': (optional) file owner, string with the format 'owner:group'
1957 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
1958 'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
1959 'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
1960 'size': (mandatory) string with the size of the disk in GB
1961 availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
1962 availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
1963 availability_zone_index is None
tierno98e909c2017-10-14 13:27:03 +02001964 Returns a tuple with the instance identifier and created_items or raises an exception on error
1965 created_items can be None or a dictionary where this method can include key-values that will be passed to
1966 the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc.
1967 Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same
1968 as not present.
bayramov325fa1c2016-09-08 01:42:46 -07001969 """
kate15f1c382016-12-15 01:12:40 -08001970 self.logger.info("Creating new instance for entry {}".format(name))
sousaedu80135b92021-02-17 15:05:18 +01001971 self.logger.debug(
1972 "desc {} boot {} image_id: {} flavor_id: {} net_list: {} cloud_config {} disk_list {} "
1973 "availability_zone_index {} availability_zone_list {}".format(
1974 description,
1975 start,
1976 image_id,
1977 flavor_id,
1978 net_list,
1979 cloud_config,
1980 disk_list,
1981 availability_zone_index,
1982 availability_zone_list,
1983 )
1984 )
bayramov325fa1c2016-09-08 01:42:46 -07001985
beierlb22ce2d2019-12-12 12:09:51 -05001986 # new vm name = vmname + tenant_id + uuid
sousaedu80135b92021-02-17 15:05:18 +01001987 new_vm_name = [name, "-", str(uuid.uuid4())]
1988 vmname_andid = "".join(new_vm_name)
bayramov5761ad12016-10-04 09:00:30 +04001989
kasarc5bf2932018-03-09 04:15:22 -08001990 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01001991 if net["type"] == "PCI-PASSTHROUGH":
tierno72774862020-05-04 11:44:15 +00001992 raise vimconn.VimConnNotSupportedException(
sousaedu80135b92021-02-17 15:05:18 +01001993 "Current vCD version does not support type : {}".format(net["type"])
1994 )
bayramov325fa1c2016-09-08 01:42:46 -07001995
kasarc5bf2932018-03-09 04:15:22 -08001996 if len(net_list) > 10:
tierno72774862020-05-04 11:44:15 +00001997 raise vimconn.VimConnNotSupportedException(
sousaedu80135b92021-02-17 15:05:18 +01001998 "The VM hardware versions 7 and above support upto 10 NICs only"
1999 )
kasarc5bf2932018-03-09 04:15:22 -08002000
2001 # if vm already deployed we return existing uuid
bayramovef390722016-09-27 03:34:46 -07002002 # we check for presence of VDC, Catalog entry and Flavor.
kasarc5bf2932018-03-09 04:15:22 -08002003 org, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07002004 if vdc is None:
tierno72774862020-05-04 11:44:15 +00002005 raise vimconn.VimConnNotFoundException(
sousaedu80135b92021-02-17 15:05:18 +01002006 "new_vminstance(): Failed create vApp {}: (Failed retrieve VDC information)".format(
2007 name
2008 )
2009 )
2010
kasarc5bf2932018-03-09 04:15:22 -08002011 catalogs = org.list_catalogs()
bhangare1a0b97c2017-06-21 02:20:15 -07002012 if catalogs is None:
beierlb22ce2d2019-12-12 12:09:51 -05002013 # Retry once, if failed by refreshing token
bhangare1a0b97c2017-06-21 02:20:15 -07002014 self.get_token()
kasarc5bf2932018-03-09 04:15:22 -08002015 org = Org(self.client, resource=self.client.get_org())
2016 catalogs = org.list_catalogs()
sousaedu80135b92021-02-17 15:05:18 +01002017
bayramovef390722016-09-27 03:34:46 -07002018 if catalogs is None:
tierno72774862020-05-04 11:44:15 +00002019 raise vimconn.VimConnNotFoundException(
sousaedu80135b92021-02-17 15:05:18 +01002020 "new_vminstance(): Failed create vApp {}: (Failed retrieve catalogs list)".format(
2021 name
2022 )
2023 )
bayramovbd6160f2016-09-28 04:12:05 +04002024
sousaedu80135b92021-02-17 15:05:18 +01002025 catalog_hash_name = self.get_catalogbyid(
2026 catalog_uuid=image_id, catalogs=catalogs
2027 )
kate15f1c382016-12-15 01:12:40 -08002028 if catalog_hash_name:
sousaedu80135b92021-02-17 15:05:18 +01002029 self.logger.info(
2030 "Found catalog entry {} for image id {}".format(
2031 catalog_hash_name, image_id
2032 )
2033 )
kate15f1c382016-12-15 01:12:40 -08002034 else:
sousaedu80135b92021-02-17 15:05:18 +01002035 raise vimconn.VimConnNotFoundException(
2036 "new_vminstance(): Failed create vApp {}: "
2037 "(Failed retrieve catalog information {})".format(name, image_id)
2038 )
kate15f1c382016-12-15 01:12:40 -08002039
kate15f1c382016-12-15 01:12:40 -08002040 # Set vCPU and Memory based on flavor.
bayramovb6ffe792016-09-28 11:50:56 +04002041 vm_cpus = None
2042 vm_memory = None
bhangarea92ae392017-01-12 22:30:29 -08002043 vm_disk = None
bhangare68e73e62017-07-04 22:44:01 -07002044 numas = None
kateac1e3792017-04-01 02:16:39 -07002045
bayramovb6ffe792016-09-28 11:50:56 +04002046 if flavor_id is not None:
kateeb044522017-03-06 23:54:39 -08002047 if flavor_id not in vimconnector.flavorlist:
sousaedu80135b92021-02-17 15:05:18 +01002048 raise vimconn.VimConnNotFoundException(
2049 "new_vminstance(): Failed create vApp {}: "
2050 "Failed retrieve flavor information "
2051 "flavor id {}".format(name, flavor_id)
2052 )
bayramovb6ffe792016-09-28 11:50:56 +04002053 else:
2054 try:
kateeb044522017-03-06 23:54:39 -08002055 flavor = vimconnector.flavorlist[flavor_id]
kate15f1c382016-12-15 01:12:40 -08002056 vm_cpus = flavor[FLAVOR_VCPUS_KEY]
2057 vm_memory = flavor[FLAVOR_RAM_KEY]
bhangarea92ae392017-01-12 22:30:29 -08002058 vm_disk = flavor[FLAVOR_DISK_KEY]
bhangarefda5f7c2017-01-12 23:50:34 -08002059 extended = flavor.get("extended", None)
sousaedu80135b92021-02-17 15:05:18 +01002060
bhangarefda5f7c2017-01-12 23:50:34 -08002061 if extended:
beierlb22ce2d2019-12-12 12:09:51 -05002062 numas = extended.get("numas", None)
kateeb044522017-03-06 23:54:39 -08002063 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01002064 raise vimconn.VimConnException(
2065 "Corrupted flavor. {}.Exception: {}".format(flavor_id, exp)
2066 )
bayramov325fa1c2016-09-08 01:42:46 -07002067
bayramovef390722016-09-27 03:34:46 -07002068 # image upload creates template name as catalog name space Template.
kate15f1c382016-12-15 01:12:40 -08002069 templateName = self.get_catalogbyid(catalog_uuid=image_id, catalogs=catalogs)
beierlb22ce2d2019-12-12 12:09:51 -05002070 # power_on = 'false'
2071 # if start:
2072 # power_on = 'true'
bayramovef390722016-09-27 03:34:46 -07002073
2074 # client must provide at least one entry in net_list if not we report error
beierlb22ce2d2019-12-12 12:09:51 -05002075 # If net type is mgmt, then configure it as primary net & use its NIC index as primary NIC
beierl26fec002019-12-06 17:06:40 -05002076 # If no mgmt, then the 1st NN in netlist is considered as primary net.
bhangare0e571a92017-01-12 04:02:23 -08002077 primary_net = None
kate15f1c382016-12-15 01:12:40 -08002078 primary_netname = None
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00002079 primary_net_href = None
beierlb22ce2d2019-12-12 12:09:51 -05002080 # network_mode = 'bridged'
bayramovb6ffe792016-09-28 11:50:56 +04002081 if net_list is not None and len(net_list) > 0:
bhangare0e571a92017-01-12 04:02:23 -08002082 for net in net_list:
sousaedu80135b92021-02-17 15:05:18 +01002083 if "use" in net and net["use"] == "mgmt" and not primary_net:
bhangare0e571a92017-01-12 04:02:23 -08002084 primary_net = net
sousaedu80135b92021-02-17 15:05:18 +01002085
bayramovb6ffe792016-09-28 11:50:56 +04002086 if primary_net is None:
bhangare0e571a92017-01-12 04:02:23 -08002087 primary_net = net_list[0]
2088
2089 try:
sousaedu80135b92021-02-17 15:05:18 +01002090 primary_net_id = primary_net["net_id"]
2091 url_list = [self.url, "/api/network/", primary_net_id]
2092 primary_net_href = "".join(url_list)
bhangare0e571a92017-01-12 04:02:23 -08002093 network_dict = self.get_vcd_network(network_uuid=primary_net_id)
bhangare0e571a92017-01-12 04:02:23 -08002094
sousaedu80135b92021-02-17 15:05:18 +01002095 if "name" in network_dict:
2096 primary_netname = network_dict["name"]
bhangare0e571a92017-01-12 04:02:23 -08002097 except KeyError:
sousaedu80135b92021-02-17 15:05:18 +01002098 raise vimconn.VimConnException(
2099 "Corrupted flavor. {}".format(primary_net)
2100 )
bhangare0e571a92017-01-12 04:02:23 -08002101 else:
sousaedu80135b92021-02-17 15:05:18 +01002102 raise vimconn.VimConnUnexpectedResponse(
2103 "new_vminstance(): Failed network list is empty."
2104 )
bayramovef390722016-09-27 03:34:46 -07002105
2106 # use: 'data', 'bridge', 'mgmt'
2107 # create vApp. Set vcpu and ram based on flavor id.
bhangarebfdca492017-03-11 01:32:46 -08002108 try:
kasarc5bf2932018-03-09 04:15:22 -08002109 vdc_obj = VDC(self.client, resource=org.get_vdc(self.tenant_name))
2110 if not vdc_obj:
sousaedu80135b92021-02-17 15:05:18 +01002111 raise vimconn.VimConnNotFoundException(
2112 "new_vminstance(): Failed to get VDC object"
2113 )
bhangare1a0b97c2017-06-21 02:20:15 -07002114
beierl26fec002019-12-06 17:06:40 -05002115 for retry in (1, 2):
kasarc5bf2932018-03-09 04:15:22 -08002116 items = org.get_catalog_item(catalog_hash_name, catalog_hash_name)
2117 catalog_items = [items.attrib]
2118
2119 if len(catalog_items) == 1:
2120 if self.client:
sousaedu80135b92021-02-17 15:05:18 +01002121 headers = {
2122 "Accept": "application/*+xml;version=" + API_VERSION,
2123 "x-vcloud-authorization": self.client._session.headers[
2124 "x-vcloud-authorization"
2125 ],
2126 }
kasarc5bf2932018-03-09 04:15:22 -08002127
sousaedu80135b92021-02-17 15:05:18 +01002128 response = self.perform_request(
2129 req_type="GET",
2130 url=catalog_items[0].get("href"),
2131 headers=headers,
2132 )
beierl26fec002019-12-06 17:06:40 -05002133 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002134 entity = [
2135 child
2136 for child in catalogItem
2137 if child.get("type")
2138 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
2139 ][0]
kasarc5bf2932018-03-09 04:15:22 -08002140 vapp_tempalte_href = entity.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07002141
sousaedu80135b92021-02-17 15:05:18 +01002142 response = self.perform_request(
2143 req_type="GET", url=vapp_tempalte_href, headers=headers
2144 )
2145
kasarc5bf2932018-03-09 04:15:22 -08002146 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01002147 self.logger.debug(
2148 "REST API call {} failed. Return status code {}".format(
2149 vapp_tempalte_href, response.status_code
2150 )
2151 )
kasarc5bf2932018-03-09 04:15:22 -08002152 else:
beierl26fec002019-12-06 17:06:40 -05002153 result = (response.text).replace("\n", " ")
kasarc5bf2932018-03-09 04:15:22 -08002154
beierl26fec002019-12-06 17:06:40 -05002155 vapp_template_tree = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002156 children_element = [
2157 child for child in vapp_template_tree if "Children" in child.tag
2158 ][0]
2159 vm_element = [child for child in children_element if "Vm" in child.tag][
2160 0
2161 ]
2162 vm_name = vm_element.get("name")
2163 vm_id = vm_element.get("id")
2164 vm_href = vm_element.get("href")
kasarc5bf2932018-03-09 04:15:22 -08002165
beierlb22ce2d2019-12-12 12:09:51 -05002166 # cpus = re.search('<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>',
2167 # result).group(1)
sousaedu80135b92021-02-17 15:05:18 +01002168 memory_mb = re.search(
2169 "<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>",
2170 result,
2171 ).group(1)
beierlb22ce2d2019-12-12 12:09:51 -05002172 # cores = re.search('<vmw:CoresPerSocket ovf:required.*?>(\d+)</vmw:CoresPerSocket>', result).group(1)
kasarc5bf2932018-03-09 04:15:22 -08002173
sousaedu80135b92021-02-17 15:05:18 +01002174 headers[
2175 "Content-Type"
2176 ] = "application/vnd.vmware.vcloud.instantiateVAppTemplateParams+xml"
2177 vdc_id = vdc.get("id").split(":")[-1]
2178 instantiate_vapp_href = (
2179 "{}/api/vdc/{}/action/instantiateVAppTemplate".format(
2180 self.url, vdc_id
2181 )
2182 )
2183
2184 with open(
2185 os.path.join(
2186 os.path.dirname(__file__), "InstantiateVAppTemplateParams.xml"
2187 ),
2188 "r",
2189 ) as f:
beierl26fec002019-12-06 17:06:40 -05002190 template = f.read()
2191
sousaedu80135b92021-02-17 15:05:18 +01002192 data = template.format(
2193 vmname_andid,
2194 primary_netname,
2195 primary_net_href,
2196 vapp_tempalte_href,
2197 vm_href,
2198 vm_id,
2199 vm_name,
2200 primary_netname,
2201 cpu=vm_cpus,
2202 core=1,
2203 memory=vm_memory,
2204 )
kasarc5bf2932018-03-09 04:15:22 -08002205
sousaedu80135b92021-02-17 15:05:18 +01002206 response = self.perform_request(
2207 req_type="POST",
2208 url=instantiate_vapp_href,
2209 headers=headers,
2210 data=data,
2211 )
kasarc5bf2932018-03-09 04:15:22 -08002212
2213 if response.status_code != 201:
sousaedu80135b92021-02-17 15:05:18 +01002214 self.logger.error(
2215 "REST call {} failed reason : {}"
2216 "status code : {}".format(
2217 instantiate_vapp_href, response.text, response.status_code
2218 )
2219 )
2220 raise vimconn.VimConnException(
2221 "new_vminstance(): Failed to create"
2222 "vAapp {}".format(vmname_andid)
2223 )
kasarc5bf2932018-03-09 04:15:22 -08002224 else:
beierl26fec002019-12-06 17:06:40 -05002225 vapptask = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08002226
beierlb22ce2d2019-12-12 12:09:51 -05002227 if vapptask is None and retry == 1:
2228 self.get_token() # Retry getting token
bhangare68e73e62017-07-04 22:44:01 -07002229 continue
2230 else:
2231 break
2232
bhangare1a0b97c2017-06-21 02:20:15 -07002233 if vapptask is None or vapptask is False:
tierno72774862020-05-04 11:44:15 +00002234 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002235 "new_vminstance(): failed to create vApp {}".format(vmname_andid)
2236 )
kasarc5bf2932018-03-09 04:15:22 -08002237
sbhangarea8e5b782018-06-21 02:10:03 -07002238 # wait for task to complete
kasarc5bf2932018-03-09 04:15:22 -08002239 result = self.client.get_task_monitor().wait_for_success(task=vapptask)
2240
sousaedu80135b92021-02-17 15:05:18 +01002241 if result.get("status") == "success":
2242 self.logger.debug(
2243 "new_vminstance(): Sucessfully created Vapp {}".format(vmname_andid)
2244 )
kasarc5bf2932018-03-09 04:15:22 -08002245 else:
tierno72774862020-05-04 11:44:15 +00002246 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002247 "new_vminstance(): failed to create vApp {}".format(vmname_andid)
2248 )
bhangarebfdca492017-03-11 01:32:46 -08002249 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002250 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002251 "new_vminstance(): failed to create vApp {} with Exception:{}".format(
2252 vmname_andid, exp
2253 )
2254 )
bayramovef390722016-09-27 03:34:46 -07002255
2256 # we should have now vapp in undeployed state.
bhangarebfdca492017-03-11 01:32:46 -08002257 try:
sousaedu80135b92021-02-17 15:05:18 +01002258 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08002259 vapp_resource = vdc_obj.get_vapp(vmname_andid)
sousaedu80135b92021-02-17 15:05:18 +01002260 vapp_uuid = vapp_resource.get("id").split(":")[-1]
kasarc5bf2932018-03-09 04:15:22 -08002261 vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08002262 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002263 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002264 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}".format(
2265 vmname_andid, exp
2266 )
2267 )
bhangarebfdca492017-03-11 01:32:46 -08002268
bhangare1a0b97c2017-06-21 02:20:15 -07002269 if vapp_uuid is None:
tierno72774862020-05-04 11:44:15 +00002270 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002271 "new_vminstance(): Failed to retrieve vApp {} after creation".format(
2272 vmname_andid
2273 )
2274 )
bhangarea92ae392017-01-12 22:30:29 -08002275
beierl26fec002019-12-06 17:06:40 -05002276 # Add PCI passthrough/SRIOV configrations
kateac1e3792017-04-01 02:16:39 -07002277 pci_devices_info = []
kateac1e3792017-04-01 02:16:39 -07002278 reserve_memory = False
2279
2280 for net in net_list:
tierno66eba6e2017-11-10 17:09:18 +01002281 if net["type"] == "PF" or net["type"] == "PCI-PASSTHROUGH":
kateac1e3792017-04-01 02:16:39 -07002282 pci_devices_info.append(net)
sousaedu80135b92021-02-17 15:05:18 +01002283 elif (
2284 net["type"] == "VF"
2285 or net["type"] == "SR-IOV"
2286 or net["type"] == "VFnotShared"
2287 ) and "net_id" in net:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00002288 reserve_memory = True
kateac1e3792017-04-01 02:16:39 -07002289
beierl26fec002019-12-06 17:06:40 -05002290 # Add PCI
bhangarefda5f7c2017-01-12 23:50:34 -08002291 if len(pci_devices_info) > 0:
sousaedu80135b92021-02-17 15:05:18 +01002292 self.logger.info(
2293 "Need to add PCI devices {} into VM {}".format(
2294 pci_devices_info, vmname_andid
2295 )
2296 )
2297 PCI_devices_status, _, _ = self.add_pci_devices(
2298 vapp_uuid, pci_devices_info, vmname_andid
2299 )
2300
beierl26fec002019-12-06 17:06:40 -05002301 if PCI_devices_status:
sousaedu80135b92021-02-17 15:05:18 +01002302 self.logger.info(
2303 "Added PCI devives {} to VM {}".format(
2304 pci_devices_info, vmname_andid
2305 )
2306 )
kateac1e3792017-04-01 02:16:39 -07002307 reserve_memory = True
bhangarefda5f7c2017-01-12 23:50:34 -08002308 else:
sousaedu80135b92021-02-17 15:05:18 +01002309 self.logger.info(
2310 "Fail to add PCI devives {} to VM {}".format(
2311 pci_devices_info, vmname_andid
2312 )
2313 )
bhangare1a0b97c2017-06-21 02:20:15 -07002314
beierl26fec002019-12-06 17:06:40 -05002315 # Add serial console - this allows cloud images to boot as if we are running under OpenStack
2316 self.add_serial_device(vapp_uuid)
2317
bhangarea92ae392017-01-12 22:30:29 -08002318 if vm_disk:
beierl26fec002019-12-06 17:06:40 -05002319 # Assuming there is only one disk in ovf and fast provisioning in organization vDC is disabled
bhangarea92ae392017-01-12 22:30:29 -08002320 result = self.modify_vm_disk(vapp_uuid, vm_disk)
beierl26fec002019-12-06 17:06:40 -05002321 if result:
bhangarea92ae392017-01-12 22:30:29 -08002322 self.logger.debug("Modified Disk size of VM {} ".format(vmname_andid))
bayramovef390722016-09-27 03:34:46 -07002323
beierlb22ce2d2019-12-12 12:09:51 -05002324 # Add new or existing disks to vApp
bhangare06312472017-03-30 05:49:07 -07002325 if disk_list:
2326 added_existing_disk = False
2327 for disk in disk_list:
sousaedu80135b92021-02-17 15:05:18 +01002328 if "device_type" in disk and disk["device_type"] == "cdrom":
2329 image_id = disk["image_id"]
kasar0c007d62017-05-19 03:13:57 -07002330 # Adding CD-ROM to VM
2331 # will revisit code once specification ready to support this feature
2332 self.insert_media_to_vm(vapp, image_id)
2333 elif "image_id" in disk and disk["image_id"] is not None:
sousaedu80135b92021-02-17 15:05:18 +01002334 self.logger.debug(
2335 "Adding existing disk from image {} to vm {} ".format(
2336 disk["image_id"], vapp_uuid
2337 )
2338 )
2339 self.add_existing_disk(
2340 catalogs=catalogs,
2341 image_id=disk["image_id"],
2342 size=disk["size"],
2343 template_name=templateName,
2344 vapp_uuid=vapp_uuid,
2345 )
bhangare06312472017-03-30 05:49:07 -07002346 added_existing_disk = True
2347 else:
beierlb22ce2d2019-12-12 12:09:51 -05002348 # Wait till added existing disk gets reflected into vCD database/API
bhangare06312472017-03-30 05:49:07 -07002349 if added_existing_disk:
2350 time.sleep(5)
2351 added_existing_disk = False
sousaedu80135b92021-02-17 15:05:18 +01002352 self.add_new_disk(vapp_uuid, disk["size"])
bhangare06312472017-03-30 05:49:07 -07002353
kasarde691232017-03-25 03:37:31 -07002354 if numas:
2355 # Assigning numa affinity setting
2356 for numa in numas:
sousaedu80135b92021-02-17 15:05:18 +01002357 if "paired-threads-id" in numa:
2358 paired_threads_id = numa["paired-threads-id"]
kasarde691232017-03-25 03:37:31 -07002359 self.set_numa_affinity(vapp_uuid, paired_threads_id)
2360
bhangare0e571a92017-01-12 04:02:23 -08002361 # add NICs & connect to networks in netlist
bayramovef390722016-09-27 03:34:46 -07002362 try:
sousaedu80135b92021-02-17 15:05:18 +01002363 vdc_obj = VDC(self.client, href=vdc.get("href"))
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002364 vapp_resource = vdc_obj.get_vapp(vmname_andid)
2365 vapp = VApp(self.client, resource=vapp_resource)
sousaedu80135b92021-02-17 15:05:18 +01002366 vapp_id = vapp_resource.get("id").split(":")[-1]
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002367
2368 self.logger.info("Removing primary NIC: ")
2369 # First remove all NICs so that NIC properties can be adjusted as needed
2370 self.remove_primary_network_adapter_from_all_vms(vapp)
2371
kate15f1c382016-12-15 01:12:40 -08002372 self.logger.info("Request to connect VM to a network: {}".format(net_list))
bhangare0e571a92017-01-12 04:02:23 -08002373 primary_nic_index = 0
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00002374 nicIndex = 0
bayramovef390722016-09-27 03:34:46 -07002375 for net in net_list:
2376 # openmano uses network id in UUID format.
2377 # vCloud Director need a name so we do reverse operation from provided UUID we lookup a name
kate15f1c382016-12-15 01:12:40 -08002378 # [{'use': 'bridge', 'net_id': '527d4bf7-566a-41e7-a9e7-ca3cdd9cef4f', 'type': 'virtual',
2379 # 'vpci': '0000:00:11.0', 'name': 'eth0'}]
2380
sousaedu80135b92021-02-17 15:05:18 +01002381 if "net_id" not in net:
kate15f1c382016-12-15 01:12:40 -08002382 continue
2383
beierlb22ce2d2019-12-12 12:09:51 -05002384 # Using net_id as a vim_id i.e. vim interface id, as do not have saperate vim interface id
2385 # Same will be returned in refresh_vms_status() as vim_interface_id
sousaedu80135b92021-02-17 15:05:18 +01002386 net["vim_id"] = net[
2387 "net_id"
2388 ] # Provide the same VIM identifier as the VIM network
tierno19860412017-10-03 10:46:46 +02002389
sousaedu80135b92021-02-17 15:05:18 +01002390 interface_net_id = net["net_id"]
2391 interface_net_name = self.get_network_name_by_id(
2392 network_uuid=interface_net_id
2393 )
2394 interface_network_mode = net["use"]
bayramovef390722016-09-27 03:34:46 -07002395
sousaedu80135b92021-02-17 15:05:18 +01002396 if interface_network_mode == "mgmt":
bhangare0e571a92017-01-12 04:02:23 -08002397 primary_nic_index = nicIndex
2398
kate15f1c382016-12-15 01:12:40 -08002399 """- POOL (A static IP address is allocated automatically from a pool of addresses.)
2400 - DHCP (The IP address is obtained from a DHCP service.)
2401 - MANUAL (The IP address is assigned manually in the IpAddress element.)
2402 - NONE (No IP addressing mode specified.)"""
2403
2404 if primary_netname is not None:
sousaedu80135b92021-02-17 15:05:18 +01002405 self.logger.debug(
2406 "new_vminstance(): Filtering by net name {}".format(
2407 interface_net_name
2408 )
2409 )
2410 nets = [
2411 n
2412 for n in self.get_network_list()
2413 if n.get("name") == interface_net_name
2414 ]
2415
bayramovef390722016-09-27 03:34:46 -07002416 if len(nets) == 1:
sousaedu80135b92021-02-17 15:05:18 +01002417 self.logger.info(
2418 "new_vminstance(): Found requested network: {}".format(
2419 nets[0].get("name")
2420 )
2421 )
bhangare1a0b97c2017-06-21 02:20:15 -07002422
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00002423 if interface_net_name != primary_netname:
2424 # connect network to VM - with all DHCP by default
sousaedu80135b92021-02-17 15:05:18 +01002425 self.logger.info(
2426 "new_vminstance(): Attaching net {} to vapp".format(
2427 interface_net_name
2428 )
2429 )
2430 self.connect_vapp_to_org_vdc_network(
2431 vapp_id, nets[0].get("name")
2432 )
kasar3ac5dc42017-03-15 06:28:22 -07002433
sousaedu80135b92021-02-17 15:05:18 +01002434 type_list = ("PF", "PCI-PASSTHROUGH", "VFnotShared")
2435 nic_type = "VMXNET3"
2436 if "type" in net and net["type"] not in type_list:
kasar3ac5dc42017-03-15 06:28:22 -07002437 # fetching nic type from vnf
sousaedu80135b92021-02-17 15:05:18 +01002438 if "model" in net:
2439 if net["model"] is not None:
2440 if (
2441 net["model"].lower() == "paravirt"
2442 or net["model"].lower() == "virtio"
2443 ):
2444 nic_type = "VMXNET3"
kasar204e39e2018-01-25 00:57:02 -08002445 else:
sousaedu80135b92021-02-17 15:05:18 +01002446 nic_type = net["model"]
kasar204e39e2018-01-25 00:57:02 -08002447
sousaedu80135b92021-02-17 15:05:18 +01002448 self.logger.info(
2449 "new_vminstance(): adding network adapter "
2450 "to a network {}".format(nets[0].get("name"))
2451 )
2452 self.add_network_adapter_to_vms(
2453 vapp,
2454 nets[0].get("name"),
2455 primary_nic_index,
2456 nicIndex,
2457 net,
2458 nic_type=nic_type,
2459 )
kasar3ac5dc42017-03-15 06:28:22 -07002460 else:
sousaedu80135b92021-02-17 15:05:18 +01002461 self.logger.info(
2462 "new_vminstance(): adding network adapter "
2463 "to a network {}".format(nets[0].get("name"))
2464 )
2465
2466 if net["type"] in ["SR-IOV", "VF"]:
2467 nic_type = net["type"]
2468 self.add_network_adapter_to_vms(
2469 vapp,
2470 nets[0].get("name"),
2471 primary_nic_index,
2472 nicIndex,
2473 net,
2474 nic_type=nic_type,
2475 )
bhangare0e571a92017-01-12 04:02:23 -08002476 nicIndex += 1
bayramovef390722016-09-27 03:34:46 -07002477
kasardc1f02e2017-03-25 07:20:30 -07002478 # cloud-init for ssh-key injection
2479 if cloud_config:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002480 # Create a catalog which will be carrying the config drive ISO
2481 # This catalog is deleted during vApp deletion. The catalog name carries
2482 # vApp UUID and thats how it gets identified during its deletion.
sousaedu80135b92021-02-17 15:05:18 +01002483 config_drive_catalog_name = "cfg_drv-" + vapp_uuid
2484 self.logger.info(
2485 'new_vminstance(): Creating catalog "{}" to carry config drive ISO'.format(
2486 config_drive_catalog_name
2487 )
2488 )
2489 config_drive_catalog_id = self.create_vimcatalog(
2490 org, config_drive_catalog_name
2491 )
2492
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002493 if config_drive_catalog_id is None:
sousaedu80135b92021-02-17 15:05:18 +01002494 error_msg = (
2495 "new_vminstance(): Failed to create new catalog '{}' to carry the config drive "
2496 "ISO".format(config_drive_catalog_name)
2497 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002498 raise Exception(error_msg)
2499
2500 # Create config-drive ISO
2501 _, userdata = self._create_user_data(cloud_config)
2502 # self.logger.debug('new_vminstance(): The userdata for cloud-init: {}'.format(userdata))
2503 iso_path = self.create_config_drive_iso(userdata)
sousaedu80135b92021-02-17 15:05:18 +01002504 self.logger.debug(
2505 "new_vminstance(): The ISO is successfully created. Path: {}".format(
2506 iso_path
2507 )
2508 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002509
sousaedu80135b92021-02-17 15:05:18 +01002510 self.logger.info(
2511 "new_vminstance(): uploading iso to catalog {}".format(
2512 config_drive_catalog_name
2513 )
2514 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002515 self.upload_iso_to_catalog(config_drive_catalog_id, iso_path)
2516 # Attach the config-drive ISO to the VM
sousaedu80135b92021-02-17 15:05:18 +01002517 self.logger.info(
2518 "new_vminstance(): Attaching the config-drive ISO to the VM"
2519 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002520 self.insert_media_to_vm(vapp, config_drive_catalog_id)
2521 shutil.rmtree(os.path.dirname(iso_path), ignore_errors=True)
kasardc1f02e2017-03-25 07:20:30 -07002522
kateac1e3792017-04-01 02:16:39 -07002523 # If VM has PCI devices or SRIOV reserve memory for VM
2524 if reserve_memory:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00002525 self.reserve_memory_for_all_vms(vapp, memory_mb)
bhangarefda5f7c2017-01-12 23:50:34 -08002526
sousaedu80135b92021-02-17 15:05:18 +01002527 self.logger.debug(
2528 "new_vminstance(): starting power on vApp {} ".format(vmname_andid)
2529 )
bhangare1a0b97c2017-06-21 02:20:15 -07002530
kasarc5bf2932018-03-09 04:15:22 -08002531 poweron_task = self.power_on_vapp(vapp_id, vmname_andid)
2532 result = self.client.get_task_monitor().wait_for_success(task=poweron_task)
sousaedu80135b92021-02-17 15:05:18 +01002533 if result.get("status") == "success":
2534 self.logger.info(
2535 "new_vminstance(): Successfully power on "
2536 "vApp {}".format(vmname_andid)
2537 )
kasarc5bf2932018-03-09 04:15:22 -08002538 else:
sousaedu80135b92021-02-17 15:05:18 +01002539 self.logger.error(
2540 "new_vminstance(): failed to power on vApp "
2541 "{}".format(vmname_andid)
2542 )
bhangarebfdca492017-03-11 01:32:46 -08002543
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002544 except Exception as exp:
2545 try:
2546 self.delete_vminstance(vapp_uuid)
2547 except Exception as exp2:
2548 self.logger.error("new_vminstance rollback fail {}".format(exp2))
bhangarebfdca492017-03-11 01:32:46 -08002549 # it might be a case if specific mandatory entry in dict is empty or some other pyVcloud exception
sousaedu80135b92021-02-17 15:05:18 +01002550 self.logger.error(
2551 "new_vminstance(): Failed create new vm instance {} with exception {}".format(
2552 name, exp
2553 )
2554 )
2555 raise vimconn.VimConnException(
2556 "new_vminstance(): Failed create new vm instance {} with exception {}".format(
2557 name, exp
2558 )
2559 )
bayramovef390722016-09-27 03:34:46 -07002560 # check if vApp deployed and if that the case return vApp UUID otherwise -1
kate13ab2c42016-12-23 01:34:24 -08002561 wait_time = 0
2562 vapp_uuid = None
2563 while wait_time <= MAX_WAIT_TIME:
bhangarebfdca492017-03-11 01:32:46 -08002564 try:
kasarc5bf2932018-03-09 04:15:22 -08002565 vapp_resource = vdc_obj.get_vapp(vmname_andid)
sbhangarea8e5b782018-06-21 02:10:03 -07002566 vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08002567 except Exception as exp:
tierno72774862020-05-04 11:44:15 +00002568 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01002569 "new_vminstance(): Failed to retrieve vApp {} after creation: Exception:{}".format(
2570 vmname_andid, exp
2571 )
2572 )
bhangarebfdca492017-03-11 01:32:46 -08002573
beierlb22ce2d2019-12-12 12:09:51 -05002574 # if vapp and vapp.me.deployed:
sousaedu80135b92021-02-17 15:05:18 +01002575 if vapp and vapp_resource.get("deployed") == "true":
2576 vapp_uuid = vapp_resource.get("id").split(":")[-1]
kate13ab2c42016-12-23 01:34:24 -08002577 break
2578 else:
sousaedu80135b92021-02-17 15:05:18 +01002579 self.logger.debug(
2580 "new_vminstance(): Wait for vApp {} to deploy".format(name)
2581 )
kate13ab2c42016-12-23 01:34:24 -08002582 time.sleep(INTERVAL_TIME)
2583
beierlb22ce2d2019-12-12 12:09:51 -05002584 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08002585
beierlb22ce2d2019-12-12 12:09:51 -05002586 # SET Affinity Rule for VM
2587 # Pre-requisites: User has created Hosh Groups in vCenter with respective Hosts to be used
2588 # While creating VIM account user has to pass the Host Group names in availability_zone list
2589 # "availability_zone" is a part of VIM "config" parameters
2590 # For example, in VIM config: "availability_zone":["HG_170","HG_174","HG_175"]
2591 # Host groups are referred as availability zones
2592 # With following procedure, deployed VM will be added into a VM group.
2593 # Then A VM to Host Affinity rule will be created using the VM group & Host group.
sousaedu80135b92021-02-17 15:05:18 +01002594 if availability_zone_list:
2595 self.logger.debug(
2596 "Existing Host Groups in VIM {}".format(
2597 self.config.get("availability_zone")
2598 )
2599 )
beierlb22ce2d2019-12-12 12:09:51 -05002600 # Admin access required for creating Affinity rules
sbhangarea8e5b782018-06-21 02:10:03 -07002601 client = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01002602
sbhangarea8e5b782018-06-21 02:10:03 -07002603 if not client:
sousaedu80135b92021-02-17 15:05:18 +01002604 raise vimconn.VimConnConnectionException(
2605 "Failed to connect vCD as admin"
2606 )
sbhangarea8e5b782018-06-21 02:10:03 -07002607 else:
2608 self.client = client
sousaedu80135b92021-02-17 15:05:18 +01002609
sbhangarea8e5b782018-06-21 02:10:03 -07002610 if self.client:
sousaedu80135b92021-02-17 15:05:18 +01002611 headers = {
2612 "Accept": "application/*+xml;version=27.0",
2613 "x-vcloud-authorization": self.client._session.headers[
2614 "x-vcloud-authorization"
2615 ],
2616 }
2617
beierlb22ce2d2019-12-12 12:09:51 -05002618 # Step1: Get provider vdc details from organization
sbhangarea8e5b782018-06-21 02:10:03 -07002619 pvdc_href = self.get_pvdc_for_org(self.tenant_name, headers)
2620 if pvdc_href is not None:
beierlb22ce2d2019-12-12 12:09:51 -05002621 # Step2: Found required pvdc, now get resource pool information
sbhangarea8e5b782018-06-21 02:10:03 -07002622 respool_href = self.get_resource_pool_details(pvdc_href, headers)
2623 if respool_href is None:
beierlb22ce2d2019-12-12 12:09:51 -05002624 # Raise error if respool_href not found
sousaedu80135b92021-02-17 15:05:18 +01002625 msg = "new_vminstance():Error in finding resource pool details in pvdc {}".format(
2626 pvdc_href
2627 )
sbhangarea8e5b782018-06-21 02:10:03 -07002628 self.log_message(msg)
2629
beierlb22ce2d2019-12-12 12:09:51 -05002630 # Step3: Verify requested availability zone(hostGroup) is present in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002631 # get availability Zone
sousaedu80135b92021-02-17 15:05:18 +01002632 vm_az = self.get_vm_availability_zone(
2633 availability_zone_index, availability_zone_list
2634 )
2635
sbhangarea8e5b782018-06-21 02:10:03 -07002636 # check if provided av zone(hostGroup) is present in vCD VIM
2637 status = self.check_availibility_zone(vm_az, respool_href, headers)
2638 if status is False:
sousaedu80135b92021-02-17 15:05:18 +01002639 msg = (
2640 "new_vminstance(): Error in finding availability zone(Host Group): {} in "
2641 "resource pool {} status: {}"
2642 ).format(vm_az, respool_href, status)
sbhangarea8e5b782018-06-21 02:10:03 -07002643 self.log_message(msg)
2644 else:
sousaedu80135b92021-02-17 15:05:18 +01002645 self.logger.debug(
2646 "new_vminstance(): Availability zone {} found in VIM".format(vm_az)
2647 )
sbhangarea8e5b782018-06-21 02:10:03 -07002648
beierlb22ce2d2019-12-12 12:09:51 -05002649 # Step4: Find VM group references to create vm group
sbhangarea8e5b782018-06-21 02:10:03 -07002650 vmgrp_href = self.find_vmgroup_reference(respool_href, headers)
beierlb22ce2d2019-12-12 12:09:51 -05002651 if vmgrp_href is None:
sbhangarea8e5b782018-06-21 02:10:03 -07002652 msg = "new_vminstance(): No reference to VmGroup found in resource pool"
2653 self.log_message(msg)
2654
beierlb22ce2d2019-12-12 12:09:51 -05002655 # Step5: Create a VmGroup with name az_VmGroup
sousaedu80135b92021-02-17 15:05:18 +01002656 vmgrp_name = (
2657 vm_az + "_" + name
2658 ) # Formed VM Group name = Host Group name + VM name
sbhangarea8e5b782018-06-21 02:10:03 -07002659 status = self.create_vmgroup(vmgrp_name, vmgrp_href, headers)
2660 if status is not True:
sousaedu80135b92021-02-17 15:05:18 +01002661 msg = "new_vminstance(): Error in creating VM group {}".format(
2662 vmgrp_name
2663 )
sbhangarea8e5b782018-06-21 02:10:03 -07002664 self.log_message(msg)
2665
beierlb22ce2d2019-12-12 12:09:51 -05002666 # VM Group url to add vms to vm group
2667 vmgrpname_url = self.url + "/api/admin/extension/vmGroup/name/" + vmgrp_name
sbhangarea8e5b782018-06-21 02:10:03 -07002668
beierlb22ce2d2019-12-12 12:09:51 -05002669 # Step6: Add VM to VM Group
2670 # Find VM uuid from vapp_uuid
sbhangarea8e5b782018-06-21 02:10:03 -07002671 vm_details = self.get_vapp_details_rest(vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01002672 vm_uuid = vm_details["vmuuid"]
sbhangarea8e5b782018-06-21 02:10:03 -07002673
2674 status = self.add_vm_to_vmgroup(vm_uuid, vmgrpname_url, vmgrp_name, headers)
2675 if status is not True:
sousaedu80135b92021-02-17 15:05:18 +01002676 msg = "new_vminstance(): Error in adding VM to VM group {}".format(
2677 vmgrp_name
2678 )
sbhangarea8e5b782018-06-21 02:10:03 -07002679 self.log_message(msg)
2680
beierlb22ce2d2019-12-12 12:09:51 -05002681 # Step7: Create VM to Host affinity rule
2682 addrule_href = self.get_add_rule_reference(respool_href, headers)
sbhangarea8e5b782018-06-21 02:10:03 -07002683 if addrule_href is None:
sousaedu80135b92021-02-17 15:05:18 +01002684 msg = "new_vminstance(): Error in finding href to add rule in resource pool: {}".format(
2685 respool_href
2686 )
sbhangarea8e5b782018-06-21 02:10:03 -07002687 self.log_message(msg)
2688
sousaedu80135b92021-02-17 15:05:18 +01002689 status = self.create_vm_to_host_affinity_rule(
2690 addrule_href, vmgrp_name, vm_az, "Affinity", headers
2691 )
sbhangarea8e5b782018-06-21 02:10:03 -07002692 if status is False:
sousaedu80135b92021-02-17 15:05:18 +01002693 msg = "new_vminstance(): Error in creating affinity rule for VM {} in Host group {}".format(
2694 name, vm_az
2695 )
sbhangarea8e5b782018-06-21 02:10:03 -07002696 self.log_message(msg)
2697 else:
sousaedu80135b92021-02-17 15:05:18 +01002698 self.logger.debug(
2699 "new_vminstance(): Affinity rule created successfully. Added {} in Host group {}".format(
2700 name, vm_az
2701 )
2702 )
beierlb22ce2d2019-12-12 12:09:51 -05002703 # Reset token to a normal user to perform other operations
sbhangarea8e5b782018-06-21 02:10:03 -07002704 self.get_token()
2705
bayramovef390722016-09-27 03:34:46 -07002706 if vapp_uuid is not None:
tierno98e909c2017-10-14 13:27:03 +02002707 return vapp_uuid, None
bayramovbd6160f2016-09-28 04:12:05 +04002708 else:
sousaedu80135b92021-02-17 15:05:18 +01002709 raise vimconn.VimConnUnexpectedResponse(
2710 "new_vminstance(): Failed create new vm instance {}".format(name)
2711 )
bayramov325fa1c2016-09-08 01:42:46 -07002712
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002713 def create_config_drive_iso(self, user_data):
2714 tmpdir = tempfile.mkdtemp()
sousaedu80135b92021-02-17 15:05:18 +01002715 iso_path = os.path.join(tmpdir, "ConfigDrive.iso")
2716 latest_dir = os.path.join(tmpdir, "openstack", "latest")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002717 os.makedirs(latest_dir)
sousaedu80135b92021-02-17 15:05:18 +01002718 with open(
2719 os.path.join(latest_dir, "meta_data.json"), "w"
2720 ) as meta_file_obj, open(
2721 os.path.join(latest_dir, "user_data"), "w"
2722 ) as userdata_file_obj:
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002723 userdata_file_obj.write(user_data)
sousaedu80135b92021-02-17 15:05:18 +01002724 meta_file_obj.write(
2725 json.dumps(
2726 {
2727 "availability_zone": "nova",
2728 "launch_index": 0,
2729 "name": "ConfigDrive",
2730 "uuid": str(uuid.uuid4()),
2731 }
2732 )
2733 )
2734 genisoimage_cmd = (
2735 "genisoimage -J -r -V config-2 -o {iso_path} {source_dir_path}".format(
2736 iso_path=iso_path, source_dir_path=tmpdir
2737 )
2738 )
2739 self.logger.info(
2740 'create_config_drive_iso(): Creating ISO by running command "{}"'.format(
2741 genisoimage_cmd
2742 )
2743 )
2744
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002745 try:
sousaedu80135b92021-02-17 15:05:18 +01002746 FNULL = open(os.devnull, "w")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002747 subprocess.check_call(genisoimage_cmd, shell=True, stdout=FNULL)
2748 except subprocess.CalledProcessError as e:
2749 shutil.rmtree(tmpdir, ignore_errors=True)
sousaedu80135b92021-02-17 15:05:18 +01002750 error_msg = "create_config_drive_iso(): Exception while running genisoimage command: {}".format(
2751 e
2752 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002753 self.logger.error(error_msg)
2754 raise Exception(error_msg)
sousaedu80135b92021-02-17 15:05:18 +01002755
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002756 return iso_path
2757
2758 def upload_iso_to_catalog(self, catalog_id, iso_file_path):
2759 if not os.path.isfile(iso_file_path):
sousaedu80135b92021-02-17 15:05:18 +01002760 error_msg = "upload_iso_to_catalog(): Given iso file is not present. Given path: {}".format(
2761 iso_file_path
2762 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002763 self.logger.error(error_msg)
2764 raise Exception(error_msg)
sousaedu80135b92021-02-17 15:05:18 +01002765
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002766 iso_file_stat = os.stat(iso_file_path)
sousaedu80135b92021-02-17 15:05:18 +01002767 xml_media_elem = """<?xml version="1.0" encoding="UTF-8"?>
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002768 <Media
2769 xmlns="http://www.vmware.com/vcloud/v1.5"
2770 name="{iso_name}"
2771 size="{iso_size}"
2772 imageType="iso">
2773 <Description>ISO image for config-drive</Description>
sousaedu80135b92021-02-17 15:05:18 +01002774 </Media>""".format(
2775 iso_name=os.path.basename(iso_file_path), iso_size=iso_file_stat.st_size
2776 )
2777 headers = {
2778 "Accept": "application/*+xml;version=" + API_VERSION,
2779 "x-vcloud-authorization": self.client._session.headers[
2780 "x-vcloud-authorization"
2781 ],
2782 }
2783 headers["Content-Type"] = "application/vnd.vmware.vcloud.media+xml"
2784 catalog_href = self.url + "/api/catalog/" + catalog_id + "/action/upload"
2785 response = self.perform_request(
2786 req_type="POST", url=catalog_href, headers=headers, data=xml_media_elem
2787 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002788
2789 if response.status_code != 201:
sousaedu80135b92021-02-17 15:05:18 +01002790 error_msg = "upload_iso_to_catalog(): Failed to POST an action/upload request to {}".format(
2791 catalog_href
2792 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002793 self.logger.error(error_msg)
2794 raise Exception(error_msg)
2795
beierl26fec002019-12-06 17:06:40 -05002796 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002797 entity = [
2798 child
2799 for child in catalogItem
2800 if child.get("type") == "application/vnd.vmware.vcloud.media+xml"
2801 ][0]
2802 entity_href = entity.get("href")
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002803
sousaedu80135b92021-02-17 15:05:18 +01002804 response = self.perform_request(
2805 req_type="GET", url=entity_href, headers=headers
2806 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002807 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01002808 raise Exception(
2809 "upload_iso_to_catalog(): Failed to GET entity href {}".format(
2810 entity_href
2811 )
2812 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002813
sousaedu80135b92021-02-17 15:05:18 +01002814 match = re.search(
2815 r'<Files>\s+?<File.+?href="(.+?)"/>\s+?</File>\s+?</Files>',
2816 response.text,
2817 re.DOTALL,
2818 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002819 if match:
2820 media_upload_href = match.group(1)
2821 else:
sousaedu80135b92021-02-17 15:05:18 +01002822 raise Exception(
2823 "Could not parse the upload URL for the media file from the last response"
2824 )
beierl26fec002019-12-06 17:06:40 -05002825 upload_iso_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01002826 headers["Content-Type"] = "application/octet-stream"
2827 response = self.perform_request(
2828 req_type="PUT",
2829 url=media_upload_href,
2830 headers=headers,
2831 data=open(iso_file_path, "rb"),
2832 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00002833
2834 if response.status_code != 200:
2835 raise Exception('PUT request to "{}" failed'.format(media_upload_href))
sousaedu80135b92021-02-17 15:05:18 +01002836
Ananda Baitharub23558c2019-06-18 13:53:37 +00002837 result = self.client.get_task_monitor().wait_for_success(task=upload_iso_task)
sousaedu80135b92021-02-17 15:05:18 +01002838 if result.get("status") != "success":
2839 raise Exception(
2840 "The upload iso task failed with status {}".format(result.get("status"))
2841 )
sbhangarea8e5b782018-06-21 02:10:03 -07002842
beierlb22ce2d2019-12-12 12:09:51 -05002843 def get_vcd_availibility_zones(self, respool_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01002844 """Method to find presence of av zone is VIM resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07002845
sousaedu80135b92021-02-17 15:05:18 +01002846 Args:
2847 respool_href - resource pool href
2848 headers - header information
sbhangarea8e5b782018-06-21 02:10:03 -07002849
sousaedu80135b92021-02-17 15:05:18 +01002850 Returns:
2851 vcd_az - list of azone present in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002852 """
2853 vcd_az = []
beierlb22ce2d2019-12-12 12:09:51 -05002854 url = respool_href
sousaedu80135b92021-02-17 15:05:18 +01002855 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07002856
2857 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01002858 self.logger.debug(
2859 "REST API call {} failed. Return status code {}".format(
2860 url, resp.status_code
2861 )
2862 )
sbhangarea8e5b782018-06-21 02:10:03 -07002863 else:
beierlb22ce2d2019-12-12 12:09:51 -05002864 # Get the href to hostGroups and find provided hostGroup is present in it
sbhangarea8e5b782018-06-21 02:10:03 -07002865 resp_xml = XmlElementTree.fromstring(resp.content)
2866 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01002867 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07002868 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01002869 if "Link" in schild.tag:
2870 if (
2871 schild.attrib.get("type")
2872 == "application/vnd.vmware.admin.vmwHostGroupsType+xml"
2873 ):
2874 hostGroup = schild.attrib.get("href")
2875 hg_resp = self.perform_request(
2876 req_type="GET", url=hostGroup, headers=headers
2877 )
2878
sbhangarea8e5b782018-06-21 02:10:03 -07002879 if hg_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01002880 self.logger.debug(
2881 "REST API call {} failed. Return status code {}".format(
2882 hostGroup, hg_resp.status_code
2883 )
2884 )
sbhangarea8e5b782018-06-21 02:10:03 -07002885 else:
sousaedu80135b92021-02-17 15:05:18 +01002886 hg_resp_xml = XmlElementTree.fromstring(
2887 hg_resp.content
2888 )
sbhangarea8e5b782018-06-21 02:10:03 -07002889 for hostGroup in hg_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01002890 if "HostGroup" in hostGroup.tag:
beierlb22ce2d2019-12-12 12:09:51 -05002891 # append host group name to the list
sbhangarea8e5b782018-06-21 02:10:03 -07002892 vcd_az.append(hostGroup.attrib.get("name"))
sousaedu80135b92021-02-17 15:05:18 +01002893
sbhangarea8e5b782018-06-21 02:10:03 -07002894 return vcd_az
2895
sbhangarea8e5b782018-06-21 02:10:03 -07002896 def set_availability_zones(self):
2897 """
2898 Set vim availability zone
2899 """
sbhangarea8e5b782018-06-21 02:10:03 -07002900 vim_availability_zones = None
2901 availability_zone = None
sousaedu80135b92021-02-17 15:05:18 +01002902
2903 if "availability_zone" in self.config:
2904 vim_availability_zones = self.config.get("availability_zone")
2905
sbhangarea8e5b782018-06-21 02:10:03 -07002906 if isinstance(vim_availability_zones, str):
2907 availability_zone = [vim_availability_zones]
2908 elif isinstance(vim_availability_zones, list):
2909 availability_zone = vim_availability_zones
2910 else:
2911 return availability_zone
2912
2913 return availability_zone
2914
sbhangarea8e5b782018-06-21 02:10:03 -07002915 def get_vm_availability_zone(self, availability_zone_index, availability_zone_list):
2916 """
2917 Return the availability zone to be used by the created VM.
2918 returns: The VIM availability zone to be used or None
2919 """
2920 if availability_zone_index is None:
sousaedu80135b92021-02-17 15:05:18 +01002921 if not self.config.get("availability_zone"):
sbhangarea8e5b782018-06-21 02:10:03 -07002922 return None
sousaedu80135b92021-02-17 15:05:18 +01002923 elif isinstance(self.config.get("availability_zone"), str):
2924 return self.config["availability_zone"]
sbhangarea8e5b782018-06-21 02:10:03 -07002925 else:
sousaedu80135b92021-02-17 15:05:18 +01002926 return self.config["availability_zone"][0]
sbhangarea8e5b782018-06-21 02:10:03 -07002927
2928 vim_availability_zones = self.availability_zone
2929
2930 # check if VIM offer enough availability zones describe in the VNFD
sousaedu80135b92021-02-17 15:05:18 +01002931 if vim_availability_zones and len(availability_zone_list) <= len(
2932 vim_availability_zones
2933 ):
sbhangarea8e5b782018-06-21 02:10:03 -07002934 # check if all the names of NFV AV match VIM AV names
2935 match_by_index = False
2936 for av in availability_zone_list:
2937 if av not in vim_availability_zones:
2938 match_by_index = True
2939 break
sousaedu80135b92021-02-17 15:05:18 +01002940
sbhangarea8e5b782018-06-21 02:10:03 -07002941 if match_by_index:
sousaedu80135b92021-02-17 15:05:18 +01002942 self.logger.debug(
2943 "Required Availability zone or Host Group not found in VIM config"
2944 )
2945 self.logger.debug(
2946 "Input Availability zone list: {}".format(availability_zone_list)
2947 )
2948 self.logger.debug(
2949 "VIM configured Availability zones: {}".format(
2950 vim_availability_zones
2951 )
2952 )
sbhangarea8e5b782018-06-21 02:10:03 -07002953 self.logger.debug("VIM Availability zones will be used by index")
2954 return vim_availability_zones[availability_zone_index]
2955 else:
2956 return availability_zone_list[availability_zone_index]
2957 else:
sousaedu80135b92021-02-17 15:05:18 +01002958 raise vimconn.VimConnConflictException(
2959 "No enough availability zones at VIM for this deployment"
2960 )
sbhangarea8e5b782018-06-21 02:10:03 -07002961
sousaedu80135b92021-02-17 15:05:18 +01002962 def create_vm_to_host_affinity_rule(
2963 self, addrule_href, vmgrpname, hostgrpname, polarity, headers
2964 ):
2965 """Method to create VM to Host Affinity rule in vCD
sbhangarea8e5b782018-06-21 02:10:03 -07002966
2967 Args:
2968 addrule_href - href to make a POST request
2969 vmgrpname - name of the VM group created
2970 hostgrpnmae - name of the host group created earlier
2971 polarity - Affinity or Anti-affinity (default: Affinity)
2972 headers - headers to make REST call
2973
2974 Returns:
2975 True- if rule is created
2976 False- Failed to create rule due to some error
2977
2978 """
2979 task_status = False
2980 rule_name = polarity + "_" + vmgrpname
2981 payload = """<?xml version="1.0" encoding="UTF-8"?>
2982 <vmext:VMWVmHostAffinityRule
2983 xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5"
2984 xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
2985 type="application/vnd.vmware.admin.vmwVmHostAffinityRule+xml">
2986 <vcloud:Name>{}</vcloud:Name>
2987 <vcloud:IsEnabled>true</vcloud:IsEnabled>
2988 <vcloud:IsMandatory>true</vcloud:IsMandatory>
2989 <vcloud:Polarity>{}</vcloud:Polarity>
2990 <vmext:HostGroupName>{}</vmext:HostGroupName>
2991 <vmext:VmGroupName>{}</vmext:VmGroupName>
sousaedu80135b92021-02-17 15:05:18 +01002992 </vmext:VMWVmHostAffinityRule>""".format(
2993 rule_name, polarity, hostgrpname, vmgrpname
2994 )
sbhangarea8e5b782018-06-21 02:10:03 -07002995
sousaedu80135b92021-02-17 15:05:18 +01002996 resp = self.perform_request(
2997 req_type="POST", url=addrule_href, headers=headers, data=payload
2998 )
sbhangarea8e5b782018-06-21 02:10:03 -07002999
3000 if resp.status_code != requests.codes.accepted:
sousaedu80135b92021-02-17 15:05:18 +01003001 self.logger.debug(
3002 "REST API call {} failed. Return status code {}".format(
3003 addrule_href, resp.status_code
3004 )
3005 )
sbhangarea8e5b782018-06-21 02:10:03 -07003006 task_status = False
sousaedu80135b92021-02-17 15:05:18 +01003007
sbhangarea8e5b782018-06-21 02:10:03 -07003008 return task_status
3009 else:
3010 affinity_task = self.get_task_from_response(resp.content)
beierlb22ce2d2019-12-12 12:09:51 -05003011 self.logger.debug("affinity_task: {}".format(affinity_task))
sousaedu80135b92021-02-17 15:05:18 +01003012
sbhangarea8e5b782018-06-21 02:10:03 -07003013 if affinity_task is None or affinity_task is False:
tierno72774862020-05-04 11:44:15 +00003014 raise vimconn.VimConnUnexpectedResponse("failed to find affinity task")
sbhangarea8e5b782018-06-21 02:10:03 -07003015 # wait for task to complete
3016 result = self.client.get_task_monitor().wait_for_success(task=affinity_task)
sousaedu80135b92021-02-17 15:05:18 +01003017
3018 if result.get("status") == "success":
3019 self.logger.debug(
3020 "Successfully created affinity rule {}".format(rule_name)
3021 )
sbhangarea8e5b782018-06-21 02:10:03 -07003022 return True
3023 else:
tierno72774862020-05-04 11:44:15 +00003024 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01003025 "failed to create affinity rule {}".format(rule_name)
3026 )
sbhangarea8e5b782018-06-21 02:10:03 -07003027
beierlb22ce2d2019-12-12 12:09:51 -05003028 def get_add_rule_reference(self, respool_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01003029 """This method finds href to add vm to host affinity rule to vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003030
3031 Args:
3032 respool_href- href to resource pool
3033 headers- header information to make REST call
3034
3035 Returns:
3036 None - if no valid href to add rule found or
3037 addrule_href - href to add vm to host affinity rule of resource pool
3038 """
3039 addrule_href = None
sousaedu80135b92021-02-17 15:05:18 +01003040 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003041
3042 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003043 self.logger.debug(
3044 "REST API call {} failed. Return status code {}".format(
3045 respool_href, resp.status_code
3046 )
3047 )
sbhangarea8e5b782018-06-21 02:10:03 -07003048 else:
sbhangarea8e5b782018-06-21 02:10:03 -07003049 resp_xml = XmlElementTree.fromstring(resp.content)
3050 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003051 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003052 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01003053 if "Link" in schild.tag:
3054 if (
3055 schild.attrib.get("type")
3056 == "application/vnd.vmware.admin.vmwVmHostAffinityRule+xml"
3057 and schild.attrib.get("rel") == "add"
3058 ):
3059 addrule_href = schild.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003060 break
3061
3062 return addrule_href
3063
sbhangarea8e5b782018-06-21 02:10:03 -07003064 def add_vm_to_vmgroup(self, vm_uuid, vmGroupNameURL, vmGroup_name, headers):
sousaedu80135b92021-02-17 15:05:18 +01003065 """Method to add deployed VM to newly created VM Group.
sbhangarea8e5b782018-06-21 02:10:03 -07003066 This is required to create VM to Host affinity in vCD
3067
3068 Args:
3069 vm_uuid- newly created vm uuid
3070 vmGroupNameURL- URL to VM Group name
3071 vmGroup_name- Name of VM group created
3072 headers- Headers for REST request
3073
3074 Returns:
3075 True- if VM added to VM group successfully
3076 False- if any error encounter
3077 """
sousaedu80135b92021-02-17 15:05:18 +01003078 addvm_resp = self.perform_request(
3079 req_type="GET", url=vmGroupNameURL, headers=headers
3080 ) # , data=payload)
sbhangarea8e5b782018-06-21 02:10:03 -07003081
3082 if addvm_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003083 self.logger.debug(
3084 "REST API call to get VM Group Name url {} failed. Return status code {}".format(
3085 vmGroupNameURL, addvm_resp.status_code
3086 )
3087 )
sbhangarea8e5b782018-06-21 02:10:03 -07003088 return False
3089 else:
3090 resp_xml = XmlElementTree.fromstring(addvm_resp.content)
3091 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003092 if child.tag.split("}")[1] == "Link":
sbhangarea8e5b782018-06-21 02:10:03 -07003093 if child.attrib.get("rel") == "addVms":
beierlb22ce2d2019-12-12 12:09:51 -05003094 addvmtogrpURL = child.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003095
beierlb22ce2d2019-12-12 12:09:51 -05003096 # Get vm details
sousaedu80135b92021-02-17 15:05:18 +01003097 url_list = [self.url, "/api/vApp/vm-", vm_uuid]
3098 vmdetailsURL = "".join(url_list)
sbhangarea8e5b782018-06-21 02:10:03 -07003099
sousaedu80135b92021-02-17 15:05:18 +01003100 resp = self.perform_request(req_type="GET", url=vmdetailsURL, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003101
3102 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003103 self.logger.debug(
3104 "REST API call {} failed. Return status code {}".format(
3105 vmdetailsURL, resp.status_code
3106 )
3107 )
sbhangarea8e5b782018-06-21 02:10:03 -07003108 return False
3109
beierlb22ce2d2019-12-12 12:09:51 -05003110 # Parse VM details
sbhangarea8e5b782018-06-21 02:10:03 -07003111 resp_xml = XmlElementTree.fromstring(resp.content)
sousaedu80135b92021-02-17 15:05:18 +01003112 if resp_xml.tag.split("}")[1] == "Vm":
sbhangarea8e5b782018-06-21 02:10:03 -07003113 vm_id = resp_xml.attrib.get("id")
3114 vm_name = resp_xml.attrib.get("name")
3115 vm_href = resp_xml.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05003116 # print vm_id, vm_name, vm_href
sousaedu80135b92021-02-17 15:05:18 +01003117
beierlb22ce2d2019-12-12 12:09:51 -05003118 # Add VM into VMgroup
sbhangarea8e5b782018-06-21 02:10:03 -07003119 payload = """<?xml version="1.0" encoding="UTF-8"?>\
3120 <ns2:Vms xmlns:ns2="http://www.vmware.com/vcloud/v1.5" \
3121 xmlns="http://www.vmware.com/vcloud/versions" \
3122 xmlns:ns3="http://schemas.dmtf.org/ovf/envelope/1" \
3123 xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" \
3124 xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/common" \
3125 xmlns:ns6="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData" \
3126 xmlns:ns7="http://www.vmware.com/schema/ovf" \
3127 xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1" \
3128 xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">\
3129 <ns2:VmReference href="{}" id="{}" name="{}" \
3130 type="application/vnd.vmware.vcloud.vm+xml" />\
sousaedu80135b92021-02-17 15:05:18 +01003131 </ns2:Vms>""".format(
3132 vm_href, vm_id, vm_name
3133 )
sbhangarea8e5b782018-06-21 02:10:03 -07003134
sousaedu80135b92021-02-17 15:05:18 +01003135 addvmtogrp_resp = self.perform_request(
3136 req_type="POST", url=addvmtogrpURL, headers=headers, data=payload
3137 )
sbhangarea8e5b782018-06-21 02:10:03 -07003138
3139 if addvmtogrp_resp.status_code != requests.codes.accepted:
sousaedu80135b92021-02-17 15:05:18 +01003140 self.logger.debug(
3141 "REST API call {} failed. Return status code {}".format(
3142 addvmtogrpURL, addvmtogrp_resp.status_code
3143 )
3144 )
3145
sbhangarea8e5b782018-06-21 02:10:03 -07003146 return False
3147 else:
sousaedu80135b92021-02-17 15:05:18 +01003148 self.logger.debug(
3149 "Done adding VM {} to VMgroup {}".format(vm_name, vmGroup_name)
3150 )
3151
sbhangarea8e5b782018-06-21 02:10:03 -07003152 return True
3153
sbhangarea8e5b782018-06-21 02:10:03 -07003154 def create_vmgroup(self, vmgroup_name, vmgroup_href, headers):
3155 """Method to create a VM group in vCD
3156
sousaedu80135b92021-02-17 15:05:18 +01003157 Args:
3158 vmgroup_name : Name of VM group to be created
3159 vmgroup_href : href for vmgroup
3160 headers- Headers for REST request
sbhangarea8e5b782018-06-21 02:10:03 -07003161 """
beierlb22ce2d2019-12-12 12:09:51 -05003162 # POST to add URL with required data
sbhangarea8e5b782018-06-21 02:10:03 -07003163 vmgroup_status = False
3164 payload = """<VMWVmGroup xmlns="http://www.vmware.com/vcloud/extension/v1.5" \
3165 xmlns:vcloud_v1.5="http://www.vmware.com/vcloud/v1.5" name="{}">\
3166 <vmCount>1</vmCount>\
sousaedu80135b92021-02-17 15:05:18 +01003167 </VMWVmGroup>""".format(
3168 vmgroup_name
3169 )
3170 resp = self.perform_request(
3171 req_type="POST", url=vmgroup_href, headers=headers, data=payload
3172 )
sbhangarea8e5b782018-06-21 02:10:03 -07003173
3174 if resp.status_code != requests.codes.accepted:
sousaedu80135b92021-02-17 15:05:18 +01003175 self.logger.debug(
3176 "REST API call {} failed. Return status code {}".format(
3177 vmgroup_href, resp.status_code
3178 )
3179 )
3180
sbhangarea8e5b782018-06-21 02:10:03 -07003181 return vmgroup_status
3182 else:
3183 vmgroup_task = self.get_task_from_response(resp.content)
3184 if vmgroup_task is None or vmgroup_task is False:
tierno72774862020-05-04 11:44:15 +00003185 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01003186 "create_vmgroup(): failed to create VM group {}".format(
3187 vmgroup_name
3188 )
3189 )
sbhangarea8e5b782018-06-21 02:10:03 -07003190
3191 # wait for task to complete
3192 result = self.client.get_task_monitor().wait_for_success(task=vmgroup_task)
3193
sousaedu80135b92021-02-17 15:05:18 +01003194 if result.get("status") == "success":
3195 self.logger.debug(
3196 "create_vmgroup(): Successfully created VM group {}".format(
3197 vmgroup_name
3198 )
3199 )
beierlb22ce2d2019-12-12 12:09:51 -05003200 # time.sleep(10)
sbhangarea8e5b782018-06-21 02:10:03 -07003201 vmgroup_status = True
sousaedu80135b92021-02-17 15:05:18 +01003202
sbhangarea8e5b782018-06-21 02:10:03 -07003203 return vmgroup_status
3204 else:
tierno72774862020-05-04 11:44:15 +00003205 raise vimconn.VimConnUnexpectedResponse(
sousaedu80135b92021-02-17 15:05:18 +01003206 "create_vmgroup(): failed to create VM group {}".format(
3207 vmgroup_name
3208 )
3209 )
sbhangarea8e5b782018-06-21 02:10:03 -07003210
3211 def find_vmgroup_reference(self, url, headers):
sousaedu80135b92021-02-17 15:05:18 +01003212 """Method to create a new VMGroup which is required to add created VM
3213 Args:
3214 url- resource pool href
3215 headers- header information
sbhangarea8e5b782018-06-21 02:10:03 -07003216
sousaedu80135b92021-02-17 15:05:18 +01003217 Returns:
3218 returns href to VM group to create VM group
sbhangarea8e5b782018-06-21 02:10:03 -07003219 """
beierlb22ce2d2019-12-12 12:09:51 -05003220 # Perform GET on resource pool to find 'add' link to create VMGroup
3221 # https://vcd-ip/api/admin/extension/providervdc/<providervdc id>/resourcePools
sbhangarea8e5b782018-06-21 02:10:03 -07003222 vmgrp_href = None
sousaedu80135b92021-02-17 15:05:18 +01003223 resp = self.perform_request(req_type="GET", url=url, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003224
3225 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003226 self.logger.debug(
3227 "REST API call {} failed. Return status code {}".format(
3228 url, resp.status_code
3229 )
3230 )
sbhangarea8e5b782018-06-21 02:10:03 -07003231 else:
beierlb22ce2d2019-12-12 12:09:51 -05003232 # Get the href to add vmGroup to vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003233 resp_xml = XmlElementTree.fromstring(resp.content)
3234 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003235 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003236 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01003237 if "Link" in schild.tag:
beierlb22ce2d2019-12-12 12:09:51 -05003238 # Find href with type VMGroup and rel with add
sousaedu80135b92021-02-17 15:05:18 +01003239 if (
3240 schild.attrib.get("type")
3241 == "application/vnd.vmware.admin.vmwVmGroupType+xml"
3242 and schild.attrib.get("rel") == "add"
3243 ):
3244 vmgrp_href = schild.attrib.get("href")
3245
sbhangarea8e5b782018-06-21 02:10:03 -07003246 return vmgrp_href
3247
sbhangarea8e5b782018-06-21 02:10:03 -07003248 def check_availibility_zone(self, az, respool_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01003249 """Method to verify requested av zone is present or not in provided
3250 resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07003251
sousaedu80135b92021-02-17 15:05:18 +01003252 Args:
3253 az - name of hostgroup (availibility_zone)
3254 respool_href - Resource Pool href
3255 headers - Headers to make REST call
3256 Returns:
3257 az_found - True if availibility_zone is found else False
sbhangarea8e5b782018-06-21 02:10:03 -07003258 """
3259 az_found = False
sousaedu80135b92021-02-17 15:05:18 +01003260 headers["Accept"] = "application/*+xml;version=27.0"
3261 resp = self.perform_request(req_type="GET", url=respool_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003262
3263 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003264 self.logger.debug(
3265 "REST API call {} failed. Return status code {}".format(
3266 respool_href, resp.status_code
3267 )
3268 )
sbhangarea8e5b782018-06-21 02:10:03 -07003269 else:
beierlb22ce2d2019-12-12 12:09:51 -05003270 # Get the href to hostGroups and find provided hostGroup is present in it
sbhangarea8e5b782018-06-21 02:10:03 -07003271 resp_xml = XmlElementTree.fromstring(resp.content)
3272
3273 for child in resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003274 if "VMWProviderVdcResourcePool" in child.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003275 for schild in child:
sousaedu80135b92021-02-17 15:05:18 +01003276 if "Link" in schild.tag:
3277 if (
3278 schild.attrib.get("type")
3279 == "application/vnd.vmware.admin.vmwHostGroupsType+xml"
3280 ):
3281 hostGroup_href = schild.attrib.get("href")
3282 hg_resp = self.perform_request(
3283 req_type="GET", url=hostGroup_href, headers=headers
3284 )
3285
sbhangarea8e5b782018-06-21 02:10:03 -07003286 if hg_resp.status_code != requests.codes.ok:
beierlb22ce2d2019-12-12 12:09:51 -05003287 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003288 "REST API call {} failed. Return status code {}".format(
3289 hostGroup_href, hg_resp.status_code
3290 )
3291 )
sbhangarea8e5b782018-06-21 02:10:03 -07003292 else:
sousaedu80135b92021-02-17 15:05:18 +01003293 hg_resp_xml = XmlElementTree.fromstring(
3294 hg_resp.content
3295 )
sbhangarea8e5b782018-06-21 02:10:03 -07003296 for hostGroup in hg_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003297 if "HostGroup" in hostGroup.tag:
sbhangarea8e5b782018-06-21 02:10:03 -07003298 if hostGroup.attrib.get("name") == az:
3299 az_found = True
3300 break
sousaedu80135b92021-02-17 15:05:18 +01003301
sbhangarea8e5b782018-06-21 02:10:03 -07003302 return az_found
3303
sbhangarea8e5b782018-06-21 02:10:03 -07003304 def get_pvdc_for_org(self, org_vdc, headers):
sousaedu80135b92021-02-17 15:05:18 +01003305 """This method gets provider vdc references from organisation
sbhangarea8e5b782018-06-21 02:10:03 -07003306
sousaedu80135b92021-02-17 15:05:18 +01003307 Args:
3308 org_vdc - name of the organisation VDC to find pvdc
3309 headers - headers to make REST call
sbhangarea8e5b782018-06-21 02:10:03 -07003310
sousaedu80135b92021-02-17 15:05:18 +01003311 Returns:
3312 None - if no pvdc href found else
3313 pvdc_href - href to pvdc
sbhangarea8e5b782018-06-21 02:10:03 -07003314 """
beierlb22ce2d2019-12-12 12:09:51 -05003315 # Get provider VDC references from vCD
sbhangarea8e5b782018-06-21 02:10:03 -07003316 pvdc_href = None
beierlb22ce2d2019-12-12 12:09:51 -05003317 # url = '<vcd url>/api/admin/extension/providerVdcReferences'
sousaedu80135b92021-02-17 15:05:18 +01003318 url_list = [self.url, "/api/admin/extension/providerVdcReferences"]
3319 url = "".join(url_list)
sbhangarea8e5b782018-06-21 02:10:03 -07003320
sousaedu80135b92021-02-17 15:05:18 +01003321 response = self.perform_request(req_type="GET", url=url, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003322 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003323 self.logger.debug(
3324 "REST API call {} failed. Return status code {}".format(
3325 url, response.status_code
3326 )
3327 )
sbhangarea8e5b782018-06-21 02:10:03 -07003328 else:
beierl26fec002019-12-06 17:06:40 -05003329 xmlroot_response = XmlElementTree.fromstring(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -07003330 for child in xmlroot_response:
sousaedu80135b92021-02-17 15:05:18 +01003331 if "ProviderVdcReference" in child.tag:
3332 pvdc_href = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05003333 # Get vdcReferences to find org
sousaedu80135b92021-02-17 15:05:18 +01003334 pvdc_resp = self.perform_request(
3335 req_type="GET", url=pvdc_href, headers=headers
3336 )
3337
sbhangarea8e5b782018-06-21 02:10:03 -07003338 if pvdc_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003339 raise vimconn.VimConnException(
3340 "REST API call {} failed. "
3341 "Return status code {}".format(url, pvdc_resp.status_code)
3342 )
sbhangarea8e5b782018-06-21 02:10:03 -07003343
3344 pvdc_resp_xml = XmlElementTree.fromstring(pvdc_resp.content)
3345 for child in pvdc_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003346 if "Link" in child.tag:
3347 if (
3348 child.attrib.get("type")
3349 == "application/vnd.vmware.admin.vdcReferences+xml"
3350 ):
3351 vdc_href = child.attrib.get("href")
sbhangarea8e5b782018-06-21 02:10:03 -07003352
beierlb22ce2d2019-12-12 12:09:51 -05003353 # Check if provided org is present in vdc
sousaedu80135b92021-02-17 15:05:18 +01003354 vdc_resp = self.perform_request(
3355 req_type="GET", url=vdc_href, headers=headers
3356 )
3357
sbhangarea8e5b782018-06-21 02:10:03 -07003358 if vdc_resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003359 raise vimconn.VimConnException(
3360 "REST API call {} failed. "
3361 "Return status code {}".format(
3362 url, vdc_resp.status_code
3363 )
3364 )
3365 vdc_resp_xml = XmlElementTree.fromstring(
3366 vdc_resp.content
3367 )
3368
sbhangarea8e5b782018-06-21 02:10:03 -07003369 for child in vdc_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003370 if "VdcReference" in child.tag:
3371 if child.attrib.get("name") == org_vdc:
sbhangarea8e5b782018-06-21 02:10:03 -07003372 return pvdc_href
3373
sbhangarea8e5b782018-06-21 02:10:03 -07003374 def get_resource_pool_details(self, pvdc_href, headers):
sousaedu80135b92021-02-17 15:05:18 +01003375 """Method to get resource pool information.
3376 Host groups are property of resource group.
3377 To get host groups, we need to GET details of resource pool.
sbhangarea8e5b782018-06-21 02:10:03 -07003378
sousaedu80135b92021-02-17 15:05:18 +01003379 Args:
3380 pvdc_href: href to pvdc details
3381 headers: headers
sbhangarea8e5b782018-06-21 02:10:03 -07003382
sousaedu80135b92021-02-17 15:05:18 +01003383 Returns:
3384 respool_href - Returns href link reference to resource pool
sbhangarea8e5b782018-06-21 02:10:03 -07003385 """
3386 respool_href = None
sousaedu80135b92021-02-17 15:05:18 +01003387 resp = self.perform_request(req_type="GET", url=pvdc_href, headers=headers)
sbhangarea8e5b782018-06-21 02:10:03 -07003388
3389 if resp.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01003390 self.logger.debug(
3391 "REST API call {} failed. Return status code {}".format(
3392 pvdc_href, resp.status_code
3393 )
3394 )
sbhangarea8e5b782018-06-21 02:10:03 -07003395 else:
3396 respool_resp_xml = XmlElementTree.fromstring(resp.content)
3397 for child in respool_resp_xml:
sousaedu80135b92021-02-17 15:05:18 +01003398 if "Link" in child.tag:
3399 if (
3400 child.attrib.get("type")
3401 == "application/vnd.vmware.admin.vmwProviderVdcResourcePoolSet+xml"
3402 ):
sbhangarea8e5b782018-06-21 02:10:03 -07003403 respool_href = child.attrib.get("href")
3404 break
sousaedu80135b92021-02-17 15:05:18 +01003405
sbhangarea8e5b782018-06-21 02:10:03 -07003406 return respool_href
3407
sbhangarea8e5b782018-06-21 02:10:03 -07003408 def log_message(self, msg):
3409 """
sousaedu80135b92021-02-17 15:05:18 +01003410 Method to log error messages related to Affinity rule creation
3411 in new_vminstance & raise Exception
3412 Args :
3413 msg - Error message to be logged
sbhangarea8e5b782018-06-21 02:10:03 -07003414
3415 """
beierlb22ce2d2019-12-12 12:09:51 -05003416 # get token to connect vCD as a normal user
sbhangarea8e5b782018-06-21 02:10:03 -07003417 self.get_token()
3418 self.logger.debug(msg)
sousaedu80135b92021-02-17 15:05:18 +01003419
tierno72774862020-05-04 11:44:15 +00003420 raise vimconn.VimConnException(msg)
sbhangarea8e5b782018-06-21 02:10:03 -07003421
beierlb22ce2d2019-12-12 12:09:51 -05003422 # #
3423 # #
3424 # # based on current discussion
3425 # #
3426 # #
3427 # # server:
bayramovef390722016-09-27 03:34:46 -07003428 # created: '2016-09-08T11:51:58'
3429 # description: simple-instance.linux1.1
3430 # flavor: ddc6776e-75a9-11e6-ad5f-0800273e724c
3431 # hostId: e836c036-74e7-11e6-b249-0800273e724c
3432 # image: dde30fe6-75a9-11e6-ad5f-0800273e724c
3433 # status: ACTIVE
3434 # error_msg:
3435 # interfaces: …
3436 #
bayramovfe3f3c92016-10-04 07:53:41 +04003437 def get_vminstance(self, vim_vm_uuid=None):
bayramov5761ad12016-10-04 09:00:30 +04003438 """Returns the VM instance information from VIM"""
bayramovef390722016-09-27 03:34:46 -07003439 self.logger.debug("Client requesting vm instance {} ".format(vim_vm_uuid))
bayramov325fa1c2016-09-08 01:42:46 -07003440
beierlb22ce2d2019-12-12 12:09:51 -05003441 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07003442 if vdc is None:
tierno72774862020-05-04 11:44:15 +00003443 raise vimconn.VimConnConnectionException(
sousaedu80135b92021-02-17 15:05:18 +01003444 "Failed to get a reference of VDC for a tenant {}".format(
3445 self.tenant_name
3446 )
3447 )
bayramov325fa1c2016-09-08 01:42:46 -07003448
bayramovfe3f3c92016-10-04 07:53:41 +04003449 vm_info_dict = self.get_vapp_details_rest(vapp_uuid=vim_vm_uuid)
3450 if not vm_info_dict:
sousaedu80135b92021-02-17 15:05:18 +01003451 self.logger.debug(
3452 "get_vminstance(): Failed to get vApp name by UUID {}".format(
3453 vim_vm_uuid
3454 )
3455 )
3456 raise vimconn.VimConnNotFoundException(
3457 "Failed to get vApp name by UUID {}".format(vim_vm_uuid)
3458 )
bayramov325fa1c2016-09-08 01:42:46 -07003459
sousaedu80135b92021-02-17 15:05:18 +01003460 status_key = vm_info_dict["status"]
3461 error = ""
bayramovef390722016-09-27 03:34:46 -07003462 try:
sousaedu80135b92021-02-17 15:05:18 +01003463 vm_dict = {
3464 "created": vm_info_dict["created"],
3465 "description": vm_info_dict["name"],
3466 "status": vcdStatusCode2manoFormat[int(status_key)],
3467 "hostId": vm_info_dict["vmuuid"],
3468 "error_msg": error,
3469 "vim_info": yaml.safe_dump(vm_info_dict),
3470 "interfaces": [],
3471 }
bayramovef390722016-09-27 03:34:46 -07003472
sousaedu80135b92021-02-17 15:05:18 +01003473 if "interfaces" in vm_info_dict:
3474 vm_dict["interfaces"] = vm_info_dict["interfaces"]
bayramovfe3f3c92016-10-04 07:53:41 +04003475 else:
sousaedu80135b92021-02-17 15:05:18 +01003476 vm_dict["interfaces"] = []
bayramovfe3f3c92016-10-04 07:53:41 +04003477 except KeyError:
sousaedu80135b92021-02-17 15:05:18 +01003478 vm_dict = {
3479 "created": "",
3480 "description": "",
3481 "status": vcdStatusCode2manoFormat[int(-1)],
3482 "hostId": vm_info_dict["vmuuid"],
3483 "error_msg": "Inconsistency state",
3484 "vim_info": yaml.safe_dump(vm_info_dict),
3485 "interfaces": [],
3486 }
bayramovef390722016-09-27 03:34:46 -07003487
3488 return vm_dict
3489
tierno98e909c2017-10-14 13:27:03 +02003490 def delete_vminstance(self, vm__vim_uuid, created_items=None):
bayramovef390722016-09-27 03:34:46 -07003491 """Method poweroff and remove VM instance from vcloud director network.
3492
3493 Args:
3494 vm__vim_uuid: VM UUID
3495
3496 Returns:
3497 Returns the instance identifier
3498 """
sousaedu80135b92021-02-17 15:05:18 +01003499 self.logger.debug(
3500 "Client requesting delete vm instance {} ".format(vm__vim_uuid)
3501 )
bayramov325fa1c2016-09-08 01:42:46 -07003502
beierl01bd6692019-12-09 17:06:20 -05003503 _, vdc = self.get_vdc_details()
sousaedu80135b92021-02-17 15:05:18 +01003504 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08003505 if vdc_obj is None:
sousaedu80135b92021-02-17 15:05:18 +01003506 self.logger.debug(
3507 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
3508 self.tenant_name
3509 )
3510 )
tierno72774862020-05-04 11:44:15 +00003511 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +01003512 "delete_vminstance(): Failed to get a reference of VDC for a tenant {}".format(
3513 self.tenant_name
3514 )
3515 )
bayramov325fa1c2016-09-08 01:42:46 -07003516
bayramovef390722016-09-27 03:34:46 -07003517 try:
kasarc5bf2932018-03-09 04:15:22 -08003518 vapp_name = self.get_namebyvappid(vm__vim_uuid)
bayramovef390722016-09-27 03:34:46 -07003519 if vapp_name is None:
sousaedu80135b92021-02-17 15:05:18 +01003520 self.logger.debug(
3521 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3522 vm__vim_uuid
3523 )
3524 )
3525
3526 return (
3527 -1,
3528 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3529 vm__vim_uuid
3530 ),
3531 )
3532
3533 self.logger.info(
3534 "Deleting vApp {} and UUID {}".format(vapp_name, vm__vim_uuid)
3535 )
Ravi Chamarty41840092018-10-31 16:12:38 +00003536 vapp_resource = vdc_obj.get_vapp(vapp_name)
3537 vapp = VApp(self.client, resource=vapp_resource)
bayramov325fa1c2016-09-08 01:42:46 -07003538
bayramovef390722016-09-27 03:34:46 -07003539 # Delete vApp and wait for status change if task executed and vApp is None.
kate13ab2c42016-12-23 01:34:24 -08003540 if vapp:
sousaedu80135b92021-02-17 15:05:18 +01003541 if vapp_resource.get("deployed") == "true":
kate13ab2c42016-12-23 01:34:24 -08003542 self.logger.info("Powering off vApp {}".format(vapp_name))
beierl01bd6692019-12-09 17:06:20 -05003543 # Power off vApp
kate13ab2c42016-12-23 01:34:24 -08003544 powered_off = False
3545 wait_time = 0
sousaedu80135b92021-02-17 15:05:18 +01003546
kate13ab2c42016-12-23 01:34:24 -08003547 while wait_time <= MAX_WAIT_TIME:
kasarc5bf2932018-03-09 04:15:22 -08003548 power_off_task = vapp.power_off()
sousaedu80135b92021-02-17 15:05:18 +01003549 result = self.client.get_task_monitor().wait_for_success(
3550 task=power_off_task
3551 )
bayramovef390722016-09-27 03:34:46 -07003552
sousaedu80135b92021-02-17 15:05:18 +01003553 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003554 powered_off = True
3555 break
kate13ab2c42016-12-23 01:34:24 -08003556 else:
sousaedu80135b92021-02-17 15:05:18 +01003557 self.logger.info(
3558 "Wait for vApp {} to power off".format(vapp_name)
3559 )
kate13ab2c42016-12-23 01:34:24 -08003560 time.sleep(INTERVAL_TIME)
3561
beierl01bd6692019-12-09 17:06:20 -05003562 wait_time += INTERVAL_TIME
sousaedu80135b92021-02-17 15:05:18 +01003563
kate13ab2c42016-12-23 01:34:24 -08003564 if not powered_off:
beierl01bd6692019-12-09 17:06:20 -05003565 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003566 "delete_vminstance(): Failed to power off VM instance {} ".format(
3567 vm__vim_uuid
3568 )
3569 )
kate13ab2c42016-12-23 01:34:24 -08003570 else:
sousaedu80135b92021-02-17 15:05:18 +01003571 self.logger.info(
3572 "delete_vminstance(): Powered off VM instance {} ".format(
3573 vm__vim_uuid
3574 )
3575 )
kate13ab2c42016-12-23 01:34:24 -08003576
beierl01bd6692019-12-09 17:06:20 -05003577 # Undeploy vApp
kate13ab2c42016-12-23 01:34:24 -08003578 self.logger.info("Undeploy vApp {}".format(vapp_name))
3579 wait_time = 0
3580 undeployed = False
3581 while wait_time <= MAX_WAIT_TIME:
sbhangarea8e5b782018-06-21 02:10:03 -07003582 vapp = VApp(self.client, resource=vapp_resource)
kate13ab2c42016-12-23 01:34:24 -08003583 if not vapp:
beierl01bd6692019-12-09 17:06:20 -05003584 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003585 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3586 vm__vim_uuid
3587 )
3588 )
kate13ab2c42016-12-23 01:34:24 -08003589
sousaedu80135b92021-02-17 15:05:18 +01003590 return (
3591 -1,
3592 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3593 vm__vim_uuid
3594 ),
3595 )
3596
3597 undeploy_task = vapp.undeploy()
3598 result = self.client.get_task_monitor().wait_for_success(
3599 task=undeploy_task
3600 )
3601
3602 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003603 undeployed = True
3604 break
kate13ab2c42016-12-23 01:34:24 -08003605 else:
sousaedu80135b92021-02-17 15:05:18 +01003606 self.logger.debug(
3607 "Wait for vApp {} to undeploy".format(vapp_name)
3608 )
kate13ab2c42016-12-23 01:34:24 -08003609 time.sleep(INTERVAL_TIME)
3610
beierl01bd6692019-12-09 17:06:20 -05003611 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08003612
3613 if not undeployed:
sousaedu80135b92021-02-17 15:05:18 +01003614 self.logger.debug(
3615 "delete_vminstance(): Failed to undeploy vApp {} ".format(
3616 vm__vim_uuid
3617 )
3618 )
kate13ab2c42016-12-23 01:34:24 -08003619
3620 # delete vapp
3621 self.logger.info("Start deletion of vApp {} ".format(vapp_name))
kate13ab2c42016-12-23 01:34:24 -08003622 if vapp is not None:
3623 wait_time = 0
3624 result = False
3625
3626 while wait_time <= MAX_WAIT_TIME:
kasarc5bf2932018-03-09 04:15:22 -08003627 vapp = VApp(self.client, resource=vapp_resource)
kate13ab2c42016-12-23 01:34:24 -08003628 if not vapp:
beierl01bd6692019-12-09 17:06:20 -05003629 self.logger.debug(
sousaedu80135b92021-02-17 15:05:18 +01003630 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3631 vm__vim_uuid
3632 )
3633 )
3634
3635 return (
3636 -1,
3637 "delete_vminstance(): Failed to get vm by given {} vm uuid".format(
3638 vm__vim_uuid
3639 ),
3640 )
kate13ab2c42016-12-23 01:34:24 -08003641
kasarc5bf2932018-03-09 04:15:22 -08003642 delete_task = vdc_obj.delete_vapp(vapp.name, force=True)
sousaedu80135b92021-02-17 15:05:18 +01003643 result = self.client.get_task_monitor().wait_for_success(
3644 task=delete_task
3645 )
3646 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08003647 break
kate13ab2c42016-12-23 01:34:24 -08003648 else:
sousaedu80135b92021-02-17 15:05:18 +01003649 self.logger.debug(
3650 "Wait for vApp {} to delete".format(vapp_name)
3651 )
kate13ab2c42016-12-23 01:34:24 -08003652 time.sleep(INTERVAL_TIME)
3653
beierl01bd6692019-12-09 17:06:20 -05003654 wait_time += INTERVAL_TIME
kate13ab2c42016-12-23 01:34:24 -08003655
kasarc5bf2932018-03-09 04:15:22 -08003656 if result is None:
sousaedu80135b92021-02-17 15:05:18 +01003657 self.logger.debug(
3658 "delete_vminstance(): Failed delete uuid {} ".format(
3659 vm__vim_uuid
3660 )
3661 )
kasarc5bf2932018-03-09 04:15:22 -08003662 else:
sousaedu80135b92021-02-17 15:05:18 +01003663 self.logger.info(
3664 "Deleted vm instance {} sccessfully".format(vm__vim_uuid)
3665 )
3666 config_drive_catalog_name, config_drive_catalog_id = (
3667 "cfg_drv-" + vm__vim_uuid,
3668 None,
3669 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003670 catalog_list = self.get_image_list()
sousaedu80135b92021-02-17 15:05:18 +01003671
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003672 try:
sousaedu80135b92021-02-17 15:05:18 +01003673 config_drive_catalog_id = [
3674 catalog_["id"]
3675 for catalog_ in catalog_list
3676 if catalog_["name"] == config_drive_catalog_name
3677 ][0]
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003678 except IndexError:
3679 pass
sousaedu80135b92021-02-17 15:05:18 +01003680
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003681 if config_drive_catalog_id:
sousaedu80135b92021-02-17 15:05:18 +01003682 self.logger.debug(
3683 "delete_vminstance(): Found a config drive catalog {} matching "
3684 'vapp_name"{}". Deleting it.'.format(
3685 config_drive_catalog_id, vapp_name
3686 )
3687 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00003688 self.delete_image(config_drive_catalog_id)
sousaedu80135b92021-02-17 15:05:18 +01003689
kasarc5bf2932018-03-09 04:15:22 -08003690 return vm__vim_uuid
beierl01bd6692019-12-09 17:06:20 -05003691 except Exception:
bayramovef390722016-09-27 03:34:46 -07003692 self.logger.debug(traceback.format_exc())
sousaedu80135b92021-02-17 15:05:18 +01003693
3694 raise vimconn.VimConnException(
3695 "delete_vminstance(): Failed delete vm instance {}".format(vm__vim_uuid)
3696 )
bayramovef390722016-09-27 03:34:46 -07003697
bayramov325fa1c2016-09-08 01:42:46 -07003698 def refresh_vms_status(self, vm_list):
bayramovef390722016-09-27 03:34:46 -07003699 """Get the status of the virtual machines and their interfaces/ports
sousaedu80135b92021-02-17 15:05:18 +01003700 Params: the list of VM identifiers
3701 Returns a dictionary with:
3702 vm_id: #VIM id of this Virtual Machine
3703 status: #Mandatory. Text with one of:
3704 # DELETED (not found at vim)
3705 # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
3706 # OTHER (Vim reported other status not understood)
3707 # ERROR (VIM indicates an ERROR status)
3708 # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
3709 # CREATING (on building process), ERROR
3710 # ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
3711 #
3712 error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
3713 vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
3714 interfaces:
3715 - vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
3716 mac_address: #Text format XX:XX:XX:XX:XX:XX
3717 vim_net_id: #network id where this interface is connected
3718 vim_interface_id: #interface/port VIM id
3719 ip_address: #null, or text with IPv4, IPv6 address
bayramovef390722016-09-27 03:34:46 -07003720 """
bayramovef390722016-09-27 03:34:46 -07003721 self.logger.debug("Client requesting refresh vm status for {} ".format(vm_list))
bhangare985a1fd2017-01-31 01:53:21 -08003722
beierlb22ce2d2019-12-12 12:09:51 -05003723 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07003724 if vdc is None:
sousaedu80135b92021-02-17 15:05:18 +01003725 raise vimconn.VimConnException(
3726 "Failed to get a reference of VDC for a tenant {}".format(
3727 self.tenant_name
3728 )
3729 )
bayramovef390722016-09-27 03:34:46 -07003730
3731 vms_dict = {}
kasarde691232017-03-25 03:37:31 -07003732 nsx_edge_list = []
bayramovef390722016-09-27 03:34:46 -07003733 for vmuuid in vm_list:
kasarc5bf2932018-03-09 04:15:22 -08003734 vapp_name = self.get_namebyvappid(vmuuid)
3735 if vapp_name is not None:
bayramovef390722016-09-27 03:34:46 -07003736 try:
bhangare1a0b97c2017-06-21 02:20:15 -07003737 vm_pci_details = self.get_vm_pci_details(vmuuid)
sousaedu80135b92021-02-17 15:05:18 +01003738 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08003739 vapp_resource = vdc_obj.get_vapp(vapp_name)
3740 the_vapp = VApp(self.client, resource=vapp_resource)
bhangarebfdca492017-03-11 01:32:46 -08003741
kasarc5bf2932018-03-09 04:15:22 -08003742 vm_details = {}
3743 for vm in the_vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01003744 headers = {
3745 "Accept": "application/*+xml;version=" + API_VERSION,
3746 "x-vcloud-authorization": self.client._session.headers[
3747 "x-vcloud-authorization"
3748 ],
3749 }
3750 response = self.perform_request(
3751 req_type="GET", url=vm.get("href"), headers=headers
3752 )
bhangarebfdca492017-03-11 01:32:46 -08003753
kasarc5bf2932018-03-09 04:15:22 -08003754 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01003755 self.logger.error(
3756 "refresh_vms_status : REST call {} failed reason : {}"
3757 "status code : {}".format(
3758 vm.get("href"), response.text, response.status_code
3759 )
3760 )
3761 raise vimconn.VimConnException(
3762 "refresh_vms_status : Failed to get VM details"
3763 )
kasarde691232017-03-25 03:37:31 -07003764
sousaedu80135b92021-02-17 15:05:18 +01003765 xmlroot = XmlElementTree.fromstring(response.text)
beierl26fec002019-12-06 17:06:40 -05003766 result = response.text.replace("\n", " ")
beierlb22ce2d2019-12-12 12:09:51 -05003767 hdd_match = re.search(
sousaedu80135b92021-02-17 15:05:18 +01003768 'vcloud:capacity="(\d+)"\svcloud:storageProfileOverrideVmDefault=',
3769 result,
3770 )
3771
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00003772 if hdd_match:
3773 hdd_mb = hdd_match.group(1)
sousaedu80135b92021-02-17 15:05:18 +01003774 vm_details["hdd_mb"] = int(hdd_mb) if hdd_mb else None
3775
beierlb22ce2d2019-12-12 12:09:51 -05003776 cpus_match = re.search(
sousaedu80135b92021-02-17 15:05:18 +01003777 "<rasd:Description>Number of Virtual CPUs</.*?>(\d+)</rasd:VirtualQuantity>",
3778 result,
3779 )
3780
Ravi Chamarty1fdf9992018-10-07 15:45:44 +00003781 if cpus_match:
3782 cpus = cpus_match.group(1)
sousaedu80135b92021-02-17 15:05:18 +01003783 vm_details["cpus"] = int(cpus) if cpus else None
3784
beierlb22ce2d2019-12-12 12:09:51 -05003785 memory_mb = re.search(
sousaedu80135b92021-02-17 15:05:18 +01003786 "<rasd:Description>Memory Size</.*?>(\d+)</rasd:VirtualQuantity>",
3787 result,
3788 ).group(1)
3789 vm_details["memory_mb"] = int(memory_mb) if memory_mb else None
3790 vm_details["status"] = vcdStatusCode2manoFormat[
3791 int(xmlroot.get("status"))
3792 ]
3793 vm_details["id"] = xmlroot.get("id")
3794 vm_details["name"] = xmlroot.get("name")
kasarc5bf2932018-03-09 04:15:22 -08003795 vm_info = [vm_details]
sousaedu80135b92021-02-17 15:05:18 +01003796
kasarc5bf2932018-03-09 04:15:22 -08003797 if vm_pci_details:
sbhangarea8e5b782018-06-21 02:10:03 -07003798 vm_info[0].update(vm_pci_details)
kasarc5bf2932018-03-09 04:15:22 -08003799
sousaedu80135b92021-02-17 15:05:18 +01003800 vm_dict = {
3801 "status": vcdStatusCode2manoFormat[
3802 int(vapp_resource.get("status"))
3803 ],
3804 "error_msg": vcdStatusCode2manoFormat[
3805 int(vapp_resource.get("status"))
3806 ],
3807 "vim_info": yaml.safe_dump(vm_info),
3808 "interfaces": [],
3809 }
kasarc5bf2932018-03-09 04:15:22 -08003810
3811 # get networks
sbhangarea8e5b782018-06-21 02:10:03 -07003812 vm_ip = None
kasar1b7b9522018-05-15 06:15:07 -07003813 vm_mac = None
sousaedu80135b92021-02-17 15:05:18 +01003814 networks = re.findall(
3815 "<NetworkConnection needsCustomization=.*?</NetworkConnection>",
3816 result,
3817 )
3818
kasar1b7b9522018-05-15 06:15:07 -07003819 for network in networks:
sousaedu80135b92021-02-17 15:05:18 +01003820 mac_s = re.search("<MACAddress>(.*?)</MACAddress>", network)
kasar1b7b9522018-05-15 06:15:07 -07003821 vm_mac = mac_s.group(1) if mac_s else None
sousaedu80135b92021-02-17 15:05:18 +01003822 ip_s = re.search("<IpAddress>(.*?)</IpAddress>", network)
kasar1b7b9522018-05-15 06:15:07 -07003823 vm_ip = ip_s.group(1) if ip_s else None
kasarc5bf2932018-03-09 04:15:22 -08003824
kasar1b7b9522018-05-15 06:15:07 -07003825 if vm_ip is None:
3826 if not nsx_edge_list:
3827 nsx_edge_list = self.get_edge_details()
3828 if nsx_edge_list is None:
sousaedu80135b92021-02-17 15:05:18 +01003829 raise vimconn.VimConnException(
3830 "refresh_vms_status:"
3831 "Failed to get edge details from NSX Manager"
3832 )
3833
kasar1b7b9522018-05-15 06:15:07 -07003834 if vm_mac is not None:
sousaedu80135b92021-02-17 15:05:18 +01003835 vm_ip = self.get_ipaddr_from_NSXedge(
3836 nsx_edge_list, vm_mac
3837 )
kasarc5bf2932018-03-09 04:15:22 -08003838
beierlb22ce2d2019-12-12 12:09:51 -05003839 net_s = re.search('network="(.*?)"', network)
kasarabac1e22018-05-17 02:44:39 -07003840 network_name = net_s.group(1) if net_s else None
kasar1b7b9522018-05-15 06:15:07 -07003841 vm_net_id = self.get_network_id_by_name(network_name)
sousaedu80135b92021-02-17 15:05:18 +01003842 interface = {
3843 "mac_address": vm_mac,
3844 "vim_net_id": vm_net_id,
3845 "vim_interface_id": vm_net_id,
3846 "ip_address": vm_ip,
3847 }
kasar1b7b9522018-05-15 06:15:07 -07003848 vm_dict["interfaces"].append(interface)
kasarc5bf2932018-03-09 04:15:22 -08003849
bayramovef390722016-09-27 03:34:46 -07003850 # add a vm to vm dict
3851 vms_dict.setdefault(vmuuid, vm_dict)
kasarc5bf2932018-03-09 04:15:22 -08003852 self.logger.debug("refresh_vms_status : vm info {}".format(vm_dict))
bhangarebfdca492017-03-11 01:32:46 -08003853 except Exception as exp:
3854 self.logger.debug("Error in response {}".format(exp))
bayramovef390722016-09-27 03:34:46 -07003855 self.logger.debug(traceback.format_exc())
3856
3857 return vms_dict
3858
kasarde691232017-03-25 03:37:31 -07003859 def get_edge_details(self):
3860 """Get the NSX edge list from NSX Manager
sousaedu80135b92021-02-17 15:05:18 +01003861 Returns list of NSX edges
kasarde691232017-03-25 03:37:31 -07003862 """
3863 edge_list = []
sousaedu80135b92021-02-17 15:05:18 +01003864 rheaders = {"Content-Type": "application/xml"}
3865 nsx_api_url = "/api/4.0/edges"
kasarde691232017-03-25 03:37:31 -07003866
sousaedu80135b92021-02-17 15:05:18 +01003867 self.logger.debug(
3868 "Get edge details from NSX Manager {} {}".format(
3869 self.nsx_manager, nsx_api_url
3870 )
3871 )
kasarde691232017-03-25 03:37:31 -07003872
3873 try:
sousaedu80135b92021-02-17 15:05:18 +01003874 resp = requests.get(
3875 self.nsx_manager + nsx_api_url,
3876 auth=(self.nsx_user, self.nsx_password),
3877 verify=False,
3878 headers=rheaders,
3879 )
kasarde691232017-03-25 03:37:31 -07003880 if resp.status_code == requests.codes.ok:
3881 paged_Edge_List = XmlElementTree.fromstring(resp.text)
3882 for edge_pages in paged_Edge_List:
sousaedu80135b92021-02-17 15:05:18 +01003883 if edge_pages.tag == "edgePage":
kasarde691232017-03-25 03:37:31 -07003884 for edge_summary in edge_pages:
sousaedu80135b92021-02-17 15:05:18 +01003885 if edge_summary.tag == "pagingInfo":
kasarde691232017-03-25 03:37:31 -07003886 for element in edge_summary:
sousaedu80135b92021-02-17 15:05:18 +01003887 if (
3888 element.tag == "totalCount"
3889 and element.text == "0"
3890 ):
tierno72774862020-05-04 11:44:15 +00003891 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +01003892 "get_edge_details: No NSX edges details found: {}".format(
3893 self.nsx_manager
3894 )
3895 )
kasarde691232017-03-25 03:37:31 -07003896
sousaedu80135b92021-02-17 15:05:18 +01003897 if edge_summary.tag == "edgeSummary":
kasarde691232017-03-25 03:37:31 -07003898 for element in edge_summary:
sousaedu80135b92021-02-17 15:05:18 +01003899 if element.tag == "id":
kasarde691232017-03-25 03:37:31 -07003900 edge_list.append(element.text)
3901 else:
sousaedu80135b92021-02-17 15:05:18 +01003902 raise vimconn.VimConnException(
3903 "get_edge_details: No NSX edge details found: {}".format(
3904 self.nsx_manager
3905 )
3906 )
kasarde691232017-03-25 03:37:31 -07003907
3908 if not edge_list:
sousaedu80135b92021-02-17 15:05:18 +01003909 raise vimconn.VimConnException(
3910 "get_edge_details: "
3911 "No NSX edge details found: {}".format(self.nsx_manager)
3912 )
kasarde691232017-03-25 03:37:31 -07003913 else:
sousaedu80135b92021-02-17 15:05:18 +01003914 self.logger.debug(
3915 "get_edge_details: Found NSX edges {}".format(edge_list)
3916 )
3917
kasarde691232017-03-25 03:37:31 -07003918 return edge_list
3919 else:
sousaedu80135b92021-02-17 15:05:18 +01003920 self.logger.debug(
3921 "get_edge_details: "
3922 "Failed to get NSX edge details from NSX Manager: {}".format(
3923 resp.content
3924 )
3925 )
3926
kasarde691232017-03-25 03:37:31 -07003927 return None
3928
3929 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01003930 self.logger.debug(
3931 "get_edge_details: "
3932 "Failed to get NSX edge details from NSX Manager: {}".format(exp)
3933 )
3934 raise vimconn.VimConnException(
3935 "get_edge_details: "
3936 "Failed to get NSX edge details from NSX Manager: {}".format(exp)
3937 )
kasarde691232017-03-25 03:37:31 -07003938
kasarde691232017-03-25 03:37:31 -07003939 def get_ipaddr_from_NSXedge(self, nsx_edges, mac_address):
3940 """Get IP address details from NSX edges, using the MAC address
sousaedu80135b92021-02-17 15:05:18 +01003941 PARAMS: nsx_edges : List of NSX edges
3942 mac_address : Find IP address corresponding to this MAC address
3943 Returns: IP address corrresponding to the provided MAC address
kasarde691232017-03-25 03:37:31 -07003944 """
kasarde691232017-03-25 03:37:31 -07003945 ip_addr = None
sousaedu80135b92021-02-17 15:05:18 +01003946 rheaders = {"Content-Type": "application/xml"}
kasarde691232017-03-25 03:37:31 -07003947
3948 self.logger.debug("get_ipaddr_from_NSXedge: Finding IP addr from NSX edge")
3949
3950 try:
3951 for edge in nsx_edges:
sousaedu80135b92021-02-17 15:05:18 +01003952 nsx_api_url = "/api/4.0/edges/" + edge + "/dhcp/leaseInfo"
kasarde691232017-03-25 03:37:31 -07003953
sousaedu80135b92021-02-17 15:05:18 +01003954 resp = requests.get(
3955 self.nsx_manager + nsx_api_url,
3956 auth=(self.nsx_user, self.nsx_password),
3957 verify=False,
3958 headers=rheaders,
3959 )
kasarde691232017-03-25 03:37:31 -07003960
3961 if resp.status_code == requests.codes.ok:
3962 dhcp_leases = XmlElementTree.fromstring(resp.text)
3963 for child in dhcp_leases:
sousaedu80135b92021-02-17 15:05:18 +01003964 if child.tag == "dhcpLeaseInfo":
kasarde691232017-03-25 03:37:31 -07003965 dhcpLeaseInfo = child
3966 for leaseInfo in dhcpLeaseInfo:
3967 for elem in leaseInfo:
sousaedu80135b92021-02-17 15:05:18 +01003968 if (elem.tag) == "macAddress":
kasarde691232017-03-25 03:37:31 -07003969 edge_mac_addr = elem.text
sousaedu80135b92021-02-17 15:05:18 +01003970
3971 if (elem.tag) == "ipAddress":
kasarde691232017-03-25 03:37:31 -07003972 ip_addr = elem.text
sousaedu80135b92021-02-17 15:05:18 +01003973
kasarde691232017-03-25 03:37:31 -07003974 if edge_mac_addr is not None:
3975 if edge_mac_addr == mac_address:
sousaedu80135b92021-02-17 15:05:18 +01003976 self.logger.debug(
3977 "Found ip addr {} for mac {} at NSX edge {}".format(
3978 ip_addr, mac_address, edge
3979 )
3980 )
3981
kasarde691232017-03-25 03:37:31 -07003982 return ip_addr
3983 else:
sousaedu80135b92021-02-17 15:05:18 +01003984 self.logger.debug(
3985 "get_ipaddr_from_NSXedge: "
3986 "Error occurred while getting DHCP lease info from NSX Manager: {}".format(
3987 resp.content
3988 )
3989 )
kasarde691232017-03-25 03:37:31 -07003990
sousaedu80135b92021-02-17 15:05:18 +01003991 self.logger.debug(
3992 "get_ipaddr_from_NSXedge: No IP addr found in any NSX edge"
3993 )
3994
kasarde691232017-03-25 03:37:31 -07003995 return None
3996
3997 except XmlElementTree.ParseError as Err:
sousaedu80135b92021-02-17 15:05:18 +01003998 self.logger.debug(
3999 "ParseError in response from NSX Manager {}".format(Err.message),
4000 exc_info=True,
4001 )
kasarde691232017-03-25 03:37:31 -07004002
tierno98e909c2017-10-14 13:27:03 +02004003 def action_vminstance(self, vm__vim_uuid=None, action_dict=None, created_items={}):
bayramovef390722016-09-27 03:34:46 -07004004 """Send and action over a VM instance from VIM
4005 Returns the vm_id if the action was successfully sent to the VIM"""
4006
sousaedu80135b92021-02-17 15:05:18 +01004007 self.logger.debug(
4008 "Received action for vm {} and action dict {}".format(
4009 vm__vim_uuid, action_dict
4010 )
4011 )
4012
bayramovef390722016-09-27 03:34:46 -07004013 if vm__vim_uuid is None or action_dict is None:
tierno72774862020-05-04 11:44:15 +00004014 raise vimconn.VimConnException("Invalid request. VM id or action is None.")
bayramovef390722016-09-27 03:34:46 -07004015
beierlb22ce2d2019-12-12 12:09:51 -05004016 _, vdc = self.get_vdc_details()
bayramovef390722016-09-27 03:34:46 -07004017 if vdc is None:
sousaedu80135b92021-02-17 15:05:18 +01004018 raise vimconn.VimConnException(
4019 "Failed to get a reference of VDC for a tenant {}".format(
4020 self.tenant_name
4021 )
4022 )
bayramovef390722016-09-27 03:34:46 -07004023
kasarc5bf2932018-03-09 04:15:22 -08004024 vapp_name = self.get_namebyvappid(vm__vim_uuid)
bayramovef390722016-09-27 03:34:46 -07004025 if vapp_name is None:
sousaedu80135b92021-02-17 15:05:18 +01004026 self.logger.debug(
4027 "action_vminstance(): Failed to get vm by given {} vm uuid".format(
4028 vm__vim_uuid
4029 )
4030 )
4031
4032 raise vimconn.VimConnException(
4033 "Failed to get vm by given {} vm uuid".format(vm__vim_uuid)
4034 )
bayramovef390722016-09-27 03:34:46 -07004035 else:
sousaedu80135b92021-02-17 15:05:18 +01004036 self.logger.info(
4037 "Action_vminstance vApp {} and UUID {}".format(vapp_name, vm__vim_uuid)
4038 )
bayramovef390722016-09-27 03:34:46 -07004039
4040 try:
sousaedu80135b92021-02-17 15:05:18 +01004041 vdc_obj = VDC(self.client, href=vdc.get("href"))
kasarc5bf2932018-03-09 04:15:22 -08004042 vapp_resource = vdc_obj.get_vapp(vapp_name)
sbhangarea8e5b782018-06-21 02:10:03 -07004043 vapp = VApp(self.client, resource=vapp_resource)
sousaedu80135b92021-02-17 15:05:18 +01004044
bayramovef390722016-09-27 03:34:46 -07004045 if "start" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01004046 self.logger.info(
4047 "action_vminstance: Power on vApp: {}".format(vapp_name)
4048 )
sbhangarea8e5b782018-06-21 02:10:03 -07004049 poweron_task = self.power_on_vapp(vm__vim_uuid, vapp_name)
sousaedu80135b92021-02-17 15:05:18 +01004050 result = self.client.get_task_monitor().wait_for_success(
4051 task=poweron_task
4052 )
kasarc5bf2932018-03-09 04:15:22 -08004053 self.instance_actions_result("start", result, vapp_name)
kasar3ac5dc42017-03-15 06:28:22 -07004054 elif "rebuild" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01004055 self.logger.info(
4056 "action_vminstance: Rebuild vApp: {}".format(vapp_name)
4057 )
kasarc5bf2932018-03-09 04:15:22 -08004058 rebuild_task = vapp.deploy(power_on=True)
sousaedu80135b92021-02-17 15:05:18 +01004059 result = self.client.get_task_monitor().wait_for_success(
4060 task=rebuild_task
4061 )
kasar3ac5dc42017-03-15 06:28:22 -07004062 self.instance_actions_result("rebuild", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004063 elif "pause" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07004064 self.logger.info("action_vminstance: pause vApp: {}".format(vapp_name))
sousaedu80135b92021-02-17 15:05:18 +01004065 pause_task = vapp.undeploy(action="suspend")
4066 result = self.client.get_task_monitor().wait_for_success(
4067 task=pause_task
4068 )
kasar3ac5dc42017-03-15 06:28:22 -07004069 self.instance_actions_result("pause", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004070 elif "resume" in action_dict:
kasar3ac5dc42017-03-15 06:28:22 -07004071 self.logger.info("action_vminstance: resume vApp: {}".format(vapp_name))
kasarc5bf2932018-03-09 04:15:22 -08004072 poweron_task = self.power_on_vapp(vm__vim_uuid, vapp_name)
sousaedu80135b92021-02-17 15:05:18 +01004073 result = self.client.get_task_monitor().wait_for_success(
4074 task=poweron_task
4075 )
kasar3ac5dc42017-03-15 06:28:22 -07004076 self.instance_actions_result("resume", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004077 elif "shutoff" in action_dict or "shutdown" in action_dict:
beierlb22ce2d2019-12-12 12:09:51 -05004078 action_name, _ = list(action_dict.items())[0]
sousaedu80135b92021-02-17 15:05:18 +01004079 self.logger.info(
4080 "action_vminstance: {} vApp: {}".format(action_name, vapp_name)
4081 )
kasarc5bf2932018-03-09 04:15:22 -08004082 shutdown_task = vapp.shutdown()
sousaedu80135b92021-02-17 15:05:18 +01004083 result = self.client.get_task_monitor().wait_for_success(
4084 task=shutdown_task
4085 )
kasar3ac5dc42017-03-15 06:28:22 -07004086 if action_name == "shutdown":
4087 self.instance_actions_result("shutdown", result, vapp_name)
bhangare985a1fd2017-01-31 01:53:21 -08004088 else:
kasar3ac5dc42017-03-15 06:28:22 -07004089 self.instance_actions_result("shutoff", result, vapp_name)
bayramovef390722016-09-27 03:34:46 -07004090 elif "forceOff" in action_dict:
sousaedu80135b92021-02-17 15:05:18 +01004091 result = vapp.undeploy(action="powerOff")
kasar3ac5dc42017-03-15 06:28:22 -07004092 self.instance_actions_result("forceOff", result, vapp_name)
4093 elif "reboot" in action_dict:
4094 self.logger.info("action_vminstance: reboot vApp: {}".format(vapp_name))
kasarc5bf2932018-03-09 04:15:22 -08004095 reboot_task = vapp.reboot()
sbhangarea8e5b782018-06-21 02:10:03 -07004096 self.client.get_task_monitor().wait_for_success(task=reboot_task)
bayramovef390722016-09-27 03:34:46 -07004097 else:
tierno72774862020-05-04 11:44:15 +00004098 raise vimconn.VimConnException(
sousaedu80135b92021-02-17 15:05:18 +01004099 "action_vminstance: Invalid action {} or action is None.".format(
4100 action_dict
4101 )
4102 )
4103
kasarc5bf2932018-03-09 04:15:22 -08004104 return vm__vim_uuid
beierlb22ce2d2019-12-12 12:09:51 -05004105 except Exception as exp:
bhangarebfdca492017-03-11 01:32:46 -08004106 self.logger.debug("action_vminstance: Failed with Exception {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01004107
4108 raise vimconn.VimConnException(
4109 "action_vminstance: Failed with Exception {}".format(exp)
4110 )
bayramovef390722016-09-27 03:34:46 -07004111
kasar3ac5dc42017-03-15 06:28:22 -07004112 def instance_actions_result(self, action, result, vapp_name):
sousaedu80135b92021-02-17 15:05:18 +01004113 if result.get("status") == "success":
4114 self.logger.info(
4115 "action_vminstance: Sucessfully {} the vApp: {}".format(
4116 action, vapp_name
4117 )
4118 )
kasar3ac5dc42017-03-15 06:28:22 -07004119 else:
sousaedu80135b92021-02-17 15:05:18 +01004120 self.logger.error(
4121 "action_vminstance: Failed to {} vApp: {}".format(action, vapp_name)
4122 )
kasar3ac5dc42017-03-15 06:28:22 -07004123
kasarcf655072019-03-20 01:40:05 -07004124 def get_vminstance_console(self, vm_id, console_type="novnc"):
bayramovef390722016-09-27 03:34:46 -07004125 """
bayramov325fa1c2016-09-08 01:42:46 -07004126 Get a console for the virtual machine
4127 Params:
4128 vm_id: uuid of the VM
4129 console_type, can be:
bayramovef390722016-09-27 03:34:46 -07004130 "novnc" (by default), "xvpvnc" for VNC types,
bayramov325fa1c2016-09-08 01:42:46 -07004131 "rdp-html5" for RDP types, "spice-html5" for SPICE types
4132 Returns dict with the console parameters:
4133 protocol: ssh, ftp, http, https, ...
bayramovef390722016-09-27 03:34:46 -07004134 server: usually ip address
4135 port: the http, ssh, ... port
4136 suffix: extra text, e.g. the http path and query string
4137 """
kasarcf655072019-03-20 01:40:05 -07004138 console_dict = {}
4139
sousaedu80135b92021-02-17 15:05:18 +01004140 if console_type is None or console_type == "novnc":
4141 url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireMksTicket".format(
4142 self.url, vm_id
4143 )
4144 headers = {
4145 "Accept": "application/*+xml;version=" + API_VERSION,
4146 "x-vcloud-authorization": self.client._session.headers[
4147 "x-vcloud-authorization"
4148 ],
4149 }
4150 response = self.perform_request(
4151 req_type="POST", url=url_rest_call, headers=headers
4152 )
kasarcf655072019-03-20 01:40:05 -07004153
4154 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004155 response = self.retry_rest("GET", url_rest_call)
kasarcf655072019-03-20 01:40:05 -07004156
4157 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01004158 self.logger.error(
4159 "REST call {} failed reason : {}"
4160 "status code : {}".format(
4161 url_rest_call, response.text, response.status_code
4162 )
4163 )
4164 raise vimconn.VimConnException(
4165 "get_vminstance_console : Failed to get " "VM Mks ticket details"
4166 )
4167
beierl26fec002019-12-06 17:06:40 -05004168 s = re.search("<Host>(.*?)</Host>", response.text)
sousaedu80135b92021-02-17 15:05:18 +01004169 console_dict["server"] = s.group(1) if s else None
beierl26fec002019-12-06 17:06:40 -05004170 s1 = re.search("<Port>(\d+)</Port>", response.text)
sousaedu80135b92021-02-17 15:05:18 +01004171 console_dict["port"] = s1.group(1) if s1 else None
4172 url_rest_call = "{}/api/vApp/vm-{}/screen/action/acquireTicket".format(
4173 self.url, vm_id
4174 )
4175 headers = {
4176 "Accept": "application/*+xml;version=" + API_VERSION,
4177 "x-vcloud-authorization": self.client._session.headers[
4178 "x-vcloud-authorization"
4179 ],
4180 }
4181 response = self.perform_request(
4182 req_type="POST", url=url_rest_call, headers=headers
4183 )
kasarcf655072019-03-20 01:40:05 -07004184
4185 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004186 response = self.retry_rest("GET", url_rest_call)
kasarcf655072019-03-20 01:40:05 -07004187
4188 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01004189 self.logger.error(
4190 "REST call {} failed reason : {}"
4191 "status code : {}".format(
4192 url_rest_call, response.text, response.status_code
4193 )
4194 )
4195 raise vimconn.VimConnException(
4196 "get_vminstance_console : Failed to get " "VM console details"
4197 )
4198
beierl26fec002019-12-06 17:06:40 -05004199 s = re.search(">.*?/(vm-\d+.*)</", response.text)
sousaedu80135b92021-02-17 15:05:18 +01004200 console_dict["suffix"] = s.group(1) if s else None
4201 console_dict["protocol"] = "https"
kasarcf655072019-03-20 01:40:05 -07004202
4203 return console_dict
bayramov325fa1c2016-09-08 01:42:46 -07004204
bayramovef390722016-09-27 03:34:46 -07004205 # NOT USED METHODS in current version
bayramov325fa1c2016-09-08 01:42:46 -07004206
4207 def host_vim2gui(self, host, server_dict):
bayramov5761ad12016-10-04 09:00:30 +04004208 """Transform host dictionary from VIM format to GUI format,
bayramov325fa1c2016-09-08 01:42:46 -07004209 and append to the server_dict
bayramov5761ad12016-10-04 09:00:30 +04004210 """
tierno72774862020-05-04 11:44:15 +00004211 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004212
4213 def get_hosts_info(self):
bayramov5761ad12016-10-04 09:00:30 +04004214 """Get the information of deployed hosts
4215 Returns the hosts content"""
tierno72774862020-05-04 11:44:15 +00004216 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004217
4218 def get_hosts(self, vim_tenant):
bayramov5761ad12016-10-04 09:00:30 +04004219 """Get the hosts and deployed instances
4220 Returns the hosts content"""
tierno72774862020-05-04 11:44:15 +00004221 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004222
4223 def get_processor_rankings(self):
bayramov5761ad12016-10-04 09:00:30 +04004224 """Get the processor rankings in the VIM database"""
tierno72774862020-05-04 11:44:15 +00004225 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004226
4227 def new_host(self, host_data):
bayramov5761ad12016-10-04 09:00:30 +04004228 """Adds a new host to VIM"""
sousaedu80135b92021-02-17 15:05:18 +01004229 """Returns status code of the VIM response"""
tierno72774862020-05-04 11:44:15 +00004230 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004231
4232 def new_external_port(self, port_data):
bayramov5761ad12016-10-04 09:00:30 +04004233 """Adds a external port to VIM"""
sousaedu80135b92021-02-17 15:05:18 +01004234 """Returns the port identifier"""
tierno72774862020-05-04 11:44:15 +00004235 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004236
bayramovef390722016-09-27 03:34:46 -07004237 def new_external_network(self, net_name, net_type):
bayramov5761ad12016-10-04 09:00:30 +04004238 """Adds a external network to VIM (shared)"""
sousaedu80135b92021-02-17 15:05:18 +01004239 """Returns the network identifier"""
tierno72774862020-05-04 11:44:15 +00004240 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004241
4242 def connect_port_network(self, port_id, network_id, admin=False):
bayramov5761ad12016-10-04 09:00:30 +04004243 """Connects a external port to a network"""
sousaedu80135b92021-02-17 15:05:18 +01004244 """Returns status code of the VIM response"""
tierno72774862020-05-04 11:44:15 +00004245 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004246
4247 def new_vminstancefromJSON(self, vm_data):
bayramov5761ad12016-10-04 09:00:30 +04004248 """Adds a VM instance to VIM"""
sousaedu80135b92021-02-17 15:05:18 +01004249 """Returns the instance identifier"""
tierno72774862020-05-04 11:44:15 +00004250 raise vimconn.VimConnNotImplemented("Should have implemented this")
bayramov325fa1c2016-09-08 01:42:46 -07004251
kate15f1c382016-12-15 01:12:40 -08004252 def get_network_name_by_id(self, network_uuid=None):
bayramovef390722016-09-27 03:34:46 -07004253 """Method gets vcloud director network named based on supplied uuid.
4254
4255 Args:
kate15f1c382016-12-15 01:12:40 -08004256 network_uuid: network_id
bayramovef390722016-09-27 03:34:46 -07004257
4258 Returns:
4259 The return network name.
4260 """
4261
kate15f1c382016-12-15 01:12:40 -08004262 if not network_uuid:
bayramovef390722016-09-27 03:34:46 -07004263 return None
4264
4265 try:
kate15f1c382016-12-15 01:12:40 -08004266 org_dict = self.get_org(self.org_uuid)
sousaedu80135b92021-02-17 15:05:18 +01004267 if "networks" in org_dict:
4268 org_network_dict = org_dict["networks"]
4269
kate15f1c382016-12-15 01:12:40 -08004270 for net_uuid in org_network_dict:
4271 if net_uuid == network_uuid:
4272 return org_network_dict[net_uuid]
beierlb22ce2d2019-12-12 12:09:51 -05004273 except Exception:
bayramovef390722016-09-27 03:34:46 -07004274 self.logger.debug("Exception in get_network_name_by_id")
4275 self.logger.debug(traceback.format_exc())
4276
4277 return None
4278
bhangare2c855072016-12-27 01:41:28 -08004279 def get_network_id_by_name(self, network_name=None):
4280 """Method gets vcloud director network uuid based on supplied name.
4281
4282 Args:
4283 network_name: network_name
4284 Returns:
4285 The return network uuid.
4286 network_uuid: network_id
4287 """
bhangare2c855072016-12-27 01:41:28 -08004288 if not network_name:
4289 self.logger.debug("get_network_id_by_name() : Network name is empty")
4290 return None
4291
4292 try:
4293 org_dict = self.get_org(self.org_uuid)
sousaedu80135b92021-02-17 15:05:18 +01004294 if org_dict and "networks" in org_dict:
4295 org_network_dict = org_dict["networks"]
4296
tierno1b856002019-11-07 16:28:54 +00004297 for net_uuid, net_name in org_network_dict.items():
bhangare2c855072016-12-27 01:41:28 -08004298 if net_name == network_name:
4299 return net_uuid
4300
4301 except KeyError as exp:
4302 self.logger.debug("get_network_id_by_name() : KeyError- {} ".format(exp))
4303
4304 return None
4305
kbsuba85c54d2019-10-17 16:30:32 +00004306 def get_physical_network_by_name(self, physical_network_name):
sousaedu80135b92021-02-17 15:05:18 +01004307 """
kbsuba85c54d2019-10-17 16:30:32 +00004308 Methos returns uuid of physical network which passed
4309 Args:
4310 physical_network_name: physical network name
4311 Returns:
4312 UUID of physical_network_name
sousaedu80135b92021-02-17 15:05:18 +01004313 """
kbsuba85c54d2019-10-17 16:30:32 +00004314 try:
4315 client_as_admin = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01004316
kbsuba85c54d2019-10-17 16:30:32 +00004317 if not client_as_admin:
tierno72774862020-05-04 11:44:15 +00004318 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
sousaedu80135b92021-02-17 15:05:18 +01004319
4320 url_list = [self.url, "/api/admin/vdc/", self.tenant_id]
4321 vm_list_rest_call = "".join(url_list)
kbsuba85c54d2019-10-17 16:30:32 +00004322
4323 if client_as_admin._session:
sousaedu80135b92021-02-17 15:05:18 +01004324 headers = {
4325 "Accept": "application/*+xml;version=" + API_VERSION,
4326 "x-vcloud-authorization": client_as_admin._session.headers[
4327 "x-vcloud-authorization"
4328 ],
4329 }
4330 response = self.perform_request(
4331 req_type="GET", url=vm_list_rest_call, headers=headers
4332 )
kbsuba85c54d2019-10-17 16:30:32 +00004333 provider_network = None
4334 available_network = None
beierlb22ce2d2019-12-12 12:09:51 -05004335 # add_vdc_rest_url = None
kbsuba85c54d2019-10-17 16:30:32 +00004336
4337 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004338 self.logger.debug(
4339 "REST API call {} failed. Return status code {}".format(
4340 vm_list_rest_call, response.status_code
4341 )
4342 )
kbsuba85c54d2019-10-17 16:30:32 +00004343 return None
4344 else:
4345 try:
beierl26fec002019-12-06 17:06:40 -05004346 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
kbsuba85c54d2019-10-17 16:30:32 +00004347 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004348 if child.tag.split("}")[1] == "ProviderVdcReference":
4349 provider_network = child.attrib.get("href")
kbsuba85c54d2019-10-17 16:30:32 +00004350 # application/vnd.vmware.admin.providervdc+xml
sousaedu80135b92021-02-17 15:05:18 +01004351
4352 if child.tag.split("}")[1] == "Link":
4353 if (
4354 child.attrib.get("type")
4355 == "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
4356 and child.attrib.get("rel") == "add"
4357 ):
4358 child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05004359 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01004360 self.logger.debug(
4361 "Failed parse respond for rest api call {}".format(
4362 vm_list_rest_call
4363 )
4364 )
beierl26fec002019-12-06 17:06:40 -05004365 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01004366
kbsuba85c54d2019-10-17 16:30:32 +00004367 return None
4368
4369 # find pvdc provided available network
sousaedu80135b92021-02-17 15:05:18 +01004370 response = self.perform_request(
4371 req_type="GET", url=provider_network, headers=headers
4372 )
kbsuba85c54d2019-10-17 16:30:32 +00004373
4374 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004375 self.logger.debug(
4376 "REST API call {} failed. Return status code {}".format(
4377 vm_list_rest_call, response.status_code
4378 )
4379 )
4380
kbsuba85c54d2019-10-17 16:30:32 +00004381 return None
4382
4383 try:
beierl26fec002019-12-06 17:06:40 -05004384 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
kbsuba85c54d2019-10-17 16:30:32 +00004385 for child in vm_list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01004386 if child.tag.split("}")[1] == "AvailableNetworks":
kbsuba85c54d2019-10-17 16:30:32 +00004387 for networks in child.iter():
sousaedu80135b92021-02-17 15:05:18 +01004388 if (
4389 networks.attrib.get("href") is not None
4390 and networks.attrib.get("name") is not None
4391 ):
4392 if (
4393 networks.attrib.get("name")
4394 == physical_network_name
4395 ):
4396 network_url = networks.attrib.get("href")
4397 available_network = network_url[
4398 network_url.rindex("/") + 1 :
4399 ]
kbsuba85c54d2019-10-17 16:30:32 +00004400 break
sousaedu80135b92021-02-17 15:05:18 +01004401 except Exception:
kbsuba85c54d2019-10-17 16:30:32 +00004402 return None
4403
4404 return available_network
4405 except Exception as e:
4406 self.logger.error("Error while getting physical network: {}".format(e))
4407
bayramovef390722016-09-27 03:34:46 -07004408 def list_org_action(self):
4409 """
4410 Method leverages vCloud director and query for available organization for particular user
4411
4412 Args:
4413 vca - is active VCA connection.
4414 vdc_name - is a vdc name that will be used to query vms action
4415
4416 Returns:
4417 The return XML respond
4418 """
sousaedu80135b92021-02-17 15:05:18 +01004419 url_list = [self.url, "/api/org"]
4420 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004421
kasarc5bf2932018-03-09 04:15:22 -08004422 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01004423 headers = {
4424 "Accept": "application/*+xml;version=" + API_VERSION,
4425 "x-vcloud-authorization": self.client._session.headers[
4426 "x-vcloud-authorization"
4427 ],
4428 }
kasarc5bf2932018-03-09 04:15:22 -08004429
sousaedu80135b92021-02-17 15:05:18 +01004430 response = self.perform_request(
4431 req_type="GET", url=vm_list_rest_call, headers=headers
4432 )
bhangare1a0b97c2017-06-21 02:20:15 -07004433
4434 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004435 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004436
bayramovef390722016-09-27 03:34:46 -07004437 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004438 return response.text
bayramovef390722016-09-27 03:34:46 -07004439
4440 return None
4441
4442 def get_org_action(self, org_uuid=None):
4443 """
kasarc5bf2932018-03-09 04:15:22 -08004444 Method leverages vCloud director and retrieve available object for organization.
bayramovef390722016-09-27 03:34:46 -07004445
4446 Args:
kasarc5bf2932018-03-09 04:15:22 -08004447 org_uuid - vCD organization uuid
4448 self.client - is active connection.
bayramovef390722016-09-27 03:34:46 -07004449
4450 Returns:
4451 The return XML respond
4452 """
4453
bayramovef390722016-09-27 03:34:46 -07004454 if org_uuid is None:
4455 return None
4456
sousaedu80135b92021-02-17 15:05:18 +01004457 url_list = [self.url, "/api/org/", org_uuid]
4458 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004459
sbhangarea8e5b782018-06-21 02:10:03 -07004460 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01004461 headers = {
4462 "Accept": "application/*+xml;version=" + API_VERSION,
4463 "x-vcloud-authorization": self.client._session.headers[
4464 "x-vcloud-authorization"
4465 ],
4466 }
bhangare1a0b97c2017-06-21 02:20:15 -07004467
beierlb22ce2d2019-12-12 12:09:51 -05004468 # response = requests.get(vm_list_rest_call, headers=headers, verify=False)
sousaedu80135b92021-02-17 15:05:18 +01004469 response = self.perform_request(
4470 req_type="GET", url=vm_list_rest_call, headers=headers
4471 )
4472
bhangare1a0b97c2017-06-21 02:20:15 -07004473 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004474 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004475
bayramovef390722016-09-27 03:34:46 -07004476 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004477 return response.text
sousaedu80135b92021-02-17 15:05:18 +01004478
bayramovef390722016-09-27 03:34:46 -07004479 return None
4480
4481 def get_org(self, org_uuid=None):
4482 """
4483 Method retrieves available organization in vCloud Director
4484
4485 Args:
bayramovb6ffe792016-09-28 11:50:56 +04004486 org_uuid - is a organization uuid.
bayramovef390722016-09-27 03:34:46 -07004487
4488 Returns:
bayramovb6ffe792016-09-28 11:50:56 +04004489 The return dictionary with following key
4490 "network" - for network list under the org
4491 "catalogs" - for network list under the org
4492 "vdcs" - for vdc list under org
bayramovef390722016-09-27 03:34:46 -07004493 """
4494
4495 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07004496
4497 if org_uuid is None:
4498 return org_dict
4499
4500 content = self.get_org_action(org_uuid=org_uuid)
4501 try:
4502 vdc_list = {}
4503 network_list = {}
4504 catalog_list = {}
4505 vm_list_xmlroot = XmlElementTree.fromstring(content)
4506 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004507 if child.attrib["type"] == "application/vnd.vmware.vcloud.vdc+xml":
4508 vdc_list[child.attrib["href"].split("/")[-1:][0]] = child.attrib[
4509 "name"
4510 ]
4511 org_dict["vdcs"] = vdc_list
4512
4513 if (
4514 child.attrib["type"]
4515 == "application/vnd.vmware.vcloud.orgNetwork+xml"
4516 ):
4517 network_list[
4518 child.attrib["href"].split("/")[-1:][0]
4519 ] = child.attrib["name"]
4520 org_dict["networks"] = network_list
4521
4522 if child.attrib["type"] == "application/vnd.vmware.vcloud.catalog+xml":
4523 catalog_list[
4524 child.attrib["href"].split("/")[-1:][0]
4525 ] = child.attrib["name"]
4526 org_dict["catalogs"] = catalog_list
beierlb22ce2d2019-12-12 12:09:51 -05004527 except Exception:
bayramovef390722016-09-27 03:34:46 -07004528 pass
4529
4530 return org_dict
4531
4532 def get_org_list(self):
4533 """
4534 Method retrieves available organization in vCloud Director
4535
4536 Args:
4537 vca - is active VCA connection.
4538
4539 Returns:
4540 The return dictionary and key for each entry VDC UUID
4541 """
bayramovef390722016-09-27 03:34:46 -07004542 org_dict = {}
bayramovef390722016-09-27 03:34:46 -07004543
4544 content = self.list_org_action()
4545 try:
4546 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01004547
bayramovef390722016-09-27 03:34:46 -07004548 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004549 if vm_xml.tag.split("}")[1] == "Org":
4550 org_uuid = vm_xml.attrib["href"].split("/")[-1:]
4551 org_dict[org_uuid[0]] = vm_xml.attrib["name"]
beierlb22ce2d2019-12-12 12:09:51 -05004552 except Exception:
bayramovef390722016-09-27 03:34:46 -07004553 pass
4554
4555 return org_dict
4556
4557 def vms_view_action(self, vdc_name=None):
sousaedu80135b92021-02-17 15:05:18 +01004558 """Method leverages vCloud director vms query call
bayramovef390722016-09-27 03:34:46 -07004559
4560 Args:
4561 vca - is active VCA connection.
4562 vdc_name - is a vdc name that will be used to query vms action
4563
4564 Returns:
4565 The return XML respond
4566 """
4567 vca = self.connect()
4568 if vdc_name is None:
4569 return None
4570
sousaedu80135b92021-02-17 15:05:18 +01004571 url_list = [vca.host, "/api/vms/query"]
4572 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004573
4574 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
sousaedu80135b92021-02-17 15:05:18 +01004575 refs = [
4576 ref
4577 for ref in vca.vcloud_session.organization.Link
4578 if ref.name == vdc_name
4579 and ref.type_ == "application/vnd.vmware.vcloud.vdc+xml"
4580 ]
4581
bayramovef390722016-09-27 03:34:46 -07004582 if len(refs) == 1:
sousaedu80135b92021-02-17 15:05:18 +01004583 response = self.perform_request(
4584 req_type="GET",
4585 url=vm_list_rest_call,
4586 headers=vca.vcloud_session.get_vcloud_headers(),
4587 verify=vca.verify,
4588 logger=vca.logger,
4589 )
4590
bayramovef390722016-09-27 03:34:46 -07004591 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004592 return response.text
bayramovef390722016-09-27 03:34:46 -07004593
4594 return None
4595
4596 def get_vapp_list(self, vdc_name=None):
4597 """
4598 Method retrieves vApp list deployed vCloud director and returns a dictionary
4599 contains a list of all vapp deployed for queried VDC.
4600 The key for a dictionary is vApp UUID
4601
4602
4603 Args:
4604 vca - is active VCA connection.
4605 vdc_name - is a vdc name that will be used to query vms action
4606
4607 Returns:
4608 The return dictionary and key for each entry vapp UUID
4609 """
bayramovef390722016-09-27 03:34:46 -07004610 vapp_dict = {}
sousaedu80135b92021-02-17 15:05:18 +01004611
bayramovef390722016-09-27 03:34:46 -07004612 if vdc_name is None:
4613 return vapp_dict
4614
4615 content = self.vms_view_action(vdc_name=vdc_name)
4616 try:
4617 vm_list_xmlroot = XmlElementTree.fromstring(content)
4618 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004619 if vm_xml.tag.split("}")[1] == "VMRecord":
4620 if vm_xml.attrib["isVAppTemplate"] == "true":
4621 rawuuid = vm_xml.attrib["container"].split("/")[-1:]
4622 if "vappTemplate-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004623 # vm in format vappTemplate-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
4624 # vm and use raw UUID as key
4625 vapp_dict[rawuuid[0][13:]] = vm_xml.attrib
beierlb22ce2d2019-12-12 12:09:51 -05004626 except Exception:
bayramovef390722016-09-27 03:34:46 -07004627 pass
4628
4629 return vapp_dict
4630
4631 def get_vm_list(self, vdc_name=None):
4632 """
4633 Method retrieves VM's list deployed vCloud director. It returns a dictionary
4634 contains a list of all VM's deployed for queried VDC.
4635 The key for a dictionary is VM UUID
4636
4637
4638 Args:
4639 vca - is active VCA connection.
4640 vdc_name - is a vdc name that will be used to query vms action
4641
4642 Returns:
4643 The return dictionary and key for each entry vapp UUID
4644 """
4645 vm_dict = {}
4646
4647 if vdc_name is None:
4648 return vm_dict
4649
4650 content = self.vms_view_action(vdc_name=vdc_name)
4651 try:
4652 vm_list_xmlroot = XmlElementTree.fromstring(content)
4653 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004654 if vm_xml.tag.split("}")[1] == "VMRecord":
4655 if vm_xml.attrib["isVAppTemplate"] == "false":
4656 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4657 if "vm-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004658 # vm in format vm-e63d40e7-4ff5-4c6d-851f-96c1e4da86a5 we remove
4659 # vm and use raw UUID as key
4660 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
beierlb22ce2d2019-12-12 12:09:51 -05004661 except Exception:
bayramovef390722016-09-27 03:34:46 -07004662 pass
4663
4664 return vm_dict
4665
4666 def get_vapp(self, vdc_name=None, vapp_name=None, isuuid=False):
4667 """
bayramovb6ffe792016-09-28 11:50:56 +04004668 Method retrieves VM deployed vCloud director. It returns VM attribute as dictionary
bayramovef390722016-09-27 03:34:46 -07004669 contains a list of all VM's deployed for queried VDC.
4670 The key for a dictionary is VM UUID
4671
4672
4673 Args:
4674 vca - is active VCA connection.
4675 vdc_name - is a vdc name that will be used to query vms action
4676
4677 Returns:
4678 The return dictionary and key for each entry vapp UUID
4679 """
4680 vm_dict = {}
4681 vca = self.connect()
sousaedu80135b92021-02-17 15:05:18 +01004682
bayramovef390722016-09-27 03:34:46 -07004683 if not vca:
tierno72774862020-05-04 11:44:15 +00004684 raise vimconn.VimConnConnectionException("self.connect() is failed")
bayramovef390722016-09-27 03:34:46 -07004685
4686 if vdc_name is None:
4687 return vm_dict
4688
4689 content = self.vms_view_action(vdc_name=vdc_name)
4690 try:
4691 vm_list_xmlroot = XmlElementTree.fromstring(content)
4692 for vm_xml in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004693 if (
4694 vm_xml.tag.split("}")[1] == "VMRecord"
4695 and vm_xml.attrib["isVAppTemplate"] == "false"
4696 ):
bayramovb6ffe792016-09-28 11:50:56 +04004697 # lookup done by UUID
bayramovef390722016-09-27 03:34:46 -07004698 if isuuid:
sousaedu80135b92021-02-17 15:05:18 +01004699 if vapp_name in vm_xml.attrib["container"]:
4700 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4701 if "vm-" in rawuuid[0]:
bayramovef390722016-09-27 03:34:46 -07004702 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
bayramovb6ffe792016-09-28 11:50:56 +04004703 break
4704 # lookup done by Name
4705 else:
sousaedu80135b92021-02-17 15:05:18 +01004706 if vapp_name in vm_xml.attrib["name"]:
4707 rawuuid = vm_xml.attrib["href"].split("/")[-1:]
4708 if "vm-" in rawuuid[0]:
bayramovb6ffe792016-09-28 11:50:56 +04004709 vm_dict[rawuuid[0][3:]] = vm_xml.attrib
4710 break
beierlb22ce2d2019-12-12 12:09:51 -05004711 except Exception:
bayramovef390722016-09-27 03:34:46 -07004712 pass
4713
4714 return vm_dict
4715
4716 def get_network_action(self, network_uuid=None):
4717 """
4718 Method leverages vCloud director and query network based on network uuid
4719
4720 Args:
4721 vca - is active VCA connection.
4722 network_uuid - is a network uuid
4723
4724 Returns:
4725 The return XML respond
4726 """
bayramovef390722016-09-27 03:34:46 -07004727 if network_uuid is None:
4728 return None
4729
sousaedu80135b92021-02-17 15:05:18 +01004730 url_list = [self.url, "/api/network/", network_uuid]
4731 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004732
kasarc5bf2932018-03-09 04:15:22 -08004733 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01004734 headers = {
4735 "Accept": "application/*+xml;version=" + API_VERSION,
4736 "x-vcloud-authorization": self.client._session.headers[
4737 "x-vcloud-authorization"
4738 ],
4739 }
4740 response = self.perform_request(
4741 req_type="GET", url=vm_list_rest_call, headers=headers
4742 )
bhangare1a0b97c2017-06-21 02:20:15 -07004743
beierlb22ce2d2019-12-12 12:09:51 -05004744 # Retry login if session expired & retry sending request
bhangare1a0b97c2017-06-21 02:20:15 -07004745 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01004746 response = self.retry_rest("GET", vm_list_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07004747
bayramovef390722016-09-27 03:34:46 -07004748 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05004749 return response.text
bayramovef390722016-09-27 03:34:46 -07004750
4751 return None
4752
4753 def get_vcd_network(self, network_uuid=None):
4754 """
4755 Method retrieves available network from vCloud Director
4756
4757 Args:
4758 network_uuid - is VCD network UUID
4759
4760 Each element serialized as key : value pair
4761
4762 Following keys available for access. network_configuration['Gateway'}
4763 <Configuration>
4764 <IpScopes>
4765 <IpScope>
4766 <IsInherited>true</IsInherited>
4767 <Gateway>172.16.252.100</Gateway>
4768 <Netmask>255.255.255.0</Netmask>
4769 <Dns1>172.16.254.201</Dns1>
4770 <Dns2>172.16.254.202</Dns2>
4771 <DnsSuffix>vmwarelab.edu</DnsSuffix>
4772 <IsEnabled>true</IsEnabled>
4773 <IpRanges>
4774 <IpRange>
4775 <StartAddress>172.16.252.1</StartAddress>
4776 <EndAddress>172.16.252.99</EndAddress>
4777 </IpRange>
4778 </IpRanges>
4779 </IpScope>
4780 </IpScopes>
4781 <FenceMode>bridged</FenceMode>
4782
4783 Returns:
4784 The return dictionary and key for each entry vapp UUID
4785 """
bayramovef390722016-09-27 03:34:46 -07004786 network_configuration = {}
sousaedu80135b92021-02-17 15:05:18 +01004787
bayramovef390722016-09-27 03:34:46 -07004788 if network_uuid is None:
4789 return network_uuid
4790
bayramovef390722016-09-27 03:34:46 -07004791 try:
bhangarebfdca492017-03-11 01:32:46 -08004792 content = self.get_network_action(network_uuid=network_uuid)
kbsub3de27d62019-12-05 17:20:18 +00004793 if content is not None:
4794 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01004795 network_configuration["status"] = vm_list_xmlroot.get("status")
4796 network_configuration["name"] = vm_list_xmlroot.get("name")
4797 network_configuration["uuid"] = vm_list_xmlroot.get("id").split(":")[3]
bayramovef390722016-09-27 03:34:46 -07004798
kbsub3de27d62019-12-05 17:20:18 +00004799 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004800 if child.tag.split("}")[1] == "IsShared":
4801 network_configuration["isShared"] = child.text.strip()
4802
4803 if child.tag.split("}")[1] == "Configuration":
kbsub3de27d62019-12-05 17:20:18 +00004804 for configuration in child.iter():
4805 tagKey = configuration.tag.split("}")[1].strip()
4806 if tagKey != "":
sousaedu80135b92021-02-17 15:05:18 +01004807 network_configuration[
4808 tagKey
4809 ] = configuration.text.strip()
beierlb22ce2d2019-12-12 12:09:51 -05004810 except Exception as exp:
bhangarebfdca492017-03-11 01:32:46 -08004811 self.logger.debug("get_vcd_network: Failed with Exception {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01004812
4813 raise vimconn.VimConnException(
4814 "get_vcd_network: Failed with Exception {}".format(exp)
4815 )
bayramovef390722016-09-27 03:34:46 -07004816
4817 return network_configuration
4818
4819 def delete_network_action(self, network_uuid=None):
4820 """
4821 Method delete given network from vCloud director
4822
4823 Args:
4824 network_uuid - is a network uuid that client wish to delete
4825
4826 Returns:
4827 The return None or XML respond or false
4828 """
kasarc5bf2932018-03-09 04:15:22 -08004829 client = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01004830
kasarc5bf2932018-03-09 04:15:22 -08004831 if not client:
tierno72774862020-05-04 11:44:15 +00004832 raise vimconn.VimConnConnectionException("Failed to connect vCD as admin")
sousaedu80135b92021-02-17 15:05:18 +01004833
bayramovef390722016-09-27 03:34:46 -07004834 if network_uuid is None:
4835 return False
4836
sousaedu80135b92021-02-17 15:05:18 +01004837 url_list = [self.url, "/api/admin/network/", network_uuid]
4838 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07004839
kasarc5bf2932018-03-09 04:15:22 -08004840 if client._session:
sousaedu80135b92021-02-17 15:05:18 +01004841 headers = {
4842 "Accept": "application/*+xml;version=" + API_VERSION,
4843 "x-vcloud-authorization": client._session.headers[
4844 "x-vcloud-authorization"
4845 ],
4846 }
4847 response = self.perform_request(
4848 req_type="DELETE", url=vm_list_rest_call, headers=headers
4849 )
4850
bayramovef390722016-09-27 03:34:46 -07004851 if response.status_code == 202:
4852 return True
4853
4854 return False
4855
sousaedu80135b92021-02-17 15:05:18 +01004856 def create_network(
4857 self,
4858 network_name=None,
4859 net_type="bridge",
4860 parent_network_uuid=None,
4861 ip_profile=None,
4862 isshared="true",
4863 ):
bayramovef390722016-09-27 03:34:46 -07004864 """
4865 Method create network in vCloud director
4866
4867 Args:
4868 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08004869 net_type - can be 'bridge','data','ptp','mgmt'.
4870 ip_profile is a dict containing the IP parameters of the network
4871 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07004872 parent_network_uuid - is parent provider vdc network that will be used for mapping.
4873 It optional attribute. by default if no parent network indicate the first available will be used.
4874
4875 Returns:
4876 The return network uuid or return None
4877 """
sousaedu80135b92021-02-17 15:05:18 +01004878 new_network_name = [network_name, "-", str(uuid.uuid4())]
4879 content = self.create_network_rest(
4880 network_name="".join(new_network_name),
4881 ip_profile=ip_profile,
4882 net_type=net_type,
4883 parent_network_uuid=parent_network_uuid,
4884 isshared=isshared,
4885 )
bayramovef390722016-09-27 03:34:46 -07004886
bayramovef390722016-09-27 03:34:46 -07004887 if content is None:
4888 self.logger.debug("Failed create network {}.".format(network_name))
sousaedu80135b92021-02-17 15:05:18 +01004889
bayramovef390722016-09-27 03:34:46 -07004890 return None
4891
4892 try:
4893 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01004894 vcd_uuid = vm_list_xmlroot.get("id").split(":")
bayramovef390722016-09-27 03:34:46 -07004895 if len(vcd_uuid) == 4:
sousaedu80135b92021-02-17 15:05:18 +01004896 self.logger.info(
4897 "Created new network name: {} uuid: {}".format(
4898 network_name, vcd_uuid[3]
4899 )
4900 )
4901
bayramovef390722016-09-27 03:34:46 -07004902 return vcd_uuid[3]
beierlb22ce2d2019-12-12 12:09:51 -05004903 except Exception:
bayramovef390722016-09-27 03:34:46 -07004904 self.logger.debug("Failed create network {}".format(network_name))
sousaedu80135b92021-02-17 15:05:18 +01004905
bayramovef390722016-09-27 03:34:46 -07004906 return None
4907
sousaedu80135b92021-02-17 15:05:18 +01004908 def create_network_rest(
4909 self,
4910 network_name=None,
4911 net_type="bridge",
4912 parent_network_uuid=None,
4913 ip_profile=None,
4914 isshared="true",
4915 ):
bayramovef390722016-09-27 03:34:46 -07004916 """
4917 Method create network in vCloud director
4918
4919 Args:
4920 network_name - is network name to be created.
bhangare0e571a92017-01-12 04:02:23 -08004921 net_type - can be 'bridge','data','ptp','mgmt'.
4922 ip_profile is a dict containing the IP parameters of the network
4923 isshared - is a boolean
bayramovef390722016-09-27 03:34:46 -07004924 parent_network_uuid - is parent provider vdc network that will be used for mapping.
4925 It optional attribute. by default if no parent network indicate the first available will be used.
4926
4927 Returns:
4928 The return network uuid or return None
4929 """
kasarc5bf2932018-03-09 04:15:22 -08004930 client_as_admin = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01004931
kasarc5bf2932018-03-09 04:15:22 -08004932 if not client_as_admin:
tierno72774862020-05-04 11:44:15 +00004933 raise vimconn.VimConnConnectionException("Failed to connect vCD.")
sousaedu80135b92021-02-17 15:05:18 +01004934
bayramovef390722016-09-27 03:34:46 -07004935 if network_name is None:
4936 return None
4937
sousaedu80135b92021-02-17 15:05:18 +01004938 url_list = [self.url, "/api/admin/vdc/", self.tenant_id]
4939 vm_list_rest_call = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08004940
4941 if client_as_admin._session:
sousaedu80135b92021-02-17 15:05:18 +01004942 headers = {
4943 "Accept": "application/*+xml;version=" + API_VERSION,
4944 "x-vcloud-authorization": client_as_admin._session.headers[
4945 "x-vcloud-authorization"
4946 ],
4947 }
4948 response = self.perform_request(
4949 req_type="GET", url=vm_list_rest_call, headers=headers
4950 )
bayramovef390722016-09-27 03:34:46 -07004951 provider_network = None
4952 available_networks = None
4953 add_vdc_rest_url = None
4954
4955 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004956 self.logger.debug(
4957 "REST API call {} failed. Return status code {}".format(
4958 vm_list_rest_call, response.status_code
4959 )
4960 )
4961
bayramovef390722016-09-27 03:34:46 -07004962 return None
4963 else:
4964 try:
beierl26fec002019-12-06 17:06:40 -05004965 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07004966 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01004967 if child.tag.split("}")[1] == "ProviderVdcReference":
4968 provider_network = child.attrib.get("href")
bayramovef390722016-09-27 03:34:46 -07004969 # application/vnd.vmware.admin.providervdc+xml
sousaedu80135b92021-02-17 15:05:18 +01004970
4971 if child.tag.split("}")[1] == "Link":
4972 if (
4973 child.attrib.get("type")
4974 == "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
4975 and child.attrib.get("rel") == "add"
4976 ):
4977 add_vdc_rest_url = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05004978 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01004979 self.logger.debug(
4980 "Failed parse respond for rest api call {}".format(
4981 vm_list_rest_call
4982 )
4983 )
beierl26fec002019-12-06 17:06:40 -05004984 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01004985
bayramovef390722016-09-27 03:34:46 -07004986 return None
4987
4988 # find pvdc provided available network
sousaedu80135b92021-02-17 15:05:18 +01004989 response = self.perform_request(
4990 req_type="GET", url=provider_network, headers=headers
4991 )
kbsuba85c54d2019-10-17 16:30:32 +00004992
bayramovef390722016-09-27 03:34:46 -07004993 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01004994 self.logger.debug(
4995 "REST API call {} failed. Return status code {}".format(
4996 vm_list_rest_call, response.status_code
4997 )
4998 )
4999
bayramovef390722016-09-27 03:34:46 -07005000 return None
5001
bayramovef390722016-09-27 03:34:46 -07005002 if parent_network_uuid is None:
5003 try:
beierl26fec002019-12-06 17:06:40 -05005004 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005005 for child in vm_list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01005006 if child.tag.split("}")[1] == "AvailableNetworks":
bayramovef390722016-09-27 03:34:46 -07005007 for networks in child.iter():
5008 # application/vnd.vmware.admin.network+xml
sousaedu80135b92021-02-17 15:05:18 +01005009 if networks.attrib.get("href") is not None:
5010 available_networks = networks.attrib.get("href")
bayramovef390722016-09-27 03:34:46 -07005011 break
beierlb22ce2d2019-12-12 12:09:51 -05005012 except Exception:
bayramovef390722016-09-27 03:34:46 -07005013 return None
5014
bhangarebfdca492017-03-11 01:32:46 -08005015 try:
beierlb22ce2d2019-12-12 12:09:51 -05005016 # Configure IP profile of the network
sousaedu80135b92021-02-17 15:05:18 +01005017 ip_profile = (
5018 ip_profile if ip_profile is not None else DEFAULT_IP_PROFILE
5019 )
bhangare0e571a92017-01-12 04:02:23 -08005020
sousaedu80135b92021-02-17 15:05:18 +01005021 if (
5022 "subnet_address" not in ip_profile
5023 or ip_profile["subnet_address"] is None
5024 ):
kasarde691232017-03-25 03:37:31 -07005025 subnet_rand = random.randint(0, 255)
5026 ip_base = "192.168.{}.".format(subnet_rand)
sousaedu80135b92021-02-17 15:05:18 +01005027 ip_profile["subnet_address"] = ip_base + "0/24"
kasarde691232017-03-25 03:37:31 -07005028 else:
sousaedu80135b92021-02-17 15:05:18 +01005029 ip_base = ip_profile["subnet_address"].rsplit(".", 1)[0] + "."
kasarde691232017-03-25 03:37:31 -07005030
sousaedu80135b92021-02-17 15:05:18 +01005031 if (
5032 "gateway_address" not in ip_profile
5033 or ip_profile["gateway_address"] is None
5034 ):
5035 ip_profile["gateway_address"] = ip_base + "1"
bhangare0e571a92017-01-12 04:02:23 -08005036
sousaedu80135b92021-02-17 15:05:18 +01005037 if "dhcp_count" not in ip_profile or ip_profile["dhcp_count"] is None:
5038 ip_profile["dhcp_count"] = DEFAULT_IP_PROFILE["dhcp_count"]
bhangare0e571a92017-01-12 04:02:23 -08005039
sousaedu80135b92021-02-17 15:05:18 +01005040 if (
5041 "dhcp_enabled" not in ip_profile
5042 or ip_profile["dhcp_enabled"] is None
5043 ):
5044 ip_profile["dhcp_enabled"] = DEFAULT_IP_PROFILE["dhcp_enabled"]
5045
5046 if (
5047 "dhcp_start_address" not in ip_profile
5048 or ip_profile["dhcp_start_address"] is None
5049 ):
5050 ip_profile["dhcp_start_address"] = ip_base + "3"
5051
5052 if "ip_version" not in ip_profile or ip_profile["ip_version"] is None:
5053 ip_profile["ip_version"] = DEFAULT_IP_PROFILE["ip_version"]
5054
5055 if "dns_address" not in ip_profile or ip_profile["dns_address"] is None:
5056 ip_profile["dns_address"] = ip_base + "2"
5057
5058 gateway_address = ip_profile["gateway_address"]
5059 dhcp_count = int(ip_profile["dhcp_count"])
5060 subnet_address = self.convert_cidr_to_netmask(
5061 ip_profile["subnet_address"]
5062 )
5063
5064 if ip_profile["dhcp_enabled"] is True:
5065 dhcp_enabled = "true"
bhangarebfdca492017-03-11 01:32:46 -08005066 else:
sousaedu80135b92021-02-17 15:05:18 +01005067 dhcp_enabled = "false"
5068
5069 dhcp_start_address = ip_profile["dhcp_start_address"]
bhangare0e571a92017-01-12 04:02:23 -08005070
beierlb22ce2d2019-12-12 12:09:51 -05005071 # derive dhcp_end_address from dhcp_start_address & dhcp_count
bhangarebfdca492017-03-11 01:32:46 -08005072 end_ip_int = int(netaddr.IPAddress(dhcp_start_address))
5073 end_ip_int += dhcp_count - 1
5074 dhcp_end_address = str(netaddr.IPAddress(end_ip_int))
5075
beierlb22ce2d2019-12-12 12:09:51 -05005076 # ip_version = ip_profile['ip_version']
sousaedu80135b92021-02-17 15:05:18 +01005077 dns_address = ip_profile["dns_address"]
bhangarebfdca492017-03-11 01:32:46 -08005078 except KeyError as exp:
5079 self.logger.debug("Create Network REST: Key error {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01005080
5081 raise vimconn.VimConnException(
5082 "Create Network REST: Key error{}".format(exp)
5083 )
bhangare0e571a92017-01-12 04:02:23 -08005084
bayramovef390722016-09-27 03:34:46 -07005085 # either use client provided UUID or search for a first available
5086 # if both are not defined we return none
5087 if parent_network_uuid is not None:
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00005088 provider_network = None
5089 available_networks = None
5090 add_vdc_rest_url = None
sousaedu80135b92021-02-17 15:05:18 +01005091 url_list = [self.url, "/api/admin/vdc/", self.tenant_id, "/networks"]
5092 add_vdc_rest_url = "".join(url_list)
5093 url_list = [self.url, "/api/admin/network/", parent_network_uuid]
5094 available_networks = "".join(url_list)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00005095
beierlb22ce2d2019-12-12 12:09:51 -05005096 # Creating all networks as Direct Org VDC type networks.
5097 # Unused in case of Underlay (data/ptp) network interface.
5098 fence_mode = "isolated"
sousaedu80135b92021-02-17 15:05:18 +01005099 is_inherited = "false"
tierno455612d2017-05-30 16:40:10 +02005100 dns_list = dns_address.split(";")
5101 dns1 = dns_list[0]
5102 dns2_text = ""
sousaedu80135b92021-02-17 15:05:18 +01005103
tierno455612d2017-05-30 16:40:10 +02005104 if len(dns_list) >= 2:
sousaedu80135b92021-02-17 15:05:18 +01005105 dns2_text = "\n <Dns2>{}</Dns2>\n".format(
5106 dns_list[1]
5107 )
5108
kbsuba85c54d2019-10-17 16:30:32 +00005109 if net_type == "isolated":
beierlb22ce2d2019-12-12 12:09:51 -05005110 fence_mode = "isolated"
kbsuba85c54d2019-10-17 16:30:32 +00005111 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5112 <Description>Openmano created</Description>
5113 <Configuration>
5114 <IpScopes>
5115 <IpScope>
5116 <IsInherited>{1:s}</IsInherited>
5117 <Gateway>{2:s}</Gateway>
5118 <Netmask>{3:s}</Netmask>
5119 <Dns1>{4:s}</Dns1>{5:s}
5120 <IsEnabled>{6:s}</IsEnabled>
5121 <IpRanges>
5122 <IpRange>
5123 <StartAddress>{7:s}</StartAddress>
5124 <EndAddress>{8:s}</EndAddress>
5125 </IpRange>
5126 </IpRanges>
5127 </IpScope>
5128 </IpScopes>
5129 <FenceMode>{9:s}</FenceMode>
5130 </Configuration>
5131 <IsShared>{10:s}</IsShared>
sousaedu80135b92021-02-17 15:05:18 +01005132 </OrgVdcNetwork> """.format(
5133 escape(network_name),
5134 is_inherited,
5135 gateway_address,
5136 subnet_address,
5137 dns1,
5138 dns2_text,
5139 dhcp_enabled,
5140 dhcp_start_address,
5141 dhcp_end_address,
5142 fence_mode,
5143 isshared,
5144 )
kbsuba85c54d2019-10-17 16:30:32 +00005145 else:
5146 fence_mode = "bridged"
5147 data = """ <OrgVdcNetwork name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5148 <Description>Openmano created</Description>
5149 <Configuration>
5150 <IpScopes>
5151 <IpScope>
5152 <IsInherited>{1:s}</IsInherited>
5153 <Gateway>{2:s}</Gateway>
5154 <Netmask>{3:s}</Netmask>
5155 <Dns1>{4:s}</Dns1>{5:s}
5156 <IsEnabled>{6:s}</IsEnabled>
5157 <IpRanges>
5158 <IpRange>
5159 <StartAddress>{7:s}</StartAddress>
5160 <EndAddress>{8:s}</EndAddress>
5161 </IpRange>
5162 </IpRanges>
5163 </IpScope>
5164 </IpScopes>
5165 <ParentNetwork href="{9:s}"/>
5166 <FenceMode>{10:s}</FenceMode>
5167 </Configuration>
5168 <IsShared>{11:s}</IsShared>
sousaedu80135b92021-02-17 15:05:18 +01005169 </OrgVdcNetwork> """.format(
5170 escape(network_name),
5171 is_inherited,
5172 gateway_address,
5173 subnet_address,
5174 dns1,
5175 dns2_text,
5176 dhcp_enabled,
5177 dhcp_start_address,
5178 dhcp_end_address,
5179 available_networks,
5180 fence_mode,
5181 isshared,
5182 )
bayramovef390722016-09-27 03:34:46 -07005183
sousaedu80135b92021-02-17 15:05:18 +01005184 headers["Content-Type"] = "application/vnd.vmware.vcloud.orgVdcNetwork+xml"
bhangare0e571a92017-01-12 04:02:23 -08005185 try:
sousaedu80135b92021-02-17 15:05:18 +01005186 response = self.perform_request(
5187 req_type="POST", url=add_vdc_rest_url, headers=headers, data=data
5188 )
bayramovef390722016-09-27 03:34:46 -07005189
bhangare0e571a92017-01-12 04:02:23 -08005190 if response.status_code != 201:
sousaedu80135b92021-02-17 15:05:18 +01005191 self.logger.debug(
5192 "Create Network POST REST API call failed. "
5193 "Return status code {}, response.text: {}".format(
5194 response.status_code, response.text
5195 )
5196 )
bhangare0e571a92017-01-12 04:02:23 -08005197 else:
beierl26fec002019-12-06 17:06:40 -05005198 network_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01005199 self.logger.debug(
5200 "Create Network REST : Waiting for Network creation complete"
5201 )
kasarc5bf2932018-03-09 04:15:22 -08005202 time.sleep(5)
sousaedu80135b92021-02-17 15:05:18 +01005203 result = self.client.get_task_monitor().wait_for_success(
5204 task=network_task
5205 )
5206
5207 if result.get("status") == "success":
beierl26fec002019-12-06 17:06:40 -05005208 return response.text
kasarc5bf2932018-03-09 04:15:22 -08005209 else:
sousaedu80135b92021-02-17 15:05:18 +01005210 self.logger.debug(
5211 "create_network_rest task failed. Network Create response : {}".format(
5212 response.text
5213 )
5214 )
bhangare0e571a92017-01-12 04:02:23 -08005215 except Exception as exp:
5216 self.logger.debug("create_network_rest : Exception : {} ".format(exp))
5217
5218 return None
5219
5220 def convert_cidr_to_netmask(self, cidr_ip=None):
5221 """
5222 Method sets convert CIDR netmask address to normal IP format
5223 Args:
5224 cidr_ip : CIDR IP address
5225 Returns:
5226 netmask : Converted netmask
5227 """
5228 if cidr_ip is not None:
sousaedu80135b92021-02-17 15:05:18 +01005229 if "/" in cidr_ip:
5230 _, net_bits = cidr_ip.split("/")
5231 netmask = socket.inet_ntoa(
5232 struct.pack(">I", (0xFFFFFFFF << (32 - int(net_bits))) & 0xFFFFFFFF)
5233 )
bhangare0e571a92017-01-12 04:02:23 -08005234 else:
5235 netmask = cidr_ip
sousaedu80135b92021-02-17 15:05:18 +01005236
bhangare0e571a92017-01-12 04:02:23 -08005237 return netmask
sousaedu80135b92021-02-17 15:05:18 +01005238
bayramovef390722016-09-27 03:34:46 -07005239 return None
5240
5241 def get_provider_rest(self, vca=None):
5242 """
5243 Method gets provider vdc view from vcloud director
5244
5245 Args:
5246 network_name - is network name to be created.
5247 parent_network_uuid - is parent provider vdc network that will be used for mapping.
5248 It optional attribute. by default if no parent network indicate the first available will be used.
5249
5250 Returns:
5251 The return xml content of respond or None
5252 """
sousaedu80135b92021-02-17 15:05:18 +01005253 url_list = [self.url, "/api/admin"]
bayramovef390722016-09-27 03:34:46 -07005254
kasarc5bf2932018-03-09 04:15:22 -08005255 if vca:
sousaedu80135b92021-02-17 15:05:18 +01005256 headers = {
5257 "Accept": "application/*+xml;version=" + API_VERSION,
5258 "x-vcloud-authorization": self.client._session.headers[
5259 "x-vcloud-authorization"
5260 ],
5261 }
5262 response = self.perform_request(
5263 req_type="GET", url="".join(url_list), headers=headers
5264 )
bayramovef390722016-09-27 03:34:46 -07005265
5266 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05005267 return response.text
sousaedu80135b92021-02-17 15:05:18 +01005268
bayramovef390722016-09-27 03:34:46 -07005269 return None
5270
5271 def create_vdc(self, vdc_name=None):
bayramovef390722016-09-27 03:34:46 -07005272 vdc_dict = {}
bayramovef390722016-09-27 03:34:46 -07005273 xml_content = self.create_vdc_from_tmpl_rest(vdc_name=vdc_name)
sousaedu80135b92021-02-17 15:05:18 +01005274
bayramovef390722016-09-27 03:34:46 -07005275 if xml_content is not None:
bayramovef390722016-09-27 03:34:46 -07005276 try:
5277 task_resp_xmlroot = XmlElementTree.fromstring(xml_content)
5278 for child in task_resp_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01005279 if child.tag.split("}")[1] == "Owner":
5280 vdc_id = child.attrib.get("href").split("/")[-1]
5281 vdc_dict[vdc_id] = task_resp_xmlroot.get("href")
5282
bayramovef390722016-09-27 03:34:46 -07005283 return vdc_dict
beierlb22ce2d2019-12-12 12:09:51 -05005284 except Exception:
bayramovef390722016-09-27 03:34:46 -07005285 self.logger.debug("Respond body {}".format(xml_content))
5286
5287 return None
5288
5289 def create_vdc_from_tmpl_rest(self, vdc_name=None):
5290 """
5291 Method create vdc in vCloud director based on VDC template.
kasarc5bf2932018-03-09 04:15:22 -08005292 it uses pre-defined template.
bayramovef390722016-09-27 03:34:46 -07005293
5294 Args:
5295 vdc_name - name of a new vdc.
5296
5297 Returns:
5298 The return xml content of respond or None
5299 """
kasarc5bf2932018-03-09 04:15:22 -08005300 # pre-requesite atleast one vdc template should be available in vCD
bayramovef390722016-09-27 03:34:46 -07005301 self.logger.info("Creating new vdc {}".format(vdc_name))
kasarc5bf2932018-03-09 04:15:22 -08005302 vca = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01005303
bayramovef390722016-09-27 03:34:46 -07005304 if not vca:
tierno72774862020-05-04 11:44:15 +00005305 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu80135b92021-02-17 15:05:18 +01005306
bayramovef390722016-09-27 03:34:46 -07005307 if vdc_name is None:
5308 return None
5309
sousaedu80135b92021-02-17 15:05:18 +01005310 url_list = [self.url, "/api/vdcTemplates"]
5311 vm_list_rest_call = "".join(url_list)
5312 headers = {
5313 "Accept": "application/*+xml;version=" + API_VERSION,
5314 "x-vcloud-authorization": vca._session.headers["x-vcloud-authorization"],
5315 }
5316 response = self.perform_request(
5317 req_type="GET", url=vm_list_rest_call, headers=headers
5318 )
bayramovef390722016-09-27 03:34:46 -07005319
5320 # container url to a template
5321 vdc_template_ref = None
5322 try:
beierl26fec002019-12-06 17:06:40 -05005323 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005324 for child in vm_list_xmlroot:
5325 # application/vnd.vmware.admin.providervdc+xml
5326 # we need find a template from witch we instantiate VDC
sousaedu80135b92021-02-17 15:05:18 +01005327 if child.tag.split("}")[1] == "VdcTemplate":
5328 if (
5329 child.attrib.get("type")
5330 == "application/vnd.vmware.admin.vdcTemplate+xml"
5331 ):
5332 vdc_template_ref = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005333 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005334 self.logger.debug(
5335 "Failed parse respond for rest api call {}".format(vm_list_rest_call)
5336 )
beierl26fec002019-12-06 17:06:40 -05005337 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01005338
bayramovef390722016-09-27 03:34:46 -07005339 return None
5340
5341 # if we didn't found required pre defined template we return None
5342 if vdc_template_ref is None:
5343 return None
5344
5345 try:
5346 # instantiate vdc
sousaedu80135b92021-02-17 15:05:18 +01005347 url_list = [self.url, "/api/org/", self.org_uuid, "/action/instantiate"]
5348 vm_list_rest_call = "".join(url_list)
bayramovef390722016-09-27 03:34:46 -07005349 data = """<InstantiateVdcTemplateParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5">
5350 <Source href="{1:s}"></Source>
5351 <Description>opnemano</Description>
sousaedu80135b92021-02-17 15:05:18 +01005352 </InstantiateVdcTemplateParams>""".format(
5353 vdc_name, vdc_template_ref
5354 )
5355 headers[
5356 "Content-Type"
5357 ] = "application/vnd.vmware.vcloud.instantiateVdcTemplateParams+xml"
5358 response = self.perform_request(
5359 req_type="POST", url=vm_list_rest_call, headers=headers, data=data
5360 )
beierl26fec002019-12-06 17:06:40 -05005361 vdc_task = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08005362 self.client.get_task_monitor().wait_for_success(task=vdc_task)
kated47ad5f2017-08-03 02:16:13 -07005363
bayramovef390722016-09-27 03:34:46 -07005364 # if we all ok we respond with content otherwise by default None
5365 if response.status_code >= 200 and response.status_code < 300:
beierl26fec002019-12-06 17:06:40 -05005366 return response.text
sousaedu80135b92021-02-17 15:05:18 +01005367
bayramovef390722016-09-27 03:34:46 -07005368 return None
beierlb22ce2d2019-12-12 12:09:51 -05005369 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005370 self.logger.debug(
5371 "Failed parse respond for rest api call {}".format(vm_list_rest_call)
5372 )
beierl26fec002019-12-06 17:06:40 -05005373 self.logger.debug("Respond body {}".format(response.text))
bayramovef390722016-09-27 03:34:46 -07005374
5375 return None
5376
5377 def create_vdc_rest(self, vdc_name=None):
5378 """
5379 Method create network in vCloud director
5380
5381 Args:
kasarc5bf2932018-03-09 04:15:22 -08005382 vdc_name - vdc name to be created
bayramovef390722016-09-27 03:34:46 -07005383 Returns:
kasarc5bf2932018-03-09 04:15:22 -08005384 The return response
bayramovef390722016-09-27 03:34:46 -07005385 """
bayramovef390722016-09-27 03:34:46 -07005386 self.logger.info("Creating new vdc {}".format(vdc_name))
bayramovef390722016-09-27 03:34:46 -07005387 vca = self.connect_as_admin()
sousaedu80135b92021-02-17 15:05:18 +01005388
bayramovef390722016-09-27 03:34:46 -07005389 if not vca:
tierno72774862020-05-04 11:44:15 +00005390 raise vimconn.VimConnConnectionException("Failed to connect vCD")
sousaedu80135b92021-02-17 15:05:18 +01005391
bayramovef390722016-09-27 03:34:46 -07005392 if vdc_name is None:
5393 return None
5394
sousaedu80135b92021-02-17 15:05:18 +01005395 url_list = [self.url, "/api/admin/org/", self.org_uuid]
5396 vm_list_rest_call = "".join(url_list)
kasarc5bf2932018-03-09 04:15:22 -08005397
5398 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01005399 headers = {
5400 "Accept": "application/*+xml;version=" + API_VERSION,
5401 "x-vcloud-authorization": self.client._session.headers[
5402 "x-vcloud-authorization"
5403 ],
5404 }
5405 response = self.perform_request(
5406 req_type="GET", url=vm_list_rest_call, headers=headers
5407 )
bayramovef390722016-09-27 03:34:46 -07005408 provider_vdc_ref = None
5409 add_vdc_rest_url = None
beierlb22ce2d2019-12-12 12:09:51 -05005410 # available_networks = None
bayramovef390722016-09-27 03:34:46 -07005411
5412 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01005413 self.logger.debug(
5414 "REST API call {} failed. Return status code {}".format(
5415 vm_list_rest_call, response.status_code
5416 )
5417 )
5418
bayramovef390722016-09-27 03:34:46 -07005419 return None
5420 else:
5421 try:
beierl26fec002019-12-06 17:06:40 -05005422 vm_list_xmlroot = XmlElementTree.fromstring(response.text)
bayramovef390722016-09-27 03:34:46 -07005423 for child in vm_list_xmlroot:
5424 # application/vnd.vmware.admin.providervdc+xml
sousaedu80135b92021-02-17 15:05:18 +01005425 if child.tag.split("}")[1] == "Link":
5426 if (
5427 child.attrib.get("type")
5428 == "application/vnd.vmware.admin.createVdcParams+xml"
5429 and child.attrib.get("rel") == "add"
5430 ):
5431 add_vdc_rest_url = child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005432 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005433 self.logger.debug(
5434 "Failed parse respond for rest api call {}".format(
5435 vm_list_rest_call
5436 )
5437 )
beierl26fec002019-12-06 17:06:40 -05005438 self.logger.debug("Respond body {}".format(response.text))
sousaedu80135b92021-02-17 15:05:18 +01005439
bayramovef390722016-09-27 03:34:46 -07005440 return None
5441
5442 response = self.get_provider_rest(vca=vca)
bayramovef390722016-09-27 03:34:46 -07005443 try:
5444 vm_list_xmlroot = XmlElementTree.fromstring(response)
5445 for child in vm_list_xmlroot:
sousaedu80135b92021-02-17 15:05:18 +01005446 if child.tag.split("}")[1] == "ProviderVdcReferences":
bayramovef390722016-09-27 03:34:46 -07005447 for sub_child in child:
sousaedu80135b92021-02-17 15:05:18 +01005448 provider_vdc_ref = sub_child.attrib.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05005449 except Exception:
sousaedu80135b92021-02-17 15:05:18 +01005450 self.logger.debug(
5451 "Failed parse respond for rest api call {}".format(
5452 vm_list_rest_call
5453 )
5454 )
bayramovef390722016-09-27 03:34:46 -07005455 self.logger.debug("Respond body {}".format(response))
sousaedu80135b92021-02-17 15:05:18 +01005456
bayramovef390722016-09-27 03:34:46 -07005457 return None
5458
bayramovef390722016-09-27 03:34:46 -07005459 if add_vdc_rest_url is not None and provider_vdc_ref is not None:
5460 data = """ <CreateVdcParams name="{0:s}" xmlns="http://www.vmware.com/vcloud/v1.5"><Description>{1:s}</Description>
5461 <AllocationModel>ReservationPool</AllocationModel>
5462 <ComputeCapacity><Cpu><Units>MHz</Units><Allocated>2048</Allocated><Limit>2048</Limit></Cpu>
5463 <Memory><Units>MB</Units><Allocated>2048</Allocated><Limit>2048</Limit></Memory>
5464 </ComputeCapacity><NicQuota>0</NicQuota><NetworkQuota>100</NetworkQuota>
5465 <VdcStorageProfile><Enabled>true</Enabled><Units>MB</Units><Limit>20480</Limit><Default>true</Default></VdcStorageProfile>
5466 <ProviderVdcReference
5467 name="Main Provider"
5468 href="{2:s}" />
sousaedu80135b92021-02-17 15:05:18 +01005469 <UsesFastProvisioning>true</UsesFastProvisioning></CreateVdcParams>""".format(
5470 escape(vdc_name), escape(vdc_name), provider_vdc_ref
5471 )
5472 headers[
5473 "Content-Type"
5474 ] = "application/vnd.vmware.admin.createVdcParams+xml"
5475 response = self.perform_request(
5476 req_type="POST",
5477 url=add_vdc_rest_url,
5478 headers=headers,
5479 data=data,
5480 )
bayramovef390722016-09-27 03:34:46 -07005481
bayramovef390722016-09-27 03:34:46 -07005482 # if we all ok we respond with content otherwise by default None
5483 if response.status_code == 201:
beierl26fec002019-12-06 17:06:40 -05005484 return response.text
sousaedu80135b92021-02-17 15:05:18 +01005485
bayramovef390722016-09-27 03:34:46 -07005486 return None
bayramovfe3f3c92016-10-04 07:53:41 +04005487
bhangarefda5f7c2017-01-12 23:50:34 -08005488 def get_vapp_details_rest(self, vapp_uuid=None, need_admin_access=False):
bayramovfe3f3c92016-10-04 07:53:41 +04005489 """
5490 Method retrieve vapp detail from vCloud director
5491
5492 Args:
5493 vapp_uuid - is vapp identifier.
5494
5495 Returns:
5496 The return network uuid or return None
5497 """
bayramovfe3f3c92016-10-04 07:53:41 +04005498 parsed_respond = {}
bhangarefda5f7c2017-01-12 23:50:34 -08005499 vca = None
bayramovfe3f3c92016-10-04 07:53:41 +04005500
bhangarefda5f7c2017-01-12 23:50:34 -08005501 if need_admin_access:
5502 vca = self.connect_as_admin()
5503 else:
sbhangarea8e5b782018-06-21 02:10:03 -07005504 vca = self.client
bhangarefda5f7c2017-01-12 23:50:34 -08005505
bayramovfe3f3c92016-10-04 07:53:41 +04005506 if not vca:
tierno72774862020-05-04 11:44:15 +00005507 raise vimconn.VimConnConnectionException("Failed to connect vCD")
bayramovfe3f3c92016-10-04 07:53:41 +04005508 if vapp_uuid is None:
5509 return None
5510
sousaedu80135b92021-02-17 15:05:18 +01005511 url_list = [self.url, "/api/vApp/vapp-", vapp_uuid]
5512 get_vapp_restcall = "".join(url_list)
bhangarefda5f7c2017-01-12 23:50:34 -08005513
kasarc5bf2932018-03-09 04:15:22 -08005514 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01005515 headers = {
5516 "Accept": "application/*+xml;version=" + API_VERSION,
5517 "x-vcloud-authorization": vca._session.headers[
5518 "x-vcloud-authorization"
5519 ],
5520 }
5521 response = self.perform_request(
5522 req_type="GET", url=get_vapp_restcall, headers=headers
5523 )
bayramovfe3f3c92016-10-04 07:53:41 +04005524
bhangare1a0b97c2017-06-21 02:20:15 -07005525 if response.status_code == 403:
beierlb22ce2d2019-12-12 12:09:51 -05005526 if need_admin_access is False:
sousaedu80135b92021-02-17 15:05:18 +01005527 response = self.retry_rest("GET", get_vapp_restcall)
bhangare1a0b97c2017-06-21 02:20:15 -07005528
bayramovfe3f3c92016-10-04 07:53:41 +04005529 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01005530 self.logger.debug(
5531 "REST API call {} failed. Return status code {}".format(
5532 get_vapp_restcall, response.status_code
5533 )
5534 )
5535
bayramovfe3f3c92016-10-04 07:53:41 +04005536 return parsed_respond
5537
5538 try:
beierl26fec002019-12-06 17:06:40 -05005539 xmlroot_respond = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01005540 parsed_respond["ovfDescriptorUploaded"] = xmlroot_respond.attrib[
5541 "ovfDescriptorUploaded"
5542 ]
beierlb22ce2d2019-12-12 12:09:51 -05005543 namespaces = {
5544 "vssd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData",
sousaedu80135b92021-02-17 15:05:18 +01005545 "ovf": "http://schemas.dmtf.org/ovf/envelope/1",
5546 "vmw": "http://www.vmware.com/schema/ovf",
5547 "vm": "http://www.vmware.com/vcloud/v1.5",
5548 "rasd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
beierlb22ce2d2019-12-12 12:09:51 -05005549 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
sousaedu80135b92021-02-17 15:05:18 +01005550 "xmlns": "http://www.vmware.com/vcloud/v1.5",
beierlb22ce2d2019-12-12 12:09:51 -05005551 }
bayramovfe3f3c92016-10-04 07:53:41 +04005552
sousaedu80135b92021-02-17 15:05:18 +01005553 created_section = xmlroot_respond.find("vm:DateCreated", namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04005554 if created_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01005555 parsed_respond["created"] = created_section.text
bayramovfe3f3c92016-10-04 07:53:41 +04005556
sousaedu80135b92021-02-17 15:05:18 +01005557 network_section = xmlroot_respond.find(
5558 "vm:NetworkConfigSection/vm:NetworkConfig", namespaces
5559 )
5560 if (
5561 network_section is not None
5562 and "networkName" in network_section.attrib
5563 ):
5564 parsed_respond["networkname"] = network_section.attrib[
5565 "networkName"
5566 ]
bayramovfe3f3c92016-10-04 07:53:41 +04005567
sousaedu80135b92021-02-17 15:05:18 +01005568 ipscopes_section = xmlroot_respond.find(
5569 "vm:NetworkConfigSection/vm:NetworkConfig/vm:Configuration/vm:IpScopes",
5570 namespaces,
5571 )
bayramovfe3f3c92016-10-04 07:53:41 +04005572 if ipscopes_section is not None:
5573 for ipscope in ipscopes_section:
5574 for scope in ipscope:
5575 tag_key = scope.tag.split("}")[1]
sousaedu80135b92021-02-17 15:05:18 +01005576 if tag_key == "IpRanges":
bayramovfe3f3c92016-10-04 07:53:41 +04005577 ip_ranges = scope.getchildren()
5578 for ipblock in ip_ranges:
5579 for block in ipblock:
sousaedu80135b92021-02-17 15:05:18 +01005580 parsed_respond[
5581 block.tag.split("}")[1]
5582 ] = block.text
bayramovfe3f3c92016-10-04 07:53:41 +04005583 else:
5584 parsed_respond[tag_key] = scope.text
5585
5586 # parse children section for other attrib
sousaedu80135b92021-02-17 15:05:18 +01005587 children_section = xmlroot_respond.find("vm:Children/", namespaces)
bayramovfe3f3c92016-10-04 07:53:41 +04005588 if children_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01005589 parsed_respond["name"] = children_section.attrib["name"]
5590 parsed_respond["nestedHypervisorEnabled"] = (
5591 children_section.attrib["nestedHypervisorEnabled"]
5592 if "nestedHypervisorEnabled" in children_section.attrib
5593 else None
5594 )
5595 parsed_respond["deployed"] = children_section.attrib["deployed"]
5596 parsed_respond["status"] = children_section.attrib["status"]
5597 parsed_respond["vmuuid"] = children_section.attrib["id"].split(":")[
5598 -1
5599 ]
5600 network_adapter = children_section.find(
5601 "vm:NetworkConnectionSection", namespaces
5602 )
bayramovfe3f3c92016-10-04 07:53:41 +04005603 nic_list = []
5604 for adapters in network_adapter:
5605 adapter_key = adapters.tag.split("}")[1]
sousaedu80135b92021-02-17 15:05:18 +01005606 if adapter_key == "PrimaryNetworkConnectionIndex":
5607 parsed_respond["primarynetwork"] = adapters.text
5608
5609 if adapter_key == "NetworkConnection":
bayramovfe3f3c92016-10-04 07:53:41 +04005610 vnic = {}
sousaedu80135b92021-02-17 15:05:18 +01005611 if "network" in adapters.attrib:
5612 vnic["network"] = adapters.attrib["network"]
bayramovfe3f3c92016-10-04 07:53:41 +04005613 for adapter in adapters:
5614 setting_key = adapter.tag.split("}")[1]
5615 vnic[setting_key] = adapter.text
5616 nic_list.append(vnic)
5617
5618 for link in children_section:
sousaedu80135b92021-02-17 15:05:18 +01005619 if link.tag.split("}")[1] == "Link" and "rel" in link.attrib:
5620 if link.attrib["rel"] == "screen:acquireTicket":
5621 parsed_respond["acquireTicket"] = link.attrib
bayramovfe3f3c92016-10-04 07:53:41 +04005622
sousaedu80135b92021-02-17 15:05:18 +01005623 if link.attrib["rel"] == "screen:acquireMksTicket":
5624 parsed_respond["acquireMksTicket"] = link.attrib
5625
5626 parsed_respond["interfaces"] = nic_list
5627 vCloud_extension_section = children_section.find(
5628 "xmlns:VCloudExtension", namespaces
5629 )
bhangarefda5f7c2017-01-12 23:50:34 -08005630 if vCloud_extension_section is not None:
5631 vm_vcenter_info = {}
sousaedu80135b92021-02-17 15:05:18 +01005632 vim_info = vCloud_extension_section.find(
5633 "vmext:VmVimInfo", namespaces
5634 )
5635 vmext = vim_info.find("vmext:VmVimObjectRef", namespaces)
5636
bhangarefda5f7c2017-01-12 23:50:34 -08005637 if vmext is not None:
sousaedu80135b92021-02-17 15:05:18 +01005638 vm_vcenter_info["vm_moref_id"] = vmext.find(
5639 "vmext:MoRef", namespaces
5640 ).text
5641
beierlb22ce2d2019-12-12 12:09:51 -05005642 parsed_respond["vm_vcenter_info"] = vm_vcenter_info
bayramovfe3f3c92016-10-04 07:53:41 +04005643
sousaedu80135b92021-02-17 15:05:18 +01005644 virtual_hardware_section = children_section.find(
5645 "ovf:VirtualHardwareSection", namespaces
5646 )
bhangarea92ae392017-01-12 22:30:29 -08005647 vm_virtual_hardware_info = {}
5648 if virtual_hardware_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01005649 for item in virtual_hardware_section.iterfind(
5650 "ovf:Item", namespaces
5651 ):
5652 if (
5653 item.find("rasd:Description", namespaces).text
5654 == "Hard disk"
5655 ):
beierlb22ce2d2019-12-12 12:09:51 -05005656 disk_size = item.find(
sousaedu80135b92021-02-17 15:05:18 +01005657 "rasd:HostResource", namespaces
5658 ).attrib["{" + namespaces["vm"] + "}capacity"]
beierlb22ce2d2019-12-12 12:09:51 -05005659 vm_virtual_hardware_info["disk_size"] = disk_size
bhangarea92ae392017-01-12 22:30:29 -08005660 break
5661
5662 for link in virtual_hardware_section:
sousaedu80135b92021-02-17 15:05:18 +01005663 if (
5664 link.tag.split("}")[1] == "Link"
5665 and "rel" in link.attrib
5666 ):
5667 if link.attrib["rel"] == "edit" and link.attrib[
5668 "href"
5669 ].endswith("/disks"):
5670 vm_virtual_hardware_info[
5671 "disk_edit_href"
5672 ] = link.attrib["href"]
bhangarea92ae392017-01-12 22:30:29 -08005673 break
5674
beierlb22ce2d2019-12-12 12:09:51 -05005675 parsed_respond["vm_virtual_hardware"] = vm_virtual_hardware_info
5676 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01005677 self.logger.info(
5678 "Error occurred calling rest api for getting vApp details {}".format(
5679 exp
5680 )
5681 )
5682
bayramovfe3f3c92016-10-04 07:53:41 +04005683 return parsed_respond
5684
kasarc5bf2932018-03-09 04:15:22 -08005685 def acquire_console(self, vm_uuid=None):
bayramovfe3f3c92016-10-04 07:53:41 +04005686 if vm_uuid is None:
5687 return None
bayramovfe3f3c92016-10-04 07:53:41 +04005688
sousaedu80135b92021-02-17 15:05:18 +01005689 if self.client._session:
5690 headers = {
5691 "Accept": "application/*+xml;version=" + API_VERSION,
5692 "x-vcloud-authorization": self.client._session.headers[
5693 "x-vcloud-authorization"
5694 ],
5695 }
5696 vm_dict = self.get_vapp_details_rest(vapp_uuid=vm_uuid)
5697 console_dict = vm_dict["acquireTicket"]
5698 console_rest_call = console_dict["href"]
5699
5700 response = self.perform_request(
5701 req_type="POST", url=console_rest_call, headers=headers
5702 )
kasarc5bf2932018-03-09 04:15:22 -08005703
bhangare1a0b97c2017-06-21 02:20:15 -07005704 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01005705 response = self.retry_rest("POST", console_rest_call)
bayramovfe3f3c92016-10-04 07:53:41 +04005706
bayramov5761ad12016-10-04 09:00:30 +04005707 if response.status_code == requests.codes.ok:
beierl26fec002019-12-06 17:06:40 -05005708 return response.text
bayramovfe3f3c92016-10-04 07:53:41 +04005709
kate15f1c382016-12-15 01:12:40 -08005710 return None
kate13ab2c42016-12-23 01:34:24 -08005711
bhangarea92ae392017-01-12 22:30:29 -08005712 def modify_vm_disk(self, vapp_uuid, flavor_disk):
5713 """
5714 Method retrieve vm disk details
5715
5716 Args:
5717 vapp_uuid - is vapp identifier.
5718 flavor_disk - disk size as specified in VNFD (flavor)
5719
5720 Returns:
5721 The return network uuid or return None
5722 """
5723 status = None
5724 try:
beierlb22ce2d2019-12-12 12:09:51 -05005725 # Flavor disk is in GB convert it into MB
bhangarea92ae392017-01-12 22:30:29 -08005726 flavor_disk = int(flavor_disk) * 1024
5727 vm_details = self.get_vapp_details_rest(vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01005728
bhangarea92ae392017-01-12 22:30:29 -08005729 if vm_details:
5730 vm_name = vm_details["name"]
beierlb22ce2d2019-12-12 12:09:51 -05005731 self.logger.info("VM: {} flavor_disk :{}".format(vm_name, flavor_disk))
bhangarea92ae392017-01-12 22:30:29 -08005732
5733 if vm_details and "vm_virtual_hardware" in vm_details:
5734 vm_disk = int(vm_details["vm_virtual_hardware"]["disk_size"])
5735 disk_edit_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
beierlb22ce2d2019-12-12 12:09:51 -05005736 self.logger.info("VM: {} VM_disk :{}".format(vm_name, vm_disk))
bhangarea92ae392017-01-12 22:30:29 -08005737
5738 if flavor_disk > vm_disk:
beierlb22ce2d2019-12-12 12:09:51 -05005739 status = self.modify_vm_disk_rest(disk_edit_href, flavor_disk)
sousaedu80135b92021-02-17 15:05:18 +01005740 self.logger.info(
5741 "Modify disk of VM {} from {} to {} MB".format(
5742 vm_name, vm_disk, flavor_disk
5743 )
5744 )
bhangarea92ae392017-01-12 22:30:29 -08005745 else:
5746 status = True
5747 self.logger.info("No need to modify disk of VM {}".format(vm_name))
5748
5749 return status
5750 except Exception as exp:
5751 self.logger.info("Error occurred while modifing disk size {}".format(exp))
5752
beierlb22ce2d2019-12-12 12:09:51 -05005753 def modify_vm_disk_rest(self, disk_href, disk_size):
bhangarea92ae392017-01-12 22:30:29 -08005754 """
5755 Method retrieve modify vm disk size
5756
5757 Args:
5758 disk_href - vCD API URL to GET and PUT disk data
5759 disk_size - disk size as specified in VNFD (flavor)
5760
5761 Returns:
5762 The return network uuid or return None
5763 """
bhangarea92ae392017-01-12 22:30:29 -08005764 if disk_href is None or disk_size is None:
5765 return None
5766
kasarc5bf2932018-03-09 04:15:22 -08005767 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01005768 headers = {
5769 "Accept": "application/*+xml;version=" + API_VERSION,
5770 "x-vcloud-authorization": self.client._session.headers[
5771 "x-vcloud-authorization"
5772 ],
5773 }
5774 response = self.perform_request(
5775 req_type="GET", url=disk_href, headers=headers
5776 )
bhangare1a0b97c2017-06-21 02:20:15 -07005777
5778 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01005779 response = self.retry_rest("GET", disk_href)
bhangarea92ae392017-01-12 22:30:29 -08005780
5781 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01005782 self.logger.debug(
5783 "GET REST API call {} failed. Return status code {}".format(
5784 disk_href, response.status_code
5785 )
5786 )
5787
bhangarea92ae392017-01-12 22:30:29 -08005788 return None
sousaedu80135b92021-02-17 15:05:18 +01005789
bhangarea92ae392017-01-12 22:30:29 -08005790 try:
beierl01bd6692019-12-09 17:06:20 -05005791 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01005792 namespaces = {
5793 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
5794 }
beierlb22ce2d2019-12-12 12:09:51 -05005795 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
bhangarea92ae392017-01-12 22:30:29 -08005796
sousaedu80135b92021-02-17 15:05:18 +01005797 for item in lxmlroot_respond.iterfind("xmlns:Item", namespaces):
beierlb22ce2d2019-12-12 12:09:51 -05005798 if item.find("rasd:Description", namespaces).text == "Hard disk":
5799 disk_item = item.find("rasd:HostResource", namespaces)
bhangarea92ae392017-01-12 22:30:29 -08005800 if disk_item is not None:
sousaedu80135b92021-02-17 15:05:18 +01005801 disk_item.attrib["{" + namespaces["xmlns"] + "}capacity"] = str(
5802 disk_size
5803 )
bhangarea92ae392017-01-12 22:30:29 -08005804 break
5805
sousaedu80135b92021-02-17 15:05:18 +01005806 data = lxmlElementTree.tostring(
5807 lxmlroot_respond, encoding="utf8", method="xml", xml_declaration=True
5808 )
bhangarea92ae392017-01-12 22:30:29 -08005809
beierlb22ce2d2019-12-12 12:09:51 -05005810 # Send PUT request to modify disk size
sousaedu80135b92021-02-17 15:05:18 +01005811 headers[
5812 "Content-Type"
5813 ] = "application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1"
bhangarea92ae392017-01-12 22:30:29 -08005814
sousaedu80135b92021-02-17 15:05:18 +01005815 response = self.perform_request(
5816 req_type="PUT", url=disk_href, headers=headers, data=data
5817 )
bhangare1a0b97c2017-06-21 02:20:15 -07005818 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01005819 add_headers = {"Content-Type": headers["Content-Type"]}
5820 response = self.retry_rest("PUT", disk_href, add_headers, data)
bhangarea92ae392017-01-12 22:30:29 -08005821
5822 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01005823 self.logger.debug(
5824 "PUT REST API call {} failed. Return status code {}".format(
5825 disk_href, response.status_code
5826 )
5827 )
bhangarea92ae392017-01-12 22:30:29 -08005828 else:
beierl26fec002019-12-06 17:06:40 -05005829 modify_disk_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01005830 result = self.client.get_task_monitor().wait_for_success(
5831 task=modify_disk_task
5832 )
5833 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08005834 return True
5835 else:
sbhangarea8e5b782018-06-21 02:10:03 -07005836 return False
bhangarea92ae392017-01-12 22:30:29 -08005837
sousaedu80135b92021-02-17 15:05:18 +01005838 return None
beierl26fec002019-12-06 17:06:40 -05005839 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01005840 self.logger.info(
5841 "Error occurred calling rest api for modifing disk size {}".format(exp)
5842 )
5843
5844 return None
bhangarea92ae392017-01-12 22:30:29 -08005845
beierl26fec002019-12-06 17:06:40 -05005846 def add_serial_device(self, vapp_uuid):
5847 """
sousaedu80135b92021-02-17 15:05:18 +01005848 Method to attach a serial device to a VM
beierl26fec002019-12-06 17:06:40 -05005849
sousaedu80135b92021-02-17 15:05:18 +01005850 Args:
5851 vapp_uuid - uuid of vApp/VM
beierl26fec002019-12-06 17:06:40 -05005852
sousaedu80135b92021-02-17 15:05:18 +01005853 Returns:
beierl26fec002019-12-06 17:06:40 -05005854 """
5855 self.logger.info("Add serial devices into vApp {}".format(vapp_uuid))
5856 _, content = self.get_vcenter_content()
5857 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
sousaedu80135b92021-02-17 15:05:18 +01005858
beierl26fec002019-12-06 17:06:40 -05005859 if vm_moref_id:
5860 try:
5861 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01005862 self.logger.info(
5863 "VM {} is currently on host {}".format(vm_obj, host_obj)
5864 )
beierl26fec002019-12-06 17:06:40 -05005865 if host_obj and vm_obj:
5866 spec = vim.vm.ConfigSpec()
5867 spec.deviceChange = []
5868 serial_spec = vim.vm.device.VirtualDeviceSpec()
sousaedu80135b92021-02-17 15:05:18 +01005869 serial_spec.operation = "add"
beierl26fec002019-12-06 17:06:40 -05005870 serial_port = vim.vm.device.VirtualSerialPort()
5871 serial_port.yieldOnPoll = True
5872 backing = serial_port.URIBackingInfo()
sousaedu80135b92021-02-17 15:05:18 +01005873 backing.serviceURI = "tcp://:65500"
5874 backing.direction = "server"
beierl26fec002019-12-06 17:06:40 -05005875 serial_port.backing = backing
5876 serial_spec.device = serial_port
5877 spec.deviceChange.append(serial_spec)
5878 vm_obj.ReconfigVM_Task(spec=spec)
beierl26fec002019-12-06 17:06:40 -05005879 self.logger.info("Adding serial device to VM {}".format(vm_obj))
5880 except vmodl.MethodFault as error:
5881 self.logger.error("Error occurred while adding PCI devices {} ", error)
5882
5883 def add_pci_devices(self, vapp_uuid, pci_devices, vmname_andid):
bhangarefda5f7c2017-01-12 23:50:34 -08005884 """
sousaedu80135b92021-02-17 15:05:18 +01005885 Method to attach pci devices to VM
bhangarefda5f7c2017-01-12 23:50:34 -08005886
sousaedu80135b92021-02-17 15:05:18 +01005887 Args:
5888 vapp_uuid - uuid of vApp/VM
5889 pci_devices - pci devices infromation as specified in VNFD (flavor)
bhangarefda5f7c2017-01-12 23:50:34 -08005890
sousaedu80135b92021-02-17 15:05:18 +01005891 Returns:
5892 The status of add pci device task , vm object and
5893 vcenter_conect object
bhangarefda5f7c2017-01-12 23:50:34 -08005894 """
5895 vm_obj = None
sousaedu80135b92021-02-17 15:05:18 +01005896 self.logger.info(
5897 "Add pci devices {} into vApp {}".format(pci_devices, vapp_uuid)
5898 )
bhangare06312472017-03-30 05:49:07 -07005899 vcenter_conect, content = self.get_vcenter_content()
5900 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
kateeb044522017-03-06 23:54:39 -08005901
bhangare06312472017-03-30 05:49:07 -07005902 if vm_moref_id:
bhangarefda5f7c2017-01-12 23:50:34 -08005903 try:
5904 no_of_pci_devices = len(pci_devices)
5905 if no_of_pci_devices > 0:
beierlb22ce2d2019-12-12 12:09:51 -05005906 # Get VM and its host
bhangare06312472017-03-30 05:49:07 -07005907 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01005908 self.logger.info(
5909 "VM {} is currently on host {}".format(vm_obj, host_obj)
5910 )
5911
bhangarefda5f7c2017-01-12 23:50:34 -08005912 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05005913 # get PCI devies from host on which vapp is currently installed
sousaedu80135b92021-02-17 15:05:18 +01005914 avilable_pci_devices = self.get_pci_devices(
5915 host_obj, no_of_pci_devices
5916 )
bhangarefda5f7c2017-01-12 23:50:34 -08005917
5918 if avilable_pci_devices is None:
beierlb22ce2d2019-12-12 12:09:51 -05005919 # find other hosts with active pci devices
sousaedu80135b92021-02-17 15:05:18 +01005920 (
5921 new_host_obj,
5922 avilable_pci_devices,
5923 ) = self.get_host_and_PCIdevices(content, no_of_pci_devices)
5924
5925 if (
5926 new_host_obj is not None
5927 and avilable_pci_devices is not None
5928 and len(avilable_pci_devices) > 0
5929 ):
5930 # Migrate vm to the host where PCI devices are availble
5931 self.logger.info(
5932 "Relocate VM {} on new host {}".format(
5933 vm_obj, new_host_obj
5934 )
beierlb22ce2d2019-12-12 12:09:51 -05005935 )
bhangarefda5f7c2017-01-12 23:50:34 -08005936
bhangarefda5f7c2017-01-12 23:50:34 -08005937 task = self.relocate_vm(new_host_obj, vm_obj)
5938 if task is not None:
sousaedu80135b92021-02-17 15:05:18 +01005939 result = self.wait_for_vcenter_task(
5940 task, vcenter_conect
5941 )
5942 self.logger.info(
5943 "Migrate VM status: {}".format(result)
5944 )
bhangarefda5f7c2017-01-12 23:50:34 -08005945 host_obj = new_host_obj
5946 else:
sousaedu80135b92021-02-17 15:05:18 +01005947 self.logger.info(
5948 "Fail to migrate VM : {}".format(result)
5949 )
tierno72774862020-05-04 11:44:15 +00005950 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05005951 "Fail to migrate VM : {} to host {}".format(
sousaedu80135b92021-02-17 15:05:18 +01005952 vmname_andid, new_host_obj
bhangarefda5f7c2017-01-12 23:50:34 -08005953 )
sousaedu80135b92021-02-17 15:05:18 +01005954 )
bhangarefda5f7c2017-01-12 23:50:34 -08005955
sousaedu80135b92021-02-17 15:05:18 +01005956 if (
5957 host_obj is not None
5958 and avilable_pci_devices is not None
5959 and len(avilable_pci_devices) > 0
5960 ):
beierlb22ce2d2019-12-12 12:09:51 -05005961 # Add PCI devices one by one
bhangarefda5f7c2017-01-12 23:50:34 -08005962 for pci_device in avilable_pci_devices:
5963 task = self.add_pci_to_vm(host_obj, vm_obj, pci_device)
5964 if task:
sousaedu80135b92021-02-17 15:05:18 +01005965 status = self.wait_for_vcenter_task(
5966 task, vcenter_conect
5967 )
5968
bhangarefda5f7c2017-01-12 23:50:34 -08005969 if status:
sousaedu80135b92021-02-17 15:05:18 +01005970 self.logger.info(
5971 "Added PCI device {} to VM {}".format(
5972 pci_device, str(vm_obj)
5973 )
5974 )
bhangarefda5f7c2017-01-12 23:50:34 -08005975 else:
sousaedu80135b92021-02-17 15:05:18 +01005976 self.logger.error(
5977 "Fail to add PCI device {} to VM {}".format(
5978 pci_device, str(vm_obj)
5979 )
5980 )
5981
bhangarefda5f7c2017-01-12 23:50:34 -08005982 return True, vm_obj, vcenter_conect
5983 else:
sousaedu80135b92021-02-17 15:05:18 +01005984 self.logger.error(
5985 "Currently there is no host with"
5986 " {} number of avaialble PCI devices required for VM {}".format(
5987 no_of_pci_devices, vmname_andid
5988 )
5989 )
5990
tierno72774862020-05-04 11:44:15 +00005991 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05005992 "Currently there is no host with {} "
5993 "number of avaialble PCI devices required for VM {}".format(
sousaedu80135b92021-02-17 15:05:18 +01005994 no_of_pci_devices, vmname_andid
5995 )
5996 )
bhangarefda5f7c2017-01-12 23:50:34 -08005997 else:
sousaedu80135b92021-02-17 15:05:18 +01005998 self.logger.debug(
5999 "No infromation about PCI devices {} ", pci_devices
6000 )
bhangarefda5f7c2017-01-12 23:50:34 -08006001 except vmodl.MethodFault as error:
beierlb22ce2d2019-12-12 12:09:51 -05006002 self.logger.error("Error occurred while adding PCI devices {} ", error)
sousaedu80135b92021-02-17 15:05:18 +01006003
bhangarefda5f7c2017-01-12 23:50:34 -08006004 return None, vm_obj, vcenter_conect
6005
6006 def get_vm_obj(self, content, mob_id):
6007 """
sousaedu80135b92021-02-17 15:05:18 +01006008 Method to get the vsphere VM object associated with a given morf ID
6009 Args:
6010 vapp_uuid - uuid of vApp/VM
6011 content - vCenter content object
6012 mob_id - mob_id of VM
bhangarefda5f7c2017-01-12 23:50:34 -08006013
sousaedu80135b92021-02-17 15:05:18 +01006014 Returns:
6015 VM and host object
bhangarefda5f7c2017-01-12 23:50:34 -08006016 """
6017 vm_obj = None
6018 host_obj = None
sousaedu80135b92021-02-17 15:05:18 +01006019
beierlb22ce2d2019-12-12 12:09:51 -05006020 try:
sousaedu80135b92021-02-17 15:05:18 +01006021 container = content.viewManager.CreateContainerView(
6022 content.rootFolder, [vim.VirtualMachine], True
6023 )
bhangarefda5f7c2017-01-12 23:50:34 -08006024 for vm in container.view:
6025 mobID = vm._GetMoId()
sousaedu80135b92021-02-17 15:05:18 +01006026
bhangarefda5f7c2017-01-12 23:50:34 -08006027 if mobID == mob_id:
6028 vm_obj = vm
6029 host_obj = vm_obj.runtime.host
6030 break
6031 except Exception as exp:
6032 self.logger.error("Error occurred while finding VM object : {}".format(exp))
sousaedu80135b92021-02-17 15:05:18 +01006033
bhangarefda5f7c2017-01-12 23:50:34 -08006034 return host_obj, vm_obj
6035
6036 def get_pci_devices(self, host, need_devices):
6037 """
sousaedu80135b92021-02-17 15:05:18 +01006038 Method to get the details of pci devices on given host
6039 Args:
6040 host - vSphere host object
6041 need_devices - number of pci devices needed on host
bhangarefda5f7c2017-01-12 23:50:34 -08006042
sousaedu80135b92021-02-17 15:05:18 +01006043 Returns:
6044 array of pci devices
bhangarefda5f7c2017-01-12 23:50:34 -08006045 """
6046 all_devices = []
6047 all_device_ids = []
6048 used_devices_ids = []
6049
6050 try:
6051 if host:
6052 pciPassthruInfo = host.config.pciPassthruInfo
6053 pciDevies = host.hardware.pciDevice
6054
6055 for pci_status in pciPassthruInfo:
6056 if pci_status.passthruActive:
6057 for device in pciDevies:
6058 if device.id == pci_status.id:
6059 all_device_ids.append(device.id)
6060 all_devices.append(device)
6061
beierlb22ce2d2019-12-12 12:09:51 -05006062 # check if devices are in use
bhangarefda5f7c2017-01-12 23:50:34 -08006063 avalible_devices = all_devices
6064 for vm in host.vm:
6065 if vm.runtime.powerState == vim.VirtualMachinePowerState.poweredOn:
6066 vm_devices = vm.config.hardware.device
6067 for device in vm_devices:
6068 if type(device) is vim.vm.device.VirtualPCIPassthrough:
6069 if device.backing.id in all_device_ids:
6070 for use_device in avalible_devices:
6071 if use_device.id == device.backing.id:
6072 avalible_devices.remove(use_device)
sousaedu80135b92021-02-17 15:05:18 +01006073
bhangarefda5f7c2017-01-12 23:50:34 -08006074 used_devices_ids.append(device.backing.id)
sousaedu80135b92021-02-17 15:05:18 +01006075 self.logger.debug(
6076 "Device {} from devices {}"
6077 "is in use".format(device.backing.id, device)
6078 )
bhangarefda5f7c2017-01-12 23:50:34 -08006079 if len(avalible_devices) < need_devices:
sousaedu80135b92021-02-17 15:05:18 +01006080 self.logger.debug(
6081 "Host {} don't have {} number of active devices".format(
6082 host, need_devices
6083 )
6084 )
6085 self.logger.debug(
6086 "found only {} devices {}".format(
6087 len(avalible_devices), avalible_devices
6088 )
6089 )
6090
bhangarefda5f7c2017-01-12 23:50:34 -08006091 return None
6092 else:
6093 required_devices = avalible_devices[:need_devices]
sousaedu80135b92021-02-17 15:05:18 +01006094 self.logger.info(
6095 "Found {} PCI devices on host {} but required only {}".format(
6096 len(avalible_devices), host, need_devices
6097 )
6098 )
6099 self.logger.info(
6100 "Retruning {} devices as {}".format(need_devices, required_devices)
6101 )
bhangarefda5f7c2017-01-12 23:50:34 -08006102
sousaedu80135b92021-02-17 15:05:18 +01006103 return required_devices
bhangarefda5f7c2017-01-12 23:50:34 -08006104 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006105 self.logger.error(
6106 "Error {} occurred while finding pci devices on host: {}".format(
6107 exp, host
6108 )
6109 )
bhangarefda5f7c2017-01-12 23:50:34 -08006110
6111 return None
6112
6113 def get_host_and_PCIdevices(self, content, need_devices):
6114 """
sousaedu80135b92021-02-17 15:05:18 +01006115 Method to get the details of pci devices infromation on all hosts
bhangarefda5f7c2017-01-12 23:50:34 -08006116
sousaedu80135b92021-02-17 15:05:18 +01006117 Args:
6118 content - vSphere host object
6119 need_devices - number of pci devices needed on host
bhangarefda5f7c2017-01-12 23:50:34 -08006120
sousaedu80135b92021-02-17 15:05:18 +01006121 Returns:
6122 array of pci devices and host object
bhangarefda5f7c2017-01-12 23:50:34 -08006123 """
6124 host_obj = None
6125 pci_device_objs = None
sousaedu80135b92021-02-17 15:05:18 +01006126
bhangarefda5f7c2017-01-12 23:50:34 -08006127 try:
6128 if content:
sousaedu80135b92021-02-17 15:05:18 +01006129 container = content.viewManager.CreateContainerView(
6130 content.rootFolder, [vim.HostSystem], True
6131 )
bhangarefda5f7c2017-01-12 23:50:34 -08006132 for host in container.view:
6133 devices = self.get_pci_devices(host, need_devices)
sousaedu80135b92021-02-17 15:05:18 +01006134
bhangarefda5f7c2017-01-12 23:50:34 -08006135 if devices:
6136 host_obj = host
6137 pci_device_objs = devices
6138 break
6139 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006140 self.logger.error(
6141 "Error {} occurred while finding pci devices on host: {}".format(
6142 exp, host_obj
6143 )
6144 )
bhangarefda5f7c2017-01-12 23:50:34 -08006145
beierlb22ce2d2019-12-12 12:09:51 -05006146 return host_obj, pci_device_objs
bhangarefda5f7c2017-01-12 23:50:34 -08006147
beierlb22ce2d2019-12-12 12:09:51 -05006148 def relocate_vm(self, dest_host, vm):
bhangarefda5f7c2017-01-12 23:50:34 -08006149 """
sousaedu80135b92021-02-17 15:05:18 +01006150 Method to get the relocate VM to new host
bhangarefda5f7c2017-01-12 23:50:34 -08006151
sousaedu80135b92021-02-17 15:05:18 +01006152 Args:
6153 dest_host - vSphere host object
6154 vm - vSphere VM object
bhangarefda5f7c2017-01-12 23:50:34 -08006155
sousaedu80135b92021-02-17 15:05:18 +01006156 Returns:
6157 task object
bhangarefda5f7c2017-01-12 23:50:34 -08006158 """
6159 task = None
sousaedu80135b92021-02-17 15:05:18 +01006160
bhangarefda5f7c2017-01-12 23:50:34 -08006161 try:
6162 relocate_spec = vim.vm.RelocateSpec(host=dest_host)
6163 task = vm.Relocate(relocate_spec)
sousaedu80135b92021-02-17 15:05:18 +01006164 self.logger.info(
6165 "Migrating {} to destination host {}".format(vm, dest_host)
6166 )
bhangarefda5f7c2017-01-12 23:50:34 -08006167 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006168 self.logger.error(
6169 "Error occurred while relocate VM {} to new host {}: {}".format(
6170 dest_host, vm, exp
6171 )
6172 )
6173
bhangarefda5f7c2017-01-12 23:50:34 -08006174 return task
6175
sousaedu80135b92021-02-17 15:05:18 +01006176 def wait_for_vcenter_task(self, task, actionName="job", hideResult=False):
bhangarefda5f7c2017-01-12 23:50:34 -08006177 """
6178 Waits and provides updates on a vSphere task
6179 """
6180 while task.info.state == vim.TaskInfo.State.running:
6181 time.sleep(2)
6182
6183 if task.info.state == vim.TaskInfo.State.success:
6184 if task.info.result is not None and not hideResult:
sousaedu80135b92021-02-17 15:05:18 +01006185 self.logger.info(
6186 "{} completed successfully, result: {}".format(
6187 actionName, task.info.result
6188 )
beierlb22ce2d2019-12-12 12:09:51 -05006189 )
sousaedu80135b92021-02-17 15:05:18 +01006190 else:
6191 self.logger.info("Task {} completed successfully.".format(actionName))
6192 else:
6193 self.logger.error(
6194 "{} did not complete successfully: {} ".format(
6195 actionName, task.info.error
6196 )
6197 )
bhangarefda5f7c2017-01-12 23:50:34 -08006198
6199 return task.info.result
6200
beierlb22ce2d2019-12-12 12:09:51 -05006201 def add_pci_to_vm(self, host_object, vm_object, host_pci_dev):
bhangarefda5f7c2017-01-12 23:50:34 -08006202 """
sousaedu80135b92021-02-17 15:05:18 +01006203 Method to add pci device in given VM
bhangarefda5f7c2017-01-12 23:50:34 -08006204
sousaedu80135b92021-02-17 15:05:18 +01006205 Args:
6206 host_object - vSphere host object
6207 vm_object - vSphere VM object
6208 host_pci_dev - host_pci_dev must be one of the devices from the
6209 host_object.hardware.pciDevice list
6210 which is configured as a PCI passthrough device
bhangarefda5f7c2017-01-12 23:50:34 -08006211
sousaedu80135b92021-02-17 15:05:18 +01006212 Returns:
6213 task object
bhangarefda5f7c2017-01-12 23:50:34 -08006214 """
6215 task = None
sousaedu80135b92021-02-17 15:05:18 +01006216
bhangarefda5f7c2017-01-12 23:50:34 -08006217 if vm_object and host_object and host_pci_dev:
beierlb22ce2d2019-12-12 12:09:51 -05006218 try:
6219 # Add PCI device to VM
sousaedu80135b92021-02-17 15:05:18 +01006220 pci_passthroughs = vm_object.environmentBrowser.QueryConfigTarget(
6221 host=None
6222 ).pciPassthrough
6223 systemid_by_pciid = {
6224 item.pciDevice.id: item.systemId for item in pci_passthroughs
6225 }
bhangarefda5f7c2017-01-12 23:50:34 -08006226
6227 if host_pci_dev.id not in systemid_by_pciid:
sousaedu80135b92021-02-17 15:05:18 +01006228 self.logger.error(
6229 "Device {} is not a passthrough device ".format(host_pci_dev)
6230 )
bhangarefda5f7c2017-01-12 23:50:34 -08006231 return None
6232
sousaedu80135b92021-02-17 15:05:18 +01006233 deviceId = hex(host_pci_dev.deviceId % 2 ** 16).lstrip("0x")
6234 backing = vim.VirtualPCIPassthroughDeviceBackingInfo(
6235 deviceId=deviceId,
6236 id=host_pci_dev.id,
6237 systemId=systemid_by_pciid[host_pci_dev.id],
6238 vendorId=host_pci_dev.vendorId,
6239 deviceName=host_pci_dev.deviceName,
6240 )
bhangarefda5f7c2017-01-12 23:50:34 -08006241
6242 hba_object = vim.VirtualPCIPassthrough(key=-100, backing=backing)
bhangarefda5f7c2017-01-12 23:50:34 -08006243 new_device_config = vim.VirtualDeviceConfigSpec(device=hba_object)
6244 new_device_config.operation = "add"
6245 vmConfigSpec = vim.vm.ConfigSpec()
6246 vmConfigSpec.deviceChange = [new_device_config]
bhangarefda5f7c2017-01-12 23:50:34 -08006247 task = vm_object.ReconfigVM_Task(spec=vmConfigSpec)
sousaedu80135b92021-02-17 15:05:18 +01006248 self.logger.info(
6249 "Adding PCI device {} into VM {} from host {} ".format(
6250 host_pci_dev, vm_object, host_object
beierlb22ce2d2019-12-12 12:09:51 -05006251 )
sousaedu80135b92021-02-17 15:05:18 +01006252 )
bhangarefda5f7c2017-01-12 23:50:34 -08006253 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006254 self.logger.error(
6255 "Error occurred while adding pci devive {} to VM {}: {}".format(
6256 host_pci_dev, vm_object, exp
6257 )
6258 )
6259
bhangarefda5f7c2017-01-12 23:50:34 -08006260 return task
6261
bhangare06312472017-03-30 05:49:07 -07006262 def get_vm_vcenter_info(self):
bhangarefda5f7c2017-01-12 23:50:34 -08006263 """
kateeb044522017-03-06 23:54:39 -08006264 Method to get details of vCenter and vm
bhangarefda5f7c2017-01-12 23:50:34 -08006265
6266 Args:
6267 vapp_uuid - uuid of vApp or VM
6268
6269 Returns:
6270 Moref Id of VM and deails of vCenter
6271 """
kateeb044522017-03-06 23:54:39 -08006272 vm_vcenter_info = {}
bhangarefda5f7c2017-01-12 23:50:34 -08006273
kateeb044522017-03-06 23:54:39 -08006274 if self.vcenter_ip is not None:
6275 vm_vcenter_info["vm_vcenter_ip"] = self.vcenter_ip
6276 else:
sousaedu80135b92021-02-17 15:05:18 +01006277 raise vimconn.VimConnException(
6278 message="vCenter IP is not provided."
6279 " Please provide vCenter IP while attaching datacenter "
6280 "to tenant in --config"
6281 )
6282
kateeb044522017-03-06 23:54:39 -08006283 if self.vcenter_port is not None:
6284 vm_vcenter_info["vm_vcenter_port"] = self.vcenter_port
6285 else:
sousaedu80135b92021-02-17 15:05:18 +01006286 raise vimconn.VimConnException(
6287 message="vCenter port is not provided."
6288 " Please provide vCenter port while attaching datacenter "
6289 "to tenant in --config"
6290 )
6291
kateeb044522017-03-06 23:54:39 -08006292 if self.vcenter_user is not None:
6293 vm_vcenter_info["vm_vcenter_user"] = self.vcenter_user
6294 else:
sousaedu80135b92021-02-17 15:05:18 +01006295 raise vimconn.VimConnException(
6296 message="vCenter user is not provided."
6297 " Please provide vCenter user while attaching datacenter "
6298 "to tenant in --config"
6299 )
bhangarefda5f7c2017-01-12 23:50:34 -08006300
kateeb044522017-03-06 23:54:39 -08006301 if self.vcenter_password is not None:
6302 vm_vcenter_info["vm_vcenter_password"] = self.vcenter_password
6303 else:
sousaedu80135b92021-02-17 15:05:18 +01006304 raise vimconn.VimConnException(
6305 message="vCenter user password is not provided."
6306 " Please provide vCenter user password while attaching datacenter "
6307 "to tenant in --config"
6308 )
bhangarefda5f7c2017-01-12 23:50:34 -08006309
bhangare06312472017-03-30 05:49:07 -07006310 return vm_vcenter_info
bhangarefda5f7c2017-01-12 23:50:34 -08006311
bhangarefda5f7c2017-01-12 23:50:34 -08006312 def get_vm_pci_details(self, vmuuid):
6313 """
sousaedu80135b92021-02-17 15:05:18 +01006314 Method to get VM PCI device details from vCenter
bhangarefda5f7c2017-01-12 23:50:34 -08006315
sousaedu80135b92021-02-17 15:05:18 +01006316 Args:
6317 vm_obj - vSphere VM object
bhangarefda5f7c2017-01-12 23:50:34 -08006318
sousaedu80135b92021-02-17 15:05:18 +01006319 Returns:
6320 dict of PCI devives attached to VM
bhangarefda5f7c2017-01-12 23:50:34 -08006321
6322 """
6323 vm_pci_devices_info = {}
sousaedu80135b92021-02-17 15:05:18 +01006324
bhangarefda5f7c2017-01-12 23:50:34 -08006325 try:
beierlb22ce2d2019-12-12 12:09:51 -05006326 _, content = self.get_vcenter_content()
bhangare06312472017-03-30 05:49:07 -07006327 vm_moref_id = self.get_vm_moref_id(vmuuid)
6328 if vm_moref_id:
beierlb22ce2d2019-12-12 12:09:51 -05006329 # Get VM and its host
kateeb044522017-03-06 23:54:39 -08006330 if content:
bhangare06312472017-03-30 05:49:07 -07006331 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
kateeb044522017-03-06 23:54:39 -08006332 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05006333 vm_pci_devices_info["host_name"] = host_obj.name
sousaedu80135b92021-02-17 15:05:18 +01006334 vm_pci_devices_info["host_ip"] = host_obj.config.network.vnic[
6335 0
6336 ].spec.ip.ipAddress
6337
kateeb044522017-03-06 23:54:39 -08006338 for device in vm_obj.config.hardware.device:
6339 if type(device) == vim.vm.device.VirtualPCIPassthrough:
sousaedu80135b92021-02-17 15:05:18 +01006340 device_details = {
6341 "devide_id": device.backing.id,
6342 "pciSlotNumber": device.slotInfo.pciSlotNumber,
6343 }
6344 vm_pci_devices_info[
6345 device.deviceInfo.label
6346 ] = device_details
kateeb044522017-03-06 23:54:39 -08006347 else:
sousaedu80135b92021-02-17 15:05:18 +01006348 self.logger.error(
6349 "Can not connect to vCenter while getting "
6350 "PCI devices infromationn"
6351 )
6352
kateeb044522017-03-06 23:54:39 -08006353 return vm_pci_devices_info
bhangarefda5f7c2017-01-12 23:50:34 -08006354 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006355 self.logger.error(
6356 "Error occurred while getting VM information" " for VM : {}".format(exp)
6357 )
6358
tierno72774862020-05-04 11:44:15 +00006359 raise vimconn.VimConnException(message=exp)
bhangare0e571a92017-01-12 04:02:23 -08006360
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006361 def reserve_memory_for_all_vms(self, vapp, memory_mb):
6362 """
sousaedu80135b92021-02-17 15:05:18 +01006363 Method to reserve memory for all VMs
6364 Args :
6365 vapp - VApp
6366 memory_mb - Memory in MB
6367 Returns:
6368 None
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006369 """
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006370 self.logger.info("Reserve memory for all VMs")
sousaedu80135b92021-02-17 15:05:18 +01006371
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006372 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006373 vm_id = vms.get("id").split(":")[-1]
6374 url_rest_call = "{}/api/vApp/vm-{}/virtualHardwareSection/memory".format(
6375 self.url, vm_id
6376 )
6377 headers = {
6378 "Accept": "application/*+xml;version=" + API_VERSION,
6379 "x-vcloud-authorization": self.client._session.headers[
6380 "x-vcloud-authorization"
6381 ],
6382 }
6383 headers["Content-Type"] = "application/vnd.vmware.vcloud.rasdItem+xml"
6384 response = self.perform_request(
6385 req_type="GET", url=url_rest_call, headers=headers
6386 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006387
6388 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006389 response = self.retry_rest("GET", url_rest_call)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006390
6391 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006392 self.logger.error(
6393 "REST call {} failed reason : {}"
6394 "status code : {}".format(
6395 url_rest_call, response.text, response.status_code
6396 )
6397 )
6398 raise vimconn.VimConnException(
6399 "reserve_memory_for_all_vms : Failed to get " "memory"
6400 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006401
sousaedu80135b92021-02-17 15:05:18 +01006402 bytexml = bytes(bytearray(response.text, encoding="utf-8"))
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006403 contentelem = lxmlElementTree.XML(bytexml)
sousaedu80135b92021-02-17 15:05:18 +01006404 namespaces = {
6405 prefix: uri for prefix, uri in contentelem.nsmap.items() if prefix
6406 }
beierlb22ce2d2019-12-12 12:09:51 -05006407 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006408
6409 # Find the reservation element in the response
6410 memelem_list = contentelem.findall(".//rasd:Reservation", namespaces)
6411 for memelem in memelem_list:
6412 memelem.text = str(memory_mb)
6413
6414 newdata = lxmlElementTree.tostring(contentelem, pretty_print=True)
6415
sousaedu80135b92021-02-17 15:05:18 +01006416 response = self.perform_request(
6417 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6418 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006419
6420 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006421 add_headers = {"Content-Type": headers["Content-Type"]}
6422 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006423
6424 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006425 self.logger.error(
6426 "REST call {} failed reason : {}"
6427 "status code : {} ".format(
6428 url_rest_call, response.text, response.status_code
6429 )
6430 )
6431 raise vimconn.VimConnException(
6432 "reserve_memory_for_all_vms : Failed to update "
6433 "virtual hardware memory section"
6434 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006435 else:
beierl26fec002019-12-06 17:06:40 -05006436 mem_task = self.get_task_from_response(response.text)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006437 result = self.client.get_task_monitor().wait_for_success(task=mem_task)
sousaedu80135b92021-02-17 15:05:18 +01006438
6439 if result.get("status") == "success":
6440 self.logger.info(
6441 "reserve_memory_for_all_vms(): VM {} succeeded ".format(vm_id)
6442 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006443 else:
sousaedu80135b92021-02-17 15:05:18 +01006444 self.logger.error(
6445 "reserve_memory_for_all_vms(): VM {} failed ".format(vm_id)
6446 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006447
6448 def connect_vapp_to_org_vdc_network(self, vapp_id, net_name):
6449 """
sousaedu80135b92021-02-17 15:05:18 +01006450 Configure VApp network config with org vdc network
6451 Args :
6452 vapp - VApp
6453 Returns:
6454 None
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006455 """
6456
sousaedu80135b92021-02-17 15:05:18 +01006457 self.logger.info(
6458 "Connecting vapp {} to org vdc network {}".format(vapp_id, net_name)
6459 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006460
sousaedu80135b92021-02-17 15:05:18 +01006461 url_rest_call = "{}/api/vApp/vapp-{}/networkConfigSection/".format(
6462 self.url, vapp_id
6463 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006464
sousaedu80135b92021-02-17 15:05:18 +01006465 headers = {
6466 "Accept": "application/*+xml;version=" + API_VERSION,
6467 "x-vcloud-authorization": self.client._session.headers[
6468 "x-vcloud-authorization"
6469 ],
6470 }
6471 response = self.perform_request(
6472 req_type="GET", url=url_rest_call, headers=headers
6473 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006474
6475 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006476 response = self.retry_rest("GET", url_rest_call)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006477
6478 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006479 self.logger.error(
6480 "REST call {} failed reason : {}"
6481 "status code : {}".format(
6482 url_rest_call, response.text, response.status_code
6483 )
6484 )
6485 raise vimconn.VimConnException(
6486 "connect_vapp_to_org_vdc_network : Failed to get "
6487 "network config section"
6488 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006489
beierl26fec002019-12-06 17:06:40 -05006490 data = response.text
sousaedu80135b92021-02-17 15:05:18 +01006491 headers[
6492 "Content-Type"
6493 ] = "application/vnd.vmware.vcloud.networkConfigSection+xml"
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006494 net_id = self.get_network_id_by_name(net_name)
6495 if not net_id:
sousaedu80135b92021-02-17 15:05:18 +01006496 raise vimconn.VimConnException(
6497 "connect_vapp_to_org_vdc_network : Failed to find " "existing network"
6498 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006499
sousaedu80135b92021-02-17 15:05:18 +01006500 bytexml = bytes(bytearray(data, encoding="utf-8"))
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006501 newelem = lxmlElementTree.XML(bytexml)
tierno7d782ef2019-10-04 12:56:31 +00006502 namespaces = {prefix: uri for prefix, uri in newelem.nsmap.items() if prefix}
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006503 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
6504 nwcfglist = newelem.findall(".//xmlns:NetworkConfig", namespaces)
6505
Ravi Chamarty259aebc2019-06-05 17:06:39 +00006506 # VCD 9.7 returns an incorrect parentnetwork element. Fix it before PUT operation
6507 parentnetworklist = newelem.findall(".//xmlns:ParentNetwork", namespaces)
6508 if parentnetworklist:
6509 for pn in parentnetworklist:
6510 if "href" not in pn.keys():
6511 id_val = pn.get("id")
6512 href_val = "{}/api/network/{}".format(self.url, id_val)
6513 pn.set("href", href_val)
6514
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006515 newstr = """<NetworkConfig networkName="{}">
6516 <Configuration>
6517 <ParentNetwork href="{}/api/network/{}"/>
6518 <FenceMode>bridged</FenceMode>
6519 </Configuration>
6520 </NetworkConfig>
sousaedu80135b92021-02-17 15:05:18 +01006521 """.format(
6522 net_name, self.url, net_id
6523 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006524 newcfgelem = lxmlElementTree.fromstring(newstr)
6525 if nwcfglist:
6526 nwcfglist[0].addnext(newcfgelem)
6527
6528 newdata = lxmlElementTree.tostring(newelem, pretty_print=True)
6529
sousaedu80135b92021-02-17 15:05:18 +01006530 response = self.perform_request(
6531 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6532 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006533
6534 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006535 add_headers = {"Content-Type": headers["Content-Type"]}
6536 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006537
6538 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006539 self.logger.error(
6540 "REST call {} failed reason : {}"
6541 "status code : {} ".format(
6542 url_rest_call, response.text, response.status_code
6543 )
6544 )
6545 raise vimconn.VimConnException(
6546 "connect_vapp_to_org_vdc_network : Failed to update "
6547 "network config section"
6548 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006549 else:
beierl26fec002019-12-06 17:06:40 -05006550 vapp_task = self.get_task_from_response(response.text)
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006551 result = self.client.get_task_monitor().wait_for_success(task=vapp_task)
sousaedu80135b92021-02-17 15:05:18 +01006552 if result.get("status") == "success":
6553 self.logger.info(
6554 "connect_vapp_to_org_vdc_network(): Vapp {} connected to "
6555 "network {}".format(vapp_id, net_name)
6556 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006557 else:
sousaedu80135b92021-02-17 15:05:18 +01006558 self.logger.error(
6559 "connect_vapp_to_org_vdc_network(): Vapp {} failed to "
6560 "connect to network {}".format(vapp_id, net_name)
6561 )
Ravi Chamartyb0ab2c02018-10-26 01:40:50 +00006562
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006563 def remove_primary_network_adapter_from_all_vms(self, vapp):
6564 """
sousaedu80135b92021-02-17 15:05:18 +01006565 Method to remove network adapter type to vm
6566 Args :
6567 vapp - VApp
6568 Returns:
6569 None
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006570 """
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006571 self.logger.info("Removing network adapter from all VMs")
sousaedu80135b92021-02-17 15:05:18 +01006572
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006573 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006574 vm_id = vms.get("id").split(":")[-1]
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006575
sousaedu80135b92021-02-17 15:05:18 +01006576 url_rest_call = "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6577 self.url, vm_id
6578 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006579
sousaedu80135b92021-02-17 15:05:18 +01006580 headers = {
6581 "Accept": "application/*+xml;version=" + API_VERSION,
6582 "x-vcloud-authorization": self.client._session.headers[
6583 "x-vcloud-authorization"
6584 ],
6585 }
6586 response = self.perform_request(
6587 req_type="GET", url=url_rest_call, headers=headers
6588 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006589
6590 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006591 response = self.retry_rest("GET", url_rest_call)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006592
6593 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006594 self.logger.error(
6595 "REST call {} failed reason : {}"
6596 "status code : {}".format(
6597 url_rest_call, response.text, response.status_code
6598 )
6599 )
6600 raise vimconn.VimConnException(
6601 "remove_primary_network_adapter : Failed to get "
6602 "network connection section"
6603 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006604
beierl26fec002019-12-06 17:06:40 -05006605 data = response.text
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006606 data = data.split('<Link rel="edit"')[0]
6607
sousaedu80135b92021-02-17 15:05:18 +01006608 headers[
6609 "Content-Type"
6610 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006611
6612 newdata = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
6613 <NetworkConnectionSection xmlns="http://www.vmware.com/vcloud/v1.5"
6614 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
6615 xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
6616 xmlns:common="http://schemas.dmtf.org/wbem/wscim/1/common"
6617 xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
6618 xmlns:vmw="http://www.vmware.com/schema/ovf"
6619 xmlns:ovfenv="http://schemas.dmtf.org/ovf/environment/1"
6620 xmlns:vmext="http://www.vmware.com/vcloud/extension/v1.5"
6621 xmlns:ns9="http://www.vmware.com/vcloud/versions"
beierlb22ce2d2019-12-12 12:09:51 -05006622 href="{url}" type="application/vnd.vmware.vcloud.networkConnectionSection+xml"
6623 ovf:required="false">
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006624 <ovf:Info>Specifies the available VM network connections</ovf:Info>
6625 <PrimaryNetworkConnectionIndex>0</PrimaryNetworkConnectionIndex>
beierlb22ce2d2019-12-12 12:09:51 -05006626 <Link rel="edit" href="{url}"
6627 type="application/vnd.vmware.vcloud.networkConnectionSection+xml"/>
sousaedu80135b92021-02-17 15:05:18 +01006628 </NetworkConnectionSection>""".format(
6629 url=url_rest_call
6630 )
6631 response = self.perform_request(
6632 req_type="PUT", url=url_rest_call, headers=headers, data=newdata
6633 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006634
6635 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006636 add_headers = {"Content-Type": headers["Content-Type"]}
6637 response = self.retry_rest("PUT", url_rest_call, add_headers, newdata)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006638
6639 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006640 self.logger.error(
6641 "REST call {} failed reason : {}"
6642 "status code : {} ".format(
6643 url_rest_call, response.text, response.status_code
6644 )
6645 )
6646 raise vimconn.VimConnException(
6647 "remove_primary_network_adapter : Failed to update "
6648 "network connection section"
6649 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006650 else:
beierl26fec002019-12-06 17:06:40 -05006651 nic_task = self.get_task_from_response(response.text)
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006652 result = self.client.get_task_monitor().wait_for_success(task=nic_task)
sousaedu80135b92021-02-17 15:05:18 +01006653 if result.get("status") == "success":
6654 self.logger.info(
6655 "remove_primary_network_adapter(): VM {} conneced to "
6656 "default NIC type".format(vm_id)
6657 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006658 else:
sousaedu80135b92021-02-17 15:05:18 +01006659 self.logger.error(
6660 "remove_primary_network_adapter(): VM {} failed to "
6661 "connect NIC type".format(vm_id)
6662 )
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006663
sousaedu80135b92021-02-17 15:05:18 +01006664 def add_network_adapter_to_vms(
6665 self, vapp, network_name, primary_nic_index, nicIndex, net, nic_type=None
6666 ):
kasar3ac5dc42017-03-15 06:28:22 -07006667 """
sousaedu80135b92021-02-17 15:05:18 +01006668 Method to add network adapter type to vm
6669 Args :
6670 network_name - name of network
6671 primary_nic_index - int value for primary nic index
6672 nicIndex - int value for nic index
6673 nic_type - specify model name to which add to vm
6674 Returns:
6675 None
kasar3ac5dc42017-03-15 06:28:22 -07006676 """
kasar3ac5dc42017-03-15 06:28:22 -07006677
sousaedu80135b92021-02-17 15:05:18 +01006678 self.logger.info(
6679 "Add network adapter to VM: network_name {} nicIndex {} nic_type {}".format(
6680 network_name, nicIndex, nic_type
6681 )
6682 )
kasar4cb6e902017-03-18 00:17:27 -07006683 try:
kasard2963622017-03-31 05:53:17 -07006684 ip_address = None
kasardc1f02e2017-03-25 07:20:30 -07006685 floating_ip = False
kasarc5bf2932018-03-09 04:15:22 -08006686 mac_address = None
sousaedu80135b92021-02-17 15:05:18 +01006687 if "floating_ip" in net:
6688 floating_ip = net["floating_ip"]
kasard2963622017-03-31 05:53:17 -07006689
6690 # Stub for ip_address feature
sousaedu80135b92021-02-17 15:05:18 +01006691 if "ip_address" in net:
6692 ip_address = net["ip_address"]
kasard2963622017-03-31 05:53:17 -07006693
sousaedu80135b92021-02-17 15:05:18 +01006694 if "mac_address" in net:
6695 mac_address = net["mac_address"]
kasarc5bf2932018-03-09 04:15:22 -08006696
kasard2963622017-03-31 05:53:17 -07006697 if floating_ip:
6698 allocation_mode = "POOL"
6699 elif ip_address:
6700 allocation_mode = "MANUAL"
6701 else:
6702 allocation_mode = "DHCP"
kasardc1f02e2017-03-25 07:20:30 -07006703
kasar3ac5dc42017-03-15 06:28:22 -07006704 if not nic_type:
kasarc5bf2932018-03-09 04:15:22 -08006705 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006706 vm_id = vms.get("id").split(":")[-1]
kasar3ac5dc42017-03-15 06:28:22 -07006707
sousaedu80135b92021-02-17 15:05:18 +01006708 url_rest_call = (
6709 "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6710 self.url, vm_id
6711 )
6712 )
kasar3ac5dc42017-03-15 06:28:22 -07006713
sousaedu80135b92021-02-17 15:05:18 +01006714 headers = {
6715 "Accept": "application/*+xml;version=" + API_VERSION,
6716 "x-vcloud-authorization": self.client._session.headers[
6717 "x-vcloud-authorization"
6718 ],
6719 }
6720 response = self.perform_request(
6721 req_type="GET", url=url_rest_call, headers=headers
6722 )
bhangare1a0b97c2017-06-21 02:20:15 -07006723
6724 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006725 response = self.retry_rest("GET", url_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07006726
kasar3ac5dc42017-03-15 06:28:22 -07006727 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006728 self.logger.error(
6729 "REST call {} failed reason : {}"
6730 "status code : {}".format(
6731 url_rest_call, response.text, response.status_code
6732 )
6733 )
6734 raise vimconn.VimConnException(
6735 "add_network_adapter_to_vms : Failed to get "
6736 "network connection section"
6737 )
kasar3ac5dc42017-03-15 06:28:22 -07006738
beierl26fec002019-12-06 17:06:40 -05006739 data = response.text
kasarc5bf2932018-03-09 04:15:22 -08006740 data = data.split('<Link rel="edit"')[0]
sousaedu80135b92021-02-17 15:05:18 +01006741 if "<PrimaryNetworkConnectionIndex>" not in data:
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006742 self.logger.debug("add_network_adapter PrimaryNIC not in data")
kasar3ac5dc42017-03-15 06:28:22 -07006743 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
6744 <NetworkConnection network="{}">
6745 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6746 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006747 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
sousaedu80135b92021-02-17 15:05:18 +01006748 </NetworkConnection>""".format(
6749 primary_nic_index, network_name, nicIndex, allocation_mode
6750 )
6751
kasard2963622017-03-31 05:53:17 -07006752 # Stub for ip_address feature
6753 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006754 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6755 item = item.replace(
6756 "</NetworkConnectionIndex>\n",
6757 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6758 )
kasardc1f02e2017-03-25 07:20:30 -07006759
kasarc5bf2932018-03-09 04:15:22 -08006760 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006761 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6762 item = item.replace(
6763 "</IsConnected>\n",
6764 "</IsConnected>\n{}\n".format(mac_tag),
6765 )
kasarc5bf2932018-03-09 04:15:22 -08006766
sousaedu80135b92021-02-17 15:05:18 +01006767 data = data.replace(
6768 "</ovf:Info>\n",
6769 "</ovf:Info>\n{}\n</NetworkConnectionSection>".format(item),
6770 )
kasar3ac5dc42017-03-15 06:28:22 -07006771 else:
Ravi Chamarty5b2d5c12018-10-22 23:59:10 +00006772 self.logger.debug("add_network_adapter PrimaryNIC in data")
kasar3ac5dc42017-03-15 06:28:22 -07006773 new_item = """<NetworkConnection network="{}">
6774 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6775 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006776 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
sousaedu80135b92021-02-17 15:05:18 +01006777 </NetworkConnection>""".format(
6778 network_name, nicIndex, allocation_mode
6779 )
6780
kasard2963622017-03-31 05:53:17 -07006781 # Stub for ip_address feature
6782 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006783 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6784 new_item = new_item.replace(
6785 "</NetworkConnectionIndex>\n",
6786 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6787 )
kasardc1f02e2017-03-25 07:20:30 -07006788
kasarc5bf2932018-03-09 04:15:22 -08006789 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006790 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6791 new_item = new_item.replace(
6792 "</IsConnected>\n",
6793 "</IsConnected>\n{}\n".format(mac_tag),
6794 )
kasar3ac5dc42017-03-15 06:28:22 -07006795
sousaedu80135b92021-02-17 15:05:18 +01006796 data = data + new_item + "</NetworkConnectionSection>"
kasarc5bf2932018-03-09 04:15:22 -08006797
sousaedu80135b92021-02-17 15:05:18 +01006798 headers[
6799 "Content-Type"
6800 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08006801
sousaedu80135b92021-02-17 15:05:18 +01006802 response = self.perform_request(
6803 req_type="PUT", url=url_rest_call, headers=headers, data=data
6804 )
bhangare1a0b97c2017-06-21 02:20:15 -07006805
6806 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006807 add_headers = {"Content-Type": headers["Content-Type"]}
6808 response = self.retry_rest(
6809 "PUT", url_rest_call, add_headers, data
6810 )
bhangare1a0b97c2017-06-21 02:20:15 -07006811
kasar3ac5dc42017-03-15 06:28:22 -07006812 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006813 self.logger.error(
6814 "REST call {} failed reason : {}"
6815 "status code : {} ".format(
6816 url_rest_call, response.text, response.status_code
6817 )
6818 )
6819 raise vimconn.VimConnException(
6820 "add_network_adapter_to_vms : Failed to update "
6821 "network connection section"
6822 )
kasar3ac5dc42017-03-15 06:28:22 -07006823 else:
beierl26fec002019-12-06 17:06:40 -05006824 nic_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01006825 result = self.client.get_task_monitor().wait_for_success(
6826 task=nic_task
6827 )
6828
6829 if result.get("status") == "success":
6830 self.logger.info(
6831 "add_network_adapter_to_vms(): VM {} conneced to "
6832 "default NIC type".format(vm_id)
6833 )
kasar3ac5dc42017-03-15 06:28:22 -07006834 else:
sousaedu80135b92021-02-17 15:05:18 +01006835 self.logger.error(
6836 "add_network_adapter_to_vms(): VM {} failed to "
6837 "connect NIC type".format(vm_id)
6838 )
kasar3ac5dc42017-03-15 06:28:22 -07006839 else:
kasarc5bf2932018-03-09 04:15:22 -08006840 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01006841 vm_id = vms.get("id").split(":")[-1]
kasar3ac5dc42017-03-15 06:28:22 -07006842
sousaedu80135b92021-02-17 15:05:18 +01006843 url_rest_call = (
6844 "{}/api/vApp/vm-{}/networkConnectionSection/".format(
6845 self.url, vm_id
6846 )
6847 )
kasarc5bf2932018-03-09 04:15:22 -08006848
sousaedu80135b92021-02-17 15:05:18 +01006849 headers = {
6850 "Accept": "application/*+xml;version=" + API_VERSION,
6851 "x-vcloud-authorization": self.client._session.headers[
6852 "x-vcloud-authorization"
6853 ],
6854 }
6855 response = self.perform_request(
6856 req_type="GET", url=url_rest_call, headers=headers
6857 )
bhangare1a0b97c2017-06-21 02:20:15 -07006858
6859 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006860 response = self.retry_rest("GET", url_rest_call)
bhangare1a0b97c2017-06-21 02:20:15 -07006861
kasar3ac5dc42017-03-15 06:28:22 -07006862 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01006863 self.logger.error(
6864 "REST call {} failed reason : {}"
6865 "status code : {}".format(
6866 url_rest_call, response.text, response.status_code
6867 )
6868 )
6869 raise vimconn.VimConnException(
6870 "add_network_adapter_to_vms : Failed to get "
6871 "network connection section"
6872 )
beierl26fec002019-12-06 17:06:40 -05006873 data = response.text
kasarc5bf2932018-03-09 04:15:22 -08006874 data = data.split('<Link rel="edit"')[0]
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00006875 vcd_netadapter_type = nic_type
sousaedu80135b92021-02-17 15:05:18 +01006876
6877 if nic_type in ["SR-IOV", "VF"]:
Ravi Chamartye21c9cc2018-10-24 02:14:53 +00006878 vcd_netadapter_type = "SRIOVETHERNETCARD"
6879
sousaedu80135b92021-02-17 15:05:18 +01006880 if "<PrimaryNetworkConnectionIndex>" not in data:
6881 self.logger.debug(
6882 "add_network_adapter PrimaryNIC not in data nic_type {}".format(
6883 nic_type
6884 )
6885 )
kasar3ac5dc42017-03-15 06:28:22 -07006886 item = """<PrimaryNetworkConnectionIndex>{}</PrimaryNetworkConnectionIndex>
6887 <NetworkConnection network="{}">
6888 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6889 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006890 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07006891 <NetworkAdapterType>{}</NetworkAdapterType>
sousaedu80135b92021-02-17 15:05:18 +01006892 </NetworkConnection>""".format(
6893 primary_nic_index,
6894 network_name,
6895 nicIndex,
6896 allocation_mode,
6897 vcd_netadapter_type,
6898 )
6899
kasard2963622017-03-31 05:53:17 -07006900 # Stub for ip_address feature
6901 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006902 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6903 item = item.replace(
6904 "</NetworkConnectionIndex>\n",
6905 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6906 )
kasardc1f02e2017-03-25 07:20:30 -07006907
kasarc5bf2932018-03-09 04:15:22 -08006908 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006909 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6910 item = item.replace(
6911 "</IsConnected>\n",
6912 "</IsConnected>\n{}\n".format(mac_tag),
6913 )
kasarc5bf2932018-03-09 04:15:22 -08006914
sousaedu80135b92021-02-17 15:05:18 +01006915 data = data.replace(
6916 "</ovf:Info>\n",
6917 "</ovf:Info>\n{}\n</NetworkConnectionSection>".format(item),
6918 )
kasar3ac5dc42017-03-15 06:28:22 -07006919 else:
sousaedu80135b92021-02-17 15:05:18 +01006920 self.logger.debug(
6921 "add_network_adapter PrimaryNIC in data nic_type {}".format(
6922 nic_type
6923 )
6924 )
kasar3ac5dc42017-03-15 06:28:22 -07006925 new_item = """<NetworkConnection network="{}">
6926 <NetworkConnectionIndex>{}</NetworkConnectionIndex>
6927 <IsConnected>true</IsConnected>
kasardc1f02e2017-03-25 07:20:30 -07006928 <IpAddressAllocationMode>{}</IpAddressAllocationMode>
kasar3ac5dc42017-03-15 06:28:22 -07006929 <NetworkAdapterType>{}</NetworkAdapterType>
sousaedu80135b92021-02-17 15:05:18 +01006930 </NetworkConnection>""".format(
6931 network_name, nicIndex, allocation_mode, vcd_netadapter_type
6932 )
6933
kasard2963622017-03-31 05:53:17 -07006934 # Stub for ip_address feature
6935 if ip_address:
sousaedu80135b92021-02-17 15:05:18 +01006936 ip_tag = "<IpAddress>{}</IpAddress>".format(ip_address)
6937 new_item = new_item.replace(
6938 "</NetworkConnectionIndex>\n",
6939 "</NetworkConnectionIndex>\n{}\n".format(ip_tag),
6940 )
kasardc1f02e2017-03-25 07:20:30 -07006941
kasarc5bf2932018-03-09 04:15:22 -08006942 if mac_address:
sousaedu80135b92021-02-17 15:05:18 +01006943 mac_tag = "<MACAddress>{}</MACAddress>".format(mac_address)
6944 new_item = new_item.replace(
6945 "</IsConnected>\n",
6946 "</IsConnected>\n{}\n".format(mac_tag),
6947 )
kasar3ac5dc42017-03-15 06:28:22 -07006948
sousaedu80135b92021-02-17 15:05:18 +01006949 data = data + new_item + "</NetworkConnectionSection>"
kasarc5bf2932018-03-09 04:15:22 -08006950
sousaedu80135b92021-02-17 15:05:18 +01006951 headers[
6952 "Content-Type"
6953 ] = "application/vnd.vmware.vcloud.networkConnectionSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08006954
sousaedu80135b92021-02-17 15:05:18 +01006955 response = self.perform_request(
6956 req_type="PUT", url=url_rest_call, headers=headers, data=data
6957 )
bhangare1a0b97c2017-06-21 02:20:15 -07006958
6959 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01006960 add_headers = {"Content-Type": headers["Content-Type"]}
6961 response = self.retry_rest(
6962 "PUT", url_rest_call, add_headers, data
6963 )
kasar3ac5dc42017-03-15 06:28:22 -07006964
6965 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01006966 self.logger.error(
6967 "REST call {} failed reason : {}"
6968 "status code : {}".format(
6969 url_rest_call, response.text, response.status_code
6970 )
6971 )
6972 raise vimconn.VimConnException(
6973 "add_network_adapter_to_vms : Failed to update "
6974 "network connection section"
6975 )
kasar3ac5dc42017-03-15 06:28:22 -07006976 else:
beierl26fec002019-12-06 17:06:40 -05006977 nic_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01006978 result = self.client.get_task_monitor().wait_for_success(
6979 task=nic_task
6980 )
6981
6982 if result.get("status") == "success":
6983 self.logger.info(
6984 "add_network_adapter_to_vms(): VM {} "
6985 "conneced to NIC type {}".format(vm_id, nic_type)
6986 )
kasar3ac5dc42017-03-15 06:28:22 -07006987 else:
sousaedu80135b92021-02-17 15:05:18 +01006988 self.logger.error(
6989 "add_network_adapter_to_vms(): VM {} "
6990 "failed to connect NIC type {}".format(vm_id, nic_type)
6991 )
kasar3ac5dc42017-03-15 06:28:22 -07006992 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01006993 self.logger.error(
6994 "add_network_adapter_to_vms() : exception occurred "
6995 "while adding Network adapter"
6996 )
6997
tierno72774862020-05-04 11:44:15 +00006998 raise vimconn.VimConnException(message=exp)
kasarde691232017-03-25 03:37:31 -07006999
kasarde691232017-03-25 03:37:31 -07007000 def set_numa_affinity(self, vmuuid, paired_threads_id):
7001 """
sousaedu80135b92021-02-17 15:05:18 +01007002 Method to assign numa affinity in vm configuration parammeters
7003 Args :
7004 vmuuid - vm uuid
7005 paired_threads_id - one or more virtual processor
7006 numbers
7007 Returns:
7008 return if True
kasarde691232017-03-25 03:37:31 -07007009 """
7010 try:
kasar204e39e2018-01-25 00:57:02 -08007011 vcenter_conect, content = self.get_vcenter_content()
7012 vm_moref_id = self.get_vm_moref_id(vmuuid)
beierlb22ce2d2019-12-12 12:09:51 -05007013 _, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007014
kasar204e39e2018-01-25 00:57:02 -08007015 if vm_obj:
7016 config_spec = vim.vm.ConfigSpec()
7017 config_spec.extraConfig = []
7018 opt = vim.option.OptionValue()
sousaedu80135b92021-02-17 15:05:18 +01007019 opt.key = "numa.nodeAffinity"
kasar204e39e2018-01-25 00:57:02 -08007020 opt.value = str(paired_threads_id)
7021 config_spec.extraConfig.append(opt)
7022 task = vm_obj.ReconfigVM_Task(config_spec)
sousaedu80135b92021-02-17 15:05:18 +01007023
kasar204e39e2018-01-25 00:57:02 -08007024 if task:
beierlb22ce2d2019-12-12 12:09:51 -05007025 self.wait_for_vcenter_task(task, vcenter_conect)
kasar204e39e2018-01-25 00:57:02 -08007026 extra_config = vm_obj.config.extraConfig
7027 flag = False
sousaedu80135b92021-02-17 15:05:18 +01007028
kasar204e39e2018-01-25 00:57:02 -08007029 for opts in extra_config:
sousaedu80135b92021-02-17 15:05:18 +01007030 if "numa.nodeAffinity" in opts.key:
kasar204e39e2018-01-25 00:57:02 -08007031 flag = True
sousaedu80135b92021-02-17 15:05:18 +01007032 self.logger.info(
7033 "set_numa_affinity: Sucessfully assign numa affinity "
7034 "value {} for vm {}".format(opt.value, vm_obj)
7035 )
7036
kasar204e39e2018-01-25 00:57:02 -08007037 if flag:
7038 return
7039 else:
7040 self.logger.error("set_numa_affinity: Failed to assign numa affinity")
kasarde691232017-03-25 03:37:31 -07007041 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007042 self.logger.error(
7043 "set_numa_affinity : exception occurred while setting numa affinity "
7044 "for VM {} : {}".format(vm_obj, vm_moref_id)
7045 )
7046
7047 raise vimconn.VimConnException(
7048 "set_numa_affinity : Error {} failed to assign numa "
7049 "affinity".format(exp)
7050 )
kasardc1f02e2017-03-25 07:20:30 -07007051
7052 def cloud_init(self, vapp, cloud_config):
7053 """
7054 Method to inject ssh-key
7055 vapp - vapp object
7056 cloud_config a dictionary with:
7057 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
7058 'users': (optional) list of users to be inserted, each item is a dict with:
7059 'name': (mandatory) user name,
7060 'key-pairs': (optional) list of strings with the public key to be inserted to the user
tierno40e1bce2017-08-09 09:12:04 +02007061 'user-data': (optional) can be a string with the text script to be passed directly to cloud-init,
7062 or a list of strings, each one contains a script to be passed, usually with a MIMEmultipart file
kasardc1f02e2017-03-25 07:20:30 -07007063 'config-files': (optional). List of files to be transferred. Each item is a dict with:
7064 'dest': (mandatory) string with the destination absolute path
7065 'encoding': (optional, by default text). Can be one of:
7066 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
7067 'content' (mandatory): string with the content of the file
7068 'permissions': (optional) string with file permissions, typically octal notation '0644'
7069 'owner': (optional) file owner, string with the format 'owner:group'
7070 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk
7071 """
kasardc1f02e2017-03-25 07:20:30 -07007072 try:
kasar2aa50742017-08-08 02:11:22 -07007073 if not isinstance(cloud_config, dict):
sousaedu80135b92021-02-17 15:05:18 +01007074 raise Exception(
7075 "cloud_init : parameter cloud_config is not a dictionary"
7076 )
kasar2aa50742017-08-08 02:11:22 -07007077 else:
kasardc1f02e2017-03-25 07:20:30 -07007078 key_pairs = []
7079 userdata = []
sousaedu80135b92021-02-17 15:05:18 +01007080
kasardc1f02e2017-03-25 07:20:30 -07007081 if "key-pairs" in cloud_config:
7082 key_pairs = cloud_config["key-pairs"]
7083
7084 if "users" in cloud_config:
7085 userdata = cloud_config["users"]
7086
kasar2aa50742017-08-08 02:11:22 -07007087 self.logger.debug("cloud_init : Guest os customization started..")
sousaedu80135b92021-02-17 15:05:18 +01007088 customize_script = self.format_script(
7089 key_pairs=key_pairs, users_list=userdata
7090 )
beierlb22ce2d2019-12-12 12:09:51 -05007091 customize_script = customize_script.replace("&", "&amp;")
kasar2aa50742017-08-08 02:11:22 -07007092 self.guest_customization(vapp, customize_script)
kasardc1f02e2017-03-25 07:20:30 -07007093 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007094 self.logger.error(
7095 "cloud_init : exception occurred while injecting " "ssh-key"
7096 )
7097
7098 raise vimconn.VimConnException(
7099 "cloud_init : Error {} failed to inject " "ssh-key".format(exp)
7100 )
bhangare06312472017-03-30 05:49:07 -07007101
kasar2aa50742017-08-08 02:11:22 -07007102 def format_script(self, key_pairs=[], users_list=[]):
kasarc5bf2932018-03-09 04:15:22 -08007103 bash_script = """#!/bin/sh
beierlb22ce2d2019-12-12 12:09:51 -05007104echo performing customization tasks with param $1 at `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"`>> /root/customization.log
7105if [ "$1" = "precustomization" ];then
7106 echo performing precustomization tasks on `date "+DATE: %Y-%m-%d - TIME: %H:%M:%S"` >> /root/customization.log
7107"""
kasar2aa50742017-08-08 02:11:22 -07007108
7109 keys = "\n".join(key_pairs)
7110 if keys:
7111 keys_data = """
7112 if [ ! -d /root/.ssh ];then
7113 mkdir /root/.ssh
7114 chown root:root /root/.ssh
7115 chmod 700 /root/.ssh
7116 touch /root/.ssh/authorized_keys
7117 chown root:root /root/.ssh/authorized_keys
7118 chmod 600 /root/.ssh/authorized_keys
7119 # make centos with selinux happy
7120 which restorecon && restorecon -Rv /root/.ssh
7121 else
7122 touch /root/.ssh/authorized_keys
7123 chown root:root /root/.ssh/authorized_keys
7124 chmod 600 /root/.ssh/authorized_keys
7125 fi
7126 echo '{key}' >> /root/.ssh/authorized_keys
sousaedu80135b92021-02-17 15:05:18 +01007127 """.format(
7128 key=keys
7129 )
kasar2aa50742017-08-08 02:11:22 -07007130
beierlb22ce2d2019-12-12 12:09:51 -05007131 bash_script += keys_data
kasar2aa50742017-08-08 02:11:22 -07007132
7133 for user in users_list:
sousaedu80135b92021-02-17 15:05:18 +01007134 if "name" in user:
7135 user_name = user["name"]
7136
7137 if "key-pairs" in user:
7138 user_keys = "\n".join(user["key-pairs"])
kasar2aa50742017-08-08 02:11:22 -07007139 else:
7140 user_keys = None
7141
7142 add_user_name = """
7143 useradd -d /home/{user_name} -m -g users -s /bin/bash {user_name}
sousaedu80135b92021-02-17 15:05:18 +01007144 """.format(
7145 user_name=user_name
7146 )
kasar2aa50742017-08-08 02:11:22 -07007147
beierlb22ce2d2019-12-12 12:09:51 -05007148 bash_script += add_user_name
kasar2aa50742017-08-08 02:11:22 -07007149
7150 if user_keys:
7151 user_keys_data = """
7152 mkdir /home/{user_name}/.ssh
7153 chown {user_name}:{user_name} /home/{user_name}/.ssh
7154 chmod 700 /home/{user_name}/.ssh
7155 touch /home/{user_name}/.ssh/authorized_keys
7156 chown {user_name}:{user_name} /home/{user_name}/.ssh/authorized_keys
7157 chmod 600 /home/{user_name}/.ssh/authorized_keys
7158 # make centos with selinux happy
7159 which restorecon && restorecon -Rv /home/{user_name}/.ssh
7160 echo '{user_key}' >> /home/{user_name}/.ssh/authorized_keys
sousaedu80135b92021-02-17 15:05:18 +01007161 """.format(
7162 user_name=user_name, user_key=user_keys
7163 )
beierlb22ce2d2019-12-12 12:09:51 -05007164 bash_script += user_keys_data
kasar2aa50742017-08-08 02:11:22 -07007165
beierlb22ce2d2019-12-12 12:09:51 -05007166 return bash_script + "\n\tfi"
kasar2aa50742017-08-08 02:11:22 -07007167
7168 def guest_customization(self, vapp, customize_script):
7169 """
7170 Method to customize guest os
7171 vapp - Vapp object
7172 customize_script - Customize script to be run at first boot of VM.
7173 """
kasarc5bf2932018-03-09 04:15:22 -08007174 for vm in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01007175 vm_id = vm.get("id").split(":")[-1]
7176 vm_name = vm.get("name")
7177 vm_name = vm_name.replace("_", "-")
sbhangarea8e5b782018-06-21 02:10:03 -07007178
sousaedu80135b92021-02-17 15:05:18 +01007179 vm_customization_url = (
7180 "{}/api/vApp/vm-{}/guestCustomizationSection/".format(self.url, vm_id)
7181 )
7182 headers = {
7183 "Accept": "application/*+xml;version=" + API_VERSION,
7184 "x-vcloud-authorization": self.client._session.headers[
7185 "x-vcloud-authorization"
7186 ],
7187 }
kasarc5bf2932018-03-09 04:15:22 -08007188
sousaedu80135b92021-02-17 15:05:18 +01007189 headers[
7190 "Content-Type"
7191 ] = "application/vnd.vmware.vcloud.guestCustomizationSection+xml"
kasarc5bf2932018-03-09 04:15:22 -08007192
7193 data = """<GuestCustomizationSection
7194 xmlns="http://www.vmware.com/vcloud/v1.5"
7195 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"
beierlb22ce2d2019-12-12 12:09:51 -05007196 ovf:required="false" href="{}"
7197 type="application/vnd.vmware.vcloud.guestCustomizationSection+xml">
kasarc5bf2932018-03-09 04:15:22 -08007198 <ovf:Info>Specifies Guest OS Customization Settings</ovf:Info>
7199 <Enabled>true</Enabled>
7200 <ChangeSid>false</ChangeSid>
7201 <VirtualMachineId>{}</VirtualMachineId>
7202 <JoinDomainEnabled>false</JoinDomainEnabled>
7203 <UseOrgSettings>false</UseOrgSettings>
7204 <AdminPasswordEnabled>false</AdminPasswordEnabled>
7205 <AdminPasswordAuto>true</AdminPasswordAuto>
7206 <AdminAutoLogonEnabled>false</AdminAutoLogonEnabled>
7207 <AdminAutoLogonCount>0</AdminAutoLogonCount>
7208 <ResetPasswordRequired>false</ResetPasswordRequired>
7209 <CustomizationScript>{}</CustomizationScript>
7210 <ComputerName>{}</ComputerName>
beierlb22ce2d2019-12-12 12:09:51 -05007211 <Link href="{}"
7212 type="application/vnd.vmware.vcloud.guestCustomizationSection+xml" rel="edit"/>
sbhangarea8e5b782018-06-21 02:10:03 -07007213 </GuestCustomizationSection>
sousaedu80135b92021-02-17 15:05:18 +01007214 """.format(
7215 vm_customization_url,
7216 vm_id,
7217 customize_script,
7218 vm_name,
7219 vm_customization_url,
7220 )
kasarc5bf2932018-03-09 04:15:22 -08007221
sousaedu80135b92021-02-17 15:05:18 +01007222 response = self.perform_request(
7223 req_type="PUT", url=vm_customization_url, headers=headers, data=data
7224 )
kasarc5bf2932018-03-09 04:15:22 -08007225 if response.status_code == 202:
beierl26fec002019-12-06 17:06:40 -05007226 guest_task = self.get_task_from_response(response.text)
kasarc5bf2932018-03-09 04:15:22 -08007227 self.client.get_task_monitor().wait_for_success(task=guest_task)
sousaedu80135b92021-02-17 15:05:18 +01007228 self.logger.info(
7229 "guest_customization : customized guest os task "
7230 "completed for VM {}".format(vm_name)
7231 )
kasar2aa50742017-08-08 02:11:22 -07007232 else:
sousaedu80135b92021-02-17 15:05:18 +01007233 self.logger.error(
7234 "guest_customization : task for customized guest os"
7235 "failed for VM {}".format(vm_name)
7236 )
7237
7238 raise vimconn.VimConnException(
7239 "guest_customization : failed to perform"
7240 "guest os customization on VM {}".format(vm_name)
7241 )
bhangare06312472017-03-30 05:49:07 -07007242
bhangare1a0b97c2017-06-21 02:20:15 -07007243 def add_new_disk(self, vapp_uuid, disk_size):
bhangare06312472017-03-30 05:49:07 -07007244 """
sousaedu80135b92021-02-17 15:05:18 +01007245 Method to create an empty vm disk
bhangare06312472017-03-30 05:49:07 -07007246
sousaedu80135b92021-02-17 15:05:18 +01007247 Args:
7248 vapp_uuid - is vapp identifier.
7249 disk_size - size of disk to be created in GB
bhangare06312472017-03-30 05:49:07 -07007250
sousaedu80135b92021-02-17 15:05:18 +01007251 Returns:
7252 None
bhangare06312472017-03-30 05:49:07 -07007253 """
7254 status = False
7255 vm_details = None
7256 try:
beierlb22ce2d2019-12-12 12:09:51 -05007257 # Disk size in GB, convert it into MB
bhangare06312472017-03-30 05:49:07 -07007258 if disk_size is not None:
7259 disk_size_mb = int(disk_size) * 1024
7260 vm_details = self.get_vapp_details_rest(vapp_uuid)
7261
7262 if vm_details and "vm_virtual_hardware" in vm_details:
sousaedu80135b92021-02-17 15:05:18 +01007263 self.logger.info(
7264 "Adding disk to VM: {} disk size:{}GB".format(
7265 vm_details["name"], disk_size
7266 )
7267 )
bhangare06312472017-03-30 05:49:07 -07007268 disk_href = vm_details["vm_virtual_hardware"]["disk_edit_href"]
bhangare1a0b97c2017-06-21 02:20:15 -07007269 status = self.add_new_disk_rest(disk_href, disk_size_mb)
bhangare06312472017-03-30 05:49:07 -07007270 except Exception as exp:
7271 msg = "Error occurred while creating new disk {}.".format(exp)
7272 self.rollback_newvm(vapp_uuid, msg)
7273
7274 if status:
sousaedu80135b92021-02-17 15:05:18 +01007275 self.logger.info(
7276 "Added new disk to VM: {} disk size:{}GB".format(
7277 vm_details["name"], disk_size
7278 )
7279 )
bhangare06312472017-03-30 05:49:07 -07007280 else:
beierlb22ce2d2019-12-12 12:09:51 -05007281 # If failed to add disk, delete VM
sousaedu80135b92021-02-17 15:05:18 +01007282 msg = "add_new_disk: Failed to add new disk to {}".format(
7283 vm_details["name"]
7284 )
bhangare06312472017-03-30 05:49:07 -07007285 self.rollback_newvm(vapp_uuid, msg)
7286
bhangare1a0b97c2017-06-21 02:20:15 -07007287 def add_new_disk_rest(self, disk_href, disk_size_mb):
bhangare06312472017-03-30 05:49:07 -07007288 """
7289 Retrives vApp Disks section & add new empty disk
7290
7291 Args:
7292 disk_href: Disk section href to addd disk
7293 disk_size_mb: Disk size in MB
7294
7295 Returns: Status of add new disk task
7296 """
7297 status = False
kasarc5bf2932018-03-09 04:15:22 -08007298 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01007299 headers = {
7300 "Accept": "application/*+xml;version=" + API_VERSION,
7301 "x-vcloud-authorization": self.client._session.headers[
7302 "x-vcloud-authorization"
7303 ],
7304 }
7305 response = self.perform_request(
7306 req_type="GET", url=disk_href, headers=headers
7307 )
bhangare1a0b97c2017-06-21 02:20:15 -07007308
7309 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01007310 response = self.retry_rest("GET", disk_href)
bhangare06312472017-03-30 05:49:07 -07007311
7312 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01007313 self.logger.error(
7314 "add_new_disk_rest: GET REST API call {} failed. Return status code {}".format(
7315 disk_href, response.status_code
7316 )
7317 )
7318
bhangare06312472017-03-30 05:49:07 -07007319 return status
sousaedu80135b92021-02-17 15:05:18 +01007320
bhangare06312472017-03-30 05:49:07 -07007321 try:
beierlb22ce2d2019-12-12 12:09:51 -05007322 # Find but type & max of instance IDs assigned to disks
beierl01bd6692019-12-09 17:06:20 -05007323 lxmlroot_respond = lxmlElementTree.fromstring(response.content)
sousaedu80135b92021-02-17 15:05:18 +01007324 namespaces = {
7325 prefix: uri for prefix, uri in lxmlroot_respond.nsmap.items() if prefix
7326 }
beierlb22ce2d2019-12-12 12:09:51 -05007327 namespaces["xmlns"] = "http://www.vmware.com/vcloud/v1.5"
bhangare06312472017-03-30 05:49:07 -07007328 instance_id = 0
sousaedu80135b92021-02-17 15:05:18 +01007329
7330 for item in lxmlroot_respond.iterfind("xmlns:Item", namespaces):
beierlb22ce2d2019-12-12 12:09:51 -05007331 if item.find("rasd:Description", namespaces).text == "Hard disk":
7332 inst_id = int(item.find("rasd:InstanceID", namespaces).text)
sousaedu80135b92021-02-17 15:05:18 +01007333
bhangare06312472017-03-30 05:49:07 -07007334 if inst_id > instance_id:
7335 instance_id = inst_id
beierlb22ce2d2019-12-12 12:09:51 -05007336 disk_item = item.find("rasd:HostResource", namespaces)
sousaedu80135b92021-02-17 15:05:18 +01007337 bus_subtype = disk_item.attrib[
7338 "{" + namespaces["xmlns"] + "}busSubType"
7339 ]
7340 bus_type = disk_item.attrib[
7341 "{" + namespaces["xmlns"] + "}busType"
7342 ]
bhangare06312472017-03-30 05:49:07 -07007343
7344 instance_id = instance_id + 1
beierlb22ce2d2019-12-12 12:09:51 -05007345 new_item = """<Item>
bhangare06312472017-03-30 05:49:07 -07007346 <rasd:Description>Hard disk</rasd:Description>
7347 <rasd:ElementName>New disk</rasd:ElementName>
7348 <rasd:HostResource
7349 xmlns:vcloud="http://www.vmware.com/vcloud/v1.5"
7350 vcloud:capacity="{}"
7351 vcloud:busSubType="{}"
7352 vcloud:busType="{}"></rasd:HostResource>
7353 <rasd:InstanceID>{}</rasd:InstanceID>
7354 <rasd:ResourceType>17</rasd:ResourceType>
sousaedu80135b92021-02-17 15:05:18 +01007355 </Item>""".format(
7356 disk_size_mb, bus_subtype, bus_type, instance_id
7357 )
bhangare06312472017-03-30 05:49:07 -07007358
beierl26fec002019-12-06 17:06:40 -05007359 new_data = response.text
beierlb22ce2d2019-12-12 12:09:51 -05007360 # Add new item at the bottom
sousaedu80135b92021-02-17 15:05:18 +01007361 new_data = new_data.replace(
7362 "</Item>\n</RasdItemsList>",
7363 "</Item>\n{}\n</RasdItemsList>".format(new_item),
7364 )
bhangare06312472017-03-30 05:49:07 -07007365
7366 # Send PUT request to modify virtual hardware section with new disk
sousaedu80135b92021-02-17 15:05:18 +01007367 headers[
7368 "Content-Type"
7369 ] = "application/vnd.vmware.vcloud.rasdItemsList+xml; charset=ISO-8859-1"
bhangare06312472017-03-30 05:49:07 -07007370
sousaedu80135b92021-02-17 15:05:18 +01007371 response = self.perform_request(
7372 req_type="PUT", url=disk_href, data=new_data, headers=headers
7373 )
bhangare1a0b97c2017-06-21 02:20:15 -07007374
7375 if response.status_code == 403:
sousaedu80135b92021-02-17 15:05:18 +01007376 add_headers = {"Content-Type": headers["Content-Type"]}
7377 response = self.retry_rest("PUT", disk_href, add_headers, new_data)
bhangare06312472017-03-30 05:49:07 -07007378
7379 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01007380 self.logger.error(
7381 "PUT REST API call {} failed. Return status code {}. response.text:{}".format(
7382 disk_href, response.status_code, response.text
7383 )
7384 )
bhangare06312472017-03-30 05:49:07 -07007385 else:
beierl26fec002019-12-06 17:06:40 -05007386 add_disk_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01007387 result = self.client.get_task_monitor().wait_for_success(
7388 task=add_disk_task
7389 )
7390
7391 if result.get("status") == "success":
kasarc5bf2932018-03-09 04:15:22 -08007392 status = True
7393 else:
sousaedu80135b92021-02-17 15:05:18 +01007394 self.logger.error(
7395 "Add new disk REST task failed to add {} MB disk".format(
7396 disk_size_mb
7397 )
7398 )
bhangare06312472017-03-30 05:49:07 -07007399 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007400 self.logger.error(
7401 "Error occurred calling rest api for creating new disk {}".format(exp)
7402 )
bhangare06312472017-03-30 05:49:07 -07007403
7404 return status
7405
sousaedu80135b92021-02-17 15:05:18 +01007406 def add_existing_disk(
7407 self,
7408 catalogs=None,
7409 image_id=None,
7410 size=None,
7411 template_name=None,
7412 vapp_uuid=None,
7413 ):
bhangare06312472017-03-30 05:49:07 -07007414 """
sousaedu80135b92021-02-17 15:05:18 +01007415 Method to add existing disk to vm
7416 Args :
7417 catalogs - List of VDC catalogs
7418 image_id - Catalog ID
7419 template_name - Name of template in catalog
7420 vapp_uuid - UUID of vApp
7421 Returns:
7422 None
bhangare06312472017-03-30 05:49:07 -07007423 """
7424 disk_info = None
7425 vcenter_conect, content = self.get_vcenter_content()
beierlb22ce2d2019-12-12 12:09:51 -05007426 # find moref-id of vm in image
sousaedu80135b92021-02-17 15:05:18 +01007427 catalog_vm_info = self.get_vapp_template_details(
7428 catalogs=catalogs,
7429 image_id=image_id,
7430 )
bhangare06312472017-03-30 05:49:07 -07007431
7432 if catalog_vm_info and "vm_vcenter_info" in catalog_vm_info:
7433 if "vm_moref_id" in catalog_vm_info["vm_vcenter_info"]:
sousaedu80135b92021-02-17 15:05:18 +01007434 catalog_vm_moref_id = catalog_vm_info["vm_vcenter_info"].get(
7435 "vm_moref_id", None
7436 )
7437
bhangare06312472017-03-30 05:49:07 -07007438 if catalog_vm_moref_id:
sousaedu80135b92021-02-17 15:05:18 +01007439 self.logger.info(
7440 "Moref_id of VM in catalog : {}".format(catalog_vm_moref_id)
7441 )
beierlb22ce2d2019-12-12 12:09:51 -05007442 _, catalog_vm_obj = self.get_vm_obj(content, catalog_vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007443
bhangare06312472017-03-30 05:49:07 -07007444 if catalog_vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05007445 # find existing disk
bhangare06312472017-03-30 05:49:07 -07007446 disk_info = self.find_disk(catalog_vm_obj)
7447 else:
7448 exp_msg = "No VM with image id {} found".format(image_id)
7449 self.rollback_newvm(vapp_uuid, exp_msg, exp_type="NotFound")
7450 else:
7451 exp_msg = "No Image found with image ID {} ".format(image_id)
7452 self.rollback_newvm(vapp_uuid, exp_msg, exp_type="NotFound")
7453
7454 if disk_info:
7455 self.logger.info("Existing disk_info : {}".format(disk_info))
beierlb22ce2d2019-12-12 12:09:51 -05007456 # get VM
bhangare06312472017-03-30 05:49:07 -07007457 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
beierlb22ce2d2019-12-12 12:09:51 -05007458 _, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007459
bhangare06312472017-03-30 05:49:07 -07007460 if vm_obj:
sousaedu80135b92021-02-17 15:05:18 +01007461 status = self.add_disk(
7462 vcenter_conect=vcenter_conect,
7463 vm=vm_obj,
7464 disk_info=disk_info,
7465 size=size,
7466 vapp_uuid=vapp_uuid,
7467 )
7468
bhangare06312472017-03-30 05:49:07 -07007469 if status:
sousaedu80135b92021-02-17 15:05:18 +01007470 self.logger.info(
7471 "Disk from image id {} added to {}".format(
7472 image_id, vm_obj.config.name
7473 )
7474 )
bhangare06312472017-03-30 05:49:07 -07007475 else:
7476 msg = "No disk found with image id {} to add in VM {}".format(
sousaedu80135b92021-02-17 15:05:18 +01007477 image_id, vm_obj.config.name
7478 )
bhangare06312472017-03-30 05:49:07 -07007479 self.rollback_newvm(vapp_uuid, msg, exp_type="NotFound")
7480
bhangare06312472017-03-30 05:49:07 -07007481 def find_disk(self, vm_obj):
7482 """
sousaedu80135b92021-02-17 15:05:18 +01007483 Method to find details of existing disk in VM
7484 Args:
bhangare06312472017-03-30 05:49:07 -07007485 vm_obj - vCenter object of VM
bhangare06312472017-03-30 05:49:07 -07007486 Returns:
7487 disk_info : dict of disk details
7488 """
7489 disk_info = {}
7490 if vm_obj:
7491 try:
7492 devices = vm_obj.config.hardware.device
sousaedu80135b92021-02-17 15:05:18 +01007493
bhangare06312472017-03-30 05:49:07 -07007494 for device in devices:
7495 if type(device) is vim.vm.device.VirtualDisk:
sousaedu80135b92021-02-17 15:05:18 +01007496 if (
7497 isinstance(
7498 device.backing,
7499 vim.vm.device.VirtualDisk.FlatVer2BackingInfo,
7500 )
7501 and hasattr(device.backing, "fileName")
7502 ):
bhangare06312472017-03-30 05:49:07 -07007503 disk_info["full_path"] = device.backing.fileName
7504 disk_info["datastore"] = device.backing.datastore
7505 disk_info["capacityKB"] = device.capacityInKB
7506 break
7507 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007508 self.logger.error(
7509 "find_disk() : exception occurred while "
7510 "getting existing disk details :{}".format(exp)
7511 )
7512
bhangare06312472017-03-30 05:49:07 -07007513 return disk_info
7514
sousaedu80135b92021-02-17 15:05:18 +01007515 def add_disk(
7516 self, vcenter_conect=None, vm=None, size=None, vapp_uuid=None, disk_info={}
7517 ):
bhangare06312472017-03-30 05:49:07 -07007518 """
sousaedu80135b92021-02-17 15:05:18 +01007519 Method to add existing disk in VM
7520 Args :
7521 vcenter_conect - vCenter content object
7522 vm - vCenter vm object
7523 disk_info : dict of disk details
7524 Returns:
7525 status : status of add disk task
bhangare06312472017-03-30 05:49:07 -07007526 """
7527 datastore = disk_info["datastore"] if "datastore" in disk_info else None
7528 fullpath = disk_info["full_path"] if "full_path" in disk_info else None
7529 capacityKB = disk_info["capacityKB"] if "capacityKB" in disk_info else None
7530 if size is not None:
beierlb22ce2d2019-12-12 12:09:51 -05007531 # Convert size from GB to KB
bhangare06312472017-03-30 05:49:07 -07007532 sizeKB = int(size) * 1024 * 1024
beierlb22ce2d2019-12-12 12:09:51 -05007533 # compare size of existing disk and user given size.Assign whicherver is greater
sousaedu80135b92021-02-17 15:05:18 +01007534 self.logger.info(
7535 "Add Existing disk : sizeKB {} , capacityKB {}".format(
7536 sizeKB, capacityKB
7537 )
7538 )
7539
bhangare06312472017-03-30 05:49:07 -07007540 if sizeKB > capacityKB:
7541 capacityKB = sizeKB
7542
7543 if datastore and fullpath and capacityKB:
7544 try:
7545 spec = vim.vm.ConfigSpec()
7546 # get all disks on a VM, set unit_number to the next available
7547 unit_number = 0
7548 for dev in vm.config.hardware.device:
sousaedu80135b92021-02-17 15:05:18 +01007549 if hasattr(dev.backing, "fileName"):
bhangare06312472017-03-30 05:49:07 -07007550 unit_number = int(dev.unitNumber) + 1
7551 # unit_number 7 reserved for scsi controller
sousaedu80135b92021-02-17 15:05:18 +01007552
bhangare06312472017-03-30 05:49:07 -07007553 if unit_number == 7:
7554 unit_number += 1
sousaedu80135b92021-02-17 15:05:18 +01007555
bhangare06312472017-03-30 05:49:07 -07007556 if isinstance(dev, vim.vm.device.VirtualDisk):
beierlb22ce2d2019-12-12 12:09:51 -05007557 # vim.vm.device.VirtualSCSIController
bhangare06312472017-03-30 05:49:07 -07007558 controller_key = dev.controllerKey
7559
sousaedu80135b92021-02-17 15:05:18 +01007560 self.logger.info(
7561 "Add Existing disk : unit number {} , controller key {}".format(
7562 unit_number, controller_key
7563 )
7564 )
bhangare06312472017-03-30 05:49:07 -07007565 # add disk here
7566 dev_changes = []
7567 disk_spec = vim.vm.device.VirtualDeviceSpec()
7568 disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
7569 disk_spec.device = vim.vm.device.VirtualDisk()
sousaedu80135b92021-02-17 15:05:18 +01007570 disk_spec.device.backing = (
bhangare06312472017-03-30 05:49:07 -07007571 vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
sousaedu80135b92021-02-17 15:05:18 +01007572 )
bhangare06312472017-03-30 05:49:07 -07007573 disk_spec.device.backing.thinProvisioned = True
sousaedu80135b92021-02-17 15:05:18 +01007574 disk_spec.device.backing.diskMode = "persistent"
beierlb22ce2d2019-12-12 12:09:51 -05007575 disk_spec.device.backing.datastore = datastore
7576 disk_spec.device.backing.fileName = fullpath
bhangare06312472017-03-30 05:49:07 -07007577
7578 disk_spec.device.unitNumber = unit_number
7579 disk_spec.device.capacityInKB = capacityKB
7580 disk_spec.device.controllerKey = controller_key
7581 dev_changes.append(disk_spec)
7582 spec.deviceChange = dev_changes
7583 task = vm.ReconfigVM_Task(spec=spec)
7584 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu80135b92021-02-17 15:05:18 +01007585
bhangare06312472017-03-30 05:49:07 -07007586 return status
7587 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007588 exp_msg = (
7589 "add_disk() : exception {} occurred while adding disk "
7590 "{} to vm {}".format(exp, fullpath, vm.config.name)
7591 )
bhangare06312472017-03-30 05:49:07 -07007592 self.rollback_newvm(vapp_uuid, exp_msg)
7593 else:
sousaedu80135b92021-02-17 15:05:18 +01007594 msg = "add_disk() : Can not add disk to VM with disk info {} ".format(
7595 disk_info
7596 )
bhangare06312472017-03-30 05:49:07 -07007597 self.rollback_newvm(vapp_uuid, msg)
7598
bhangare06312472017-03-30 05:49:07 -07007599 def get_vcenter_content(self):
7600 """
sousaedu80135b92021-02-17 15:05:18 +01007601 Get the vsphere content object
bhangare06312472017-03-30 05:49:07 -07007602 """
7603 try:
7604 vm_vcenter_info = self.get_vm_vcenter_info()
7605 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007606 self.logger.error(
7607 "Error occurred while getting vCenter infromationn"
7608 " for VM : {}".format(exp)
7609 )
7610
tierno72774862020-05-04 11:44:15 +00007611 raise vimconn.VimConnException(message=exp)
bhangare06312472017-03-30 05:49:07 -07007612
7613 context = None
sousaedu80135b92021-02-17 15:05:18 +01007614 if hasattr(ssl, "_create_unverified_context"):
bhangare06312472017-03-30 05:49:07 -07007615 context = ssl._create_unverified_context()
7616
7617 vcenter_conect = SmartConnect(
beierlb22ce2d2019-12-12 12:09:51 -05007618 host=vm_vcenter_info["vm_vcenter_ip"],
7619 user=vm_vcenter_info["vm_vcenter_user"],
7620 pwd=vm_vcenter_info["vm_vcenter_password"],
7621 port=int(vm_vcenter_info["vm_vcenter_port"]),
sousaedu80135b92021-02-17 15:05:18 +01007622 sslContext=context,
7623 )
bhangare06312472017-03-30 05:49:07 -07007624 atexit.register(Disconnect, vcenter_conect)
7625 content = vcenter_conect.RetrieveContent()
sousaedu80135b92021-02-17 15:05:18 +01007626
bhangare06312472017-03-30 05:49:07 -07007627 return vcenter_conect, content
7628
bhangare06312472017-03-30 05:49:07 -07007629 def get_vm_moref_id(self, vapp_uuid):
7630 """
7631 Get the moref_id of given VM
7632 """
7633 try:
7634 if vapp_uuid:
sousaedu80135b92021-02-17 15:05:18 +01007635 vm_details = self.get_vapp_details_rest(
7636 vapp_uuid, need_admin_access=True
7637 )
7638
bhangare06312472017-03-30 05:49:07 -07007639 if vm_details and "vm_vcenter_info" in vm_details:
7640 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
bhangare06312472017-03-30 05:49:07 -07007641
sousaedu80135b92021-02-17 15:05:18 +01007642 return vm_moref_id
bhangare06312472017-03-30 05:49:07 -07007643 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007644 self.logger.error(
7645 "Error occurred while getting VM moref ID " " for VM : {}".format(exp)
7646 )
7647
bhangare06312472017-03-30 05:49:07 -07007648 return None
7649
sousaedu80135b92021-02-17 15:05:18 +01007650 def get_vapp_template_details(
7651 self, catalogs=None, image_id=None, template_name=None
7652 ):
bhangare06312472017-03-30 05:49:07 -07007653 """
sousaedu80135b92021-02-17 15:05:18 +01007654 Method to get vApp template details
7655 Args :
7656 catalogs - list of VDC catalogs
7657 image_id - Catalog ID to find
7658 template_name : template name in catalog
7659 Returns:
7660 parsed_respond : dict of vApp tempalte details
bhangare06312472017-03-30 05:49:07 -07007661 """
7662 parsed_response = {}
7663
7664 vca = self.connect_as_admin()
7665 if not vca:
tierno72774862020-05-04 11:44:15 +00007666 raise vimconn.VimConnConnectionException("Failed to connect vCD")
bhangare06312472017-03-30 05:49:07 -07007667
7668 try:
beierlb22ce2d2019-12-12 12:09:51 -05007669 org, _ = self.get_vdc_details()
bhangare06312472017-03-30 05:49:07 -07007670 catalog = self.get_catalog_obj(image_id, catalogs)
7671 if catalog:
sousaedu80135b92021-02-17 15:05:18 +01007672 items = org.get_catalog_item(catalog.get("name"), catalog.get("name"))
kasarc5bf2932018-03-09 04:15:22 -08007673 catalog_items = [items.attrib]
7674
bhangare06312472017-03-30 05:49:07 -07007675 if len(catalog_items) == 1:
sousaedu80135b92021-02-17 15:05:18 +01007676 headers = {
7677 "Accept": "application/*+xml;version=" + API_VERSION,
7678 "x-vcloud-authorization": vca._session.headers[
7679 "x-vcloud-authorization"
7680 ],
7681 }
7682 response = self.perform_request(
7683 req_type="GET",
7684 url=catalog_items[0].get("href"),
7685 headers=headers,
7686 )
beierl26fec002019-12-06 17:06:40 -05007687 catalogItem = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01007688 entity = [
7689 child
7690 for child in catalogItem
7691 if child.get("type")
7692 == "application/vnd.vmware.vcloud.vAppTemplate+xml"
7693 ][0]
bhangare06312472017-03-30 05:49:07 -07007694 vapp_tempalte_href = entity.get("href")
beierlb22ce2d2019-12-12 12:09:51 -05007695 # get vapp details and parse moref id
bhangare06312472017-03-30 05:49:07 -07007696
beierlb22ce2d2019-12-12 12:09:51 -05007697 namespaces = {
sousaedu80135b92021-02-17 15:05:18 +01007698 "vssd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData",
7699 "ovf": "http://schemas.dmtf.org/ovf/envelope/1",
7700 "vmw": "http://www.vmware.com/schema/ovf",
7701 "vm": "http://www.vmware.com/vcloud/v1.5",
7702 "rasd": "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData",
7703 "vmext": "http://www.vmware.com/vcloud/extension/v1.5",
7704 "xmlns": "http://www.vmware.com/vcloud/v1.5",
beierlb22ce2d2019-12-12 12:09:51 -05007705 }
bhangare06312472017-03-30 05:49:07 -07007706
kasarc5bf2932018-03-09 04:15:22 -08007707 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01007708 response = self.perform_request(
7709 req_type="GET", url=vapp_tempalte_href, headers=headers
7710 )
bhangare06312472017-03-30 05:49:07 -07007711
7712 if response.status_code != requests.codes.ok:
sousaedu80135b92021-02-17 15:05:18 +01007713 self.logger.debug(
7714 "REST API call {} failed. Return status code {}".format(
7715 vapp_tempalte_href, response.status_code
7716 )
7717 )
bhangare06312472017-03-30 05:49:07 -07007718 else:
beierl26fec002019-12-06 17:06:40 -05007719 xmlroot_respond = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01007720 children_section = xmlroot_respond.find(
7721 "vm:Children/", namespaces
7722 )
7723
bhangare06312472017-03-30 05:49:07 -07007724 if children_section is not None:
sousaedu80135b92021-02-17 15:05:18 +01007725 vCloud_extension_section = children_section.find(
7726 "xmlns:VCloudExtension", namespaces
7727 )
7728
bhangare06312472017-03-30 05:49:07 -07007729 if vCloud_extension_section is not None:
7730 vm_vcenter_info = {}
sousaedu80135b92021-02-17 15:05:18 +01007731 vim_info = vCloud_extension_section.find(
7732 "vmext:VmVimInfo", namespaces
7733 )
7734 vmext = vim_info.find(
7735 "vmext:VmVimObjectRef", namespaces
7736 )
bhangare06312472017-03-30 05:49:07 -07007737
sousaedu80135b92021-02-17 15:05:18 +01007738 if vmext is not None:
7739 vm_vcenter_info["vm_moref_id"] = vmext.find(
7740 "vmext:MoRef", namespaces
7741 ).text
7742
7743 parsed_response["vm_vcenter_info"] = vm_vcenter_info
beierlb22ce2d2019-12-12 12:09:51 -05007744 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007745 self.logger.info(
7746 "Error occurred calling rest api for getting vApp details {}".format(
7747 exp
7748 )
7749 )
bhangare06312472017-03-30 05:49:07 -07007750
7751 return parsed_response
7752
beierlb22ce2d2019-12-12 12:09:51 -05007753 def rollback_newvm(self, vapp_uuid, msg, exp_type="Genric"):
bhangare06312472017-03-30 05:49:07 -07007754 """
sousaedu80135b92021-02-17 15:05:18 +01007755 Method to delete vApp
7756 Args :
7757 vapp_uuid - vApp UUID
7758 msg - Error message to be logged
7759 exp_type : Exception type
7760 Returns:
7761 None
bhangare06312472017-03-30 05:49:07 -07007762 """
7763 if vapp_uuid:
beierlb22ce2d2019-12-12 12:09:51 -05007764 self.delete_vminstance(vapp_uuid)
bhangare06312472017-03-30 05:49:07 -07007765 else:
7766 msg = "No vApp ID"
sousaedu80135b92021-02-17 15:05:18 +01007767
bhangare06312472017-03-30 05:49:07 -07007768 self.logger.error(msg)
sousaedu80135b92021-02-17 15:05:18 +01007769
bhangare06312472017-03-30 05:49:07 -07007770 if exp_type == "Genric":
tierno72774862020-05-04 11:44:15 +00007771 raise vimconn.VimConnException(msg)
bhangare06312472017-03-30 05:49:07 -07007772 elif exp_type == "NotFound":
tierno72774862020-05-04 11:44:15 +00007773 raise vimconn.VimConnNotFoundException(message=msg)
bhangare06312472017-03-30 05:49:07 -07007774
kateac1e3792017-04-01 02:16:39 -07007775 def add_sriov(self, vapp_uuid, sriov_nets, vmname_andid):
7776 """
sousaedu80135b92021-02-17 15:05:18 +01007777 Method to attach SRIOV adapters to VM
kateac1e3792017-04-01 02:16:39 -07007778
sousaedu80135b92021-02-17 15:05:18 +01007779 Args:
7780 vapp_uuid - uuid of vApp/VM
7781 sriov_nets - SRIOV devices infromation as specified in VNFD (flavor)
7782 vmname_andid - vmname
kateac1e3792017-04-01 02:16:39 -07007783
sousaedu80135b92021-02-17 15:05:18 +01007784 Returns:
7785 The status of add SRIOV adapter task , vm object and
7786 vcenter_conect object
kateac1e3792017-04-01 02:16:39 -07007787 """
7788 vm_obj = None
7789 vcenter_conect, content = self.get_vcenter_content()
7790 vm_moref_id = self.get_vm_moref_id(vapp_uuid)
7791
7792 if vm_moref_id:
7793 try:
7794 no_of_sriov_devices = len(sriov_nets)
7795 if no_of_sriov_devices > 0:
beierlb22ce2d2019-12-12 12:09:51 -05007796 # Get VM and its host
kateac1e3792017-04-01 02:16:39 -07007797 host_obj, vm_obj = self.get_vm_obj(content, vm_moref_id)
sousaedu80135b92021-02-17 15:05:18 +01007798 self.logger.info(
7799 "VM {} is currently on host {}".format(vm_obj, host_obj)
7800 )
7801
kateac1e3792017-04-01 02:16:39 -07007802 if host_obj and vm_obj:
beierlb22ce2d2019-12-12 12:09:51 -05007803 # get SRIOV devies from host on which vapp is currently installed
sousaedu80135b92021-02-17 15:05:18 +01007804 avilable_sriov_devices = self.get_sriov_devices(
7805 host_obj,
7806 no_of_sriov_devices,
7807 )
kateac1e3792017-04-01 02:16:39 -07007808
7809 if len(avilable_sriov_devices) == 0:
beierlb22ce2d2019-12-12 12:09:51 -05007810 # find other hosts with active pci devices
sousaedu80135b92021-02-17 15:05:18 +01007811 (
7812 new_host_obj,
7813 avilable_sriov_devices,
7814 ) = self.get_host_and_sriov_devices(
beierlb22ce2d2019-12-12 12:09:51 -05007815 content,
7816 no_of_sriov_devices,
sousaedu80135b92021-02-17 15:05:18 +01007817 )
kateac1e3792017-04-01 02:16:39 -07007818
sousaedu80135b92021-02-17 15:05:18 +01007819 if (
7820 new_host_obj is not None
7821 and len(avilable_sriov_devices) > 0
7822 ):
beierlb22ce2d2019-12-12 12:09:51 -05007823 # Migrate vm to the host where SRIOV devices are available
sousaedu80135b92021-02-17 15:05:18 +01007824 self.logger.info(
7825 "Relocate VM {} on new host {}".format(
7826 vm_obj, new_host_obj
7827 )
7828 )
kateac1e3792017-04-01 02:16:39 -07007829 task = self.relocate_vm(new_host_obj, vm_obj)
sousaedu80135b92021-02-17 15:05:18 +01007830
kateac1e3792017-04-01 02:16:39 -07007831 if task is not None:
sousaedu80135b92021-02-17 15:05:18 +01007832 result = self.wait_for_vcenter_task(
7833 task, vcenter_conect
7834 )
7835 self.logger.info(
7836 "Migrate VM status: {}".format(result)
7837 )
kateac1e3792017-04-01 02:16:39 -07007838 host_obj = new_host_obj
7839 else:
sousaedu80135b92021-02-17 15:05:18 +01007840 self.logger.info(
7841 "Fail to migrate VM : {}".format(result)
7842 )
7843
tierno72774862020-05-04 11:44:15 +00007844 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05007845 "Fail to migrate VM : {} to host {}".format(
sousaedu80135b92021-02-17 15:05:18 +01007846 vmname_andid, new_host_obj
kateac1e3792017-04-01 02:16:39 -07007847 )
sousaedu80135b92021-02-17 15:05:18 +01007848 )
kateac1e3792017-04-01 02:16:39 -07007849
sousaedu80135b92021-02-17 15:05:18 +01007850 if (
7851 host_obj is not None
7852 and avilable_sriov_devices is not None
7853 and len(avilable_sriov_devices) > 0
7854 ):
beierlb22ce2d2019-12-12 12:09:51 -05007855 # Add SRIOV devices one by one
kateac1e3792017-04-01 02:16:39 -07007856 for sriov_net in sriov_nets:
sousaedu80135b92021-02-17 15:05:18 +01007857 network_name = sriov_net.get("net_id")
beierlb22ce2d2019-12-12 12:09:51 -05007858 self.create_dvPort_group(network_name)
kateac1e3792017-04-01 02:16:39 -07007859
sousaedu80135b92021-02-17 15:05:18 +01007860 if (
7861 sriov_net.get("type") == "VF"
7862 or sriov_net.get("type") == "SR-IOV"
7863 ):
7864 # add vlan ID ,Modify portgroup for vlan ID
7865 self.configure_vlanID(
7866 content, vcenter_conect, network_name
7867 )
7868
7869 task = self.add_sriov_to_vm(
7870 content,
7871 vm_obj,
7872 host_obj,
7873 network_name,
7874 avilable_sriov_devices[0],
7875 )
7876
kateac1e3792017-04-01 02:16:39 -07007877 if task:
sousaedu80135b92021-02-17 15:05:18 +01007878 status = self.wait_for_vcenter_task(
7879 task, vcenter_conect
7880 )
7881
kateac1e3792017-04-01 02:16:39 -07007882 if status:
sousaedu80135b92021-02-17 15:05:18 +01007883 self.logger.info(
7884 "Added SRIOV {} to VM {}".format(
7885 no_of_sriov_devices, str(vm_obj)
7886 )
kateac1e3792017-04-01 02:16:39 -07007887 )
sousaedu80135b92021-02-17 15:05:18 +01007888 else:
7889 self.logger.error(
7890 "Fail to add SRIOV {} to VM {}".format(
7891 no_of_sriov_devices, str(vm_obj)
7892 )
7893 )
7894
7895 raise vimconn.VimConnUnexpectedResponse(
7896 "Fail to add SRIOV adapter in VM {}".format(
7897 str(vm_obj)
7898 )
7899 )
7900
kateac1e3792017-04-01 02:16:39 -07007901 return True, vm_obj, vcenter_conect
7902 else:
sousaedu80135b92021-02-17 15:05:18 +01007903 self.logger.error(
7904 "Currently there is no host with"
7905 " {} number of avaialble SRIOV "
7906 "VFs required for VM {}".format(
7907 no_of_sriov_devices, vmname_andid
7908 )
7909 )
7910
tierno72774862020-05-04 11:44:15 +00007911 raise vimconn.VimConnNotFoundException(
beierlb22ce2d2019-12-12 12:09:51 -05007912 "Currently there is no host with {} "
7913 "number of avaialble SRIOV devices required for VM {}".format(
sousaedu80135b92021-02-17 15:05:18 +01007914 no_of_sriov_devices, vmname_andid
7915 )
7916 )
kateac1e3792017-04-01 02:16:39 -07007917 else:
sousaedu80135b92021-02-17 15:05:18 +01007918 self.logger.debug(
7919 "No infromation about SRIOV devices {} ", sriov_nets
7920 )
kateac1e3792017-04-01 02:16:39 -07007921 except vmodl.MethodFault as error:
beierlb22ce2d2019-12-12 12:09:51 -05007922 self.logger.error("Error occurred while adding SRIOV {} ", error)
sousaedu80135b92021-02-17 15:05:18 +01007923
kateac1e3792017-04-01 02:16:39 -07007924 return None, vm_obj, vcenter_conect
7925
beierlb22ce2d2019-12-12 12:09:51 -05007926 def get_sriov_devices(self, host, no_of_vfs):
kateac1e3792017-04-01 02:16:39 -07007927 """
sousaedu80135b92021-02-17 15:05:18 +01007928 Method to get the details of SRIOV devices on given host
7929 Args:
7930 host - vSphere host object
7931 no_of_vfs - number of VFs needed on host
kateac1e3792017-04-01 02:16:39 -07007932
sousaedu80135b92021-02-17 15:05:18 +01007933 Returns:
7934 array of SRIOV devices
kateac1e3792017-04-01 02:16:39 -07007935 """
beierlb22ce2d2019-12-12 12:09:51 -05007936 sriovInfo = []
sousaedu80135b92021-02-17 15:05:18 +01007937
kateac1e3792017-04-01 02:16:39 -07007938 if host:
7939 for device in host.config.pciPassthruInfo:
beierlb22ce2d2019-12-12 12:09:51 -05007940 if isinstance(device, vim.host.SriovInfo) and device.sriovActive:
kateac1e3792017-04-01 02:16:39 -07007941 if device.numVirtualFunction >= no_of_vfs:
7942 sriovInfo.append(device)
7943 break
sousaedu80135b92021-02-17 15:05:18 +01007944
kateac1e3792017-04-01 02:16:39 -07007945 return sriovInfo
7946
kateac1e3792017-04-01 02:16:39 -07007947 def get_host_and_sriov_devices(self, content, no_of_vfs):
7948 """
sousaedu80135b92021-02-17 15:05:18 +01007949 Method to get the details of SRIOV devices infromation on all hosts
kateac1e3792017-04-01 02:16:39 -07007950
sousaedu80135b92021-02-17 15:05:18 +01007951 Args:
7952 content - vSphere host object
7953 no_of_vfs - number of pci VFs needed on host
kateac1e3792017-04-01 02:16:39 -07007954
sousaedu80135b92021-02-17 15:05:18 +01007955 Returns:
7956 array of SRIOV devices and host object
kateac1e3792017-04-01 02:16:39 -07007957 """
7958 host_obj = None
7959 sriov_device_objs = None
sousaedu80135b92021-02-17 15:05:18 +01007960
kateac1e3792017-04-01 02:16:39 -07007961 try:
7962 if content:
sousaedu80135b92021-02-17 15:05:18 +01007963 container = content.viewManager.CreateContainerView(
7964 content.rootFolder, [vim.HostSystem], True
7965 )
7966
kateac1e3792017-04-01 02:16:39 -07007967 for host in container.view:
7968 devices = self.get_sriov_devices(host, no_of_vfs)
sousaedu80135b92021-02-17 15:05:18 +01007969
kateac1e3792017-04-01 02:16:39 -07007970 if devices:
7971 host_obj = host
7972 sriov_device_objs = devices
7973 break
7974 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01007975 self.logger.error(
7976 "Error {} occurred while finding SRIOV devices on host: {}".format(
7977 exp, host_obj
7978 )
7979 )
kateac1e3792017-04-01 02:16:39 -07007980
beierlb22ce2d2019-12-12 12:09:51 -05007981 return host_obj, sriov_device_objs
kateac1e3792017-04-01 02:16:39 -07007982
beierlb22ce2d2019-12-12 12:09:51 -05007983 def add_sriov_to_vm(self, content, vm_obj, host_obj, network_name, sriov_device):
kateac1e3792017-04-01 02:16:39 -07007984 """
sousaedu80135b92021-02-17 15:05:18 +01007985 Method to add SRIOV adapter to vm
kateac1e3792017-04-01 02:16:39 -07007986
sousaedu80135b92021-02-17 15:05:18 +01007987 Args:
7988 host_obj - vSphere host object
7989 vm_obj - vSphere vm object
7990 content - vCenter content object
7991 network_name - name of distributed virtaul portgroup
7992 sriov_device - SRIOV device info
kateac1e3792017-04-01 02:16:39 -07007993
sousaedu80135b92021-02-17 15:05:18 +01007994 Returns:
7995 task object
kateac1e3792017-04-01 02:16:39 -07007996 """
7997 devices = []
7998 vnic_label = "sriov nic"
sousaedu80135b92021-02-17 15:05:18 +01007999
kateac1e3792017-04-01 02:16:39 -07008000 try:
8001 dvs_portgr = self.get_dvport_group(network_name)
8002 network_name = dvs_portgr.name
8003 nic = vim.vm.device.VirtualDeviceSpec()
8004 # VM device
8005 nic.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
8006 nic.device = vim.vm.device.VirtualSriovEthernetCard()
sousaedu80135b92021-02-17 15:05:18 +01008007 nic.device.addressType = "assigned"
beierlb22ce2d2019-12-12 12:09:51 -05008008 # nic.device.key = 13016
kateac1e3792017-04-01 02:16:39 -07008009 nic.device.deviceInfo = vim.Description()
8010 nic.device.deviceInfo.label = vnic_label
8011 nic.device.deviceInfo.summary = network_name
8012 nic.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
8013
sousaedu80135b92021-02-17 15:05:18 +01008014 nic.device.backing.network = self.get_obj(
8015 content, [vim.Network], network_name
8016 )
kateac1e3792017-04-01 02:16:39 -07008017 nic.device.backing.deviceName = network_name
8018 nic.device.backing.useAutoDetect = False
8019 nic.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
8020 nic.device.connectable.startConnected = True
8021 nic.device.connectable.allowGuestControl = True
8022
sousaedu80135b92021-02-17 15:05:18 +01008023 nic.device.sriovBacking = (
8024 vim.vm.device.VirtualSriovEthernetCard.SriovBackingInfo()
8025 )
8026 nic.device.sriovBacking.physicalFunctionBacking = (
8027 vim.vm.device.VirtualPCIPassthrough.DeviceBackingInfo()
8028 )
kateac1e3792017-04-01 02:16:39 -07008029 nic.device.sriovBacking.physicalFunctionBacking.id = sriov_device.id
8030
8031 devices.append(nic)
8032 vmconf = vim.vm.ConfigSpec(deviceChange=devices)
8033 task = vm_obj.ReconfigVM_Task(vmconf)
sousaedu80135b92021-02-17 15:05:18 +01008034
kateac1e3792017-04-01 02:16:39 -07008035 return task
8036 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008037 self.logger.error(
8038 "Error {} occurred while adding SRIOV adapter in VM: {}".format(
8039 exp, vm_obj
8040 )
8041 )
8042
kateac1e3792017-04-01 02:16:39 -07008043 return None
8044
kateac1e3792017-04-01 02:16:39 -07008045 def create_dvPort_group(self, network_name):
8046 """
sousaedu80135b92021-02-17 15:05:18 +01008047 Method to create disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008048
sousaedu80135b92021-02-17 15:05:18 +01008049 Args:
8050 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008051
sousaedu80135b92021-02-17 15:05:18 +01008052 Returns:
8053 portgroup key
kateac1e3792017-04-01 02:16:39 -07008054 """
8055 try:
sousaedu80135b92021-02-17 15:05:18 +01008056 new_network_name = [network_name, "-", str(uuid.uuid4())]
8057 network_name = "".join(new_network_name)
kateac1e3792017-04-01 02:16:39 -07008058 vcenter_conect, content = self.get_vcenter_content()
8059
sousaedu80135b92021-02-17 15:05:18 +01008060 dv_switch = self.get_obj(
8061 content, [vim.DistributedVirtualSwitch], self.dvs_name
8062 )
8063
kateac1e3792017-04-01 02:16:39 -07008064 if dv_switch:
8065 dv_pg_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
8066 dv_pg_spec.name = network_name
8067
sousaedu80135b92021-02-17 15:05:18 +01008068 dv_pg_spec.type = (
8069 vim.dvs.DistributedVirtualPortgroup.PortgroupType.earlyBinding
8070 )
8071 dv_pg_spec.defaultPortConfig = (
8072 vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
8073 )
8074 dv_pg_spec.defaultPortConfig.securityPolicy = (
8075 vim.dvs.VmwareDistributedVirtualSwitch.SecurityPolicy()
8076 )
8077 dv_pg_spec.defaultPortConfig.securityPolicy.allowPromiscuous = (
8078 vim.BoolPolicy(value=False)
8079 )
8080 dv_pg_spec.defaultPortConfig.securityPolicy.forgedTransmits = (
8081 vim.BoolPolicy(value=False)
8082 )
8083 dv_pg_spec.defaultPortConfig.securityPolicy.macChanges = vim.BoolPolicy(
8084 value=False
8085 )
kateac1e3792017-04-01 02:16:39 -07008086
8087 task = dv_switch.AddDVPortgroup_Task([dv_pg_spec])
8088 self.wait_for_vcenter_task(task, vcenter_conect)
8089
sousaedu80135b92021-02-17 15:05:18 +01008090 dvPort_group = self.get_obj(
8091 content, [vim.dvs.DistributedVirtualPortgroup], network_name
8092 )
8093
kateac1e3792017-04-01 02:16:39 -07008094 if dvPort_group:
sousaedu80135b92021-02-17 15:05:18 +01008095 self.logger.info(
8096 "Created disributed virtaul port group: {}".format(dvPort_group)
8097 )
kateac1e3792017-04-01 02:16:39 -07008098 return dvPort_group.key
8099 else:
sousaedu80135b92021-02-17 15:05:18 +01008100 self.logger.debug(
8101 "No disributed virtual switch found with name {}".format(
8102 network_name
8103 )
8104 )
kateac1e3792017-04-01 02:16:39 -07008105
8106 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008107 self.logger.error(
8108 "Error occurred while creating disributed virtaul port group {}"
8109 " : {}".format(network_name, exp)
8110 )
8111
kateac1e3792017-04-01 02:16:39 -07008112 return None
8113
beierlb22ce2d2019-12-12 12:09:51 -05008114 def reconfig_portgroup(self, content, dvPort_group_name, config_info={}):
kateac1e3792017-04-01 02:16:39 -07008115 """
sousaedu80135b92021-02-17 15:05:18 +01008116 Method to reconfigure disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008117
sousaedu80135b92021-02-17 15:05:18 +01008118 Args:
8119 dvPort_group_name - name of disributed virtual portgroup
8120 content - vCenter content object
8121 config_info - disributed virtual portgroup configuration
kateac1e3792017-04-01 02:16:39 -07008122
sousaedu80135b92021-02-17 15:05:18 +01008123 Returns:
8124 task object
kateac1e3792017-04-01 02:16:39 -07008125 """
8126 try:
8127 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008128
kateac1e3792017-04-01 02:16:39 -07008129 if dvPort_group:
8130 dv_pg_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec()
8131 dv_pg_spec.configVersion = dvPort_group.config.configVersion
sousaedu80135b92021-02-17 15:05:18 +01008132 dv_pg_spec.defaultPortConfig = (
8133 vim.dvs.VmwareDistributedVirtualSwitch.VmwarePortConfigPolicy()
8134 )
8135
kateac1e3792017-04-01 02:16:39 -07008136 if "vlanID" in config_info:
sousaedu80135b92021-02-17 15:05:18 +01008137 dv_pg_spec.defaultPortConfig.vlan = (
8138 vim.dvs.VmwareDistributedVirtualSwitch.VlanIdSpec()
8139 )
8140 dv_pg_spec.defaultPortConfig.vlan.vlanId = config_info.get("vlanID")
kateac1e3792017-04-01 02:16:39 -07008141
8142 task = dvPort_group.ReconfigureDVPortgroup_Task(spec=dv_pg_spec)
sousaedu80135b92021-02-17 15:05:18 +01008143
kateac1e3792017-04-01 02:16:39 -07008144 return task
8145 else:
8146 return None
8147 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008148 self.logger.error(
8149 "Error occurred while reconfiguraing disributed virtaul port group {}"
8150 " : {}".format(dvPort_group_name, exp)
8151 )
8152
kateac1e3792017-04-01 02:16:39 -07008153 return None
8154
beierlb22ce2d2019-12-12 12:09:51 -05008155 def destroy_dvport_group(self, dvPort_group_name):
kateac1e3792017-04-01 02:16:39 -07008156 """
sousaedu80135b92021-02-17 15:05:18 +01008157 Method to destroy disributed virtual portgroup
kateac1e3792017-04-01 02:16:39 -07008158
sousaedu80135b92021-02-17 15:05:18 +01008159 Args:
8160 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008161
sousaedu80135b92021-02-17 15:05:18 +01008162 Returns:
8163 True if portgroup successfully got deleted else false
kateac1e3792017-04-01 02:16:39 -07008164 """
beierlb22ce2d2019-12-12 12:09:51 -05008165 vcenter_conect, _ = self.get_vcenter_content()
sousaedu80135b92021-02-17 15:05:18 +01008166
kateac1e3792017-04-01 02:16:39 -07008167 try:
8168 status = None
8169 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008170
kateac1e3792017-04-01 02:16:39 -07008171 if dvPort_group:
8172 task = dvPort_group.Destroy_Task()
8173 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu80135b92021-02-17 15:05:18 +01008174
kateac1e3792017-04-01 02:16:39 -07008175 return status
8176 except vmodl.MethodFault as exp:
sousaedu80135b92021-02-17 15:05:18 +01008177 self.logger.error(
8178 "Caught vmodl fault {} while deleting disributed virtaul port group {}".format(
8179 exp, dvPort_group_name
8180 )
8181 )
8182
kateac1e3792017-04-01 02:16:39 -07008183 return None
8184
kateac1e3792017-04-01 02:16:39 -07008185 def get_dvport_group(self, dvPort_group_name):
8186 """
8187 Method to get disributed virtual portgroup
8188
8189 Args:
8190 network_name - name of network/portgroup
8191
8192 Returns:
8193 portgroup object
8194 """
beierlb22ce2d2019-12-12 12:09:51 -05008195 _, content = self.get_vcenter_content()
kateac1e3792017-04-01 02:16:39 -07008196 dvPort_group = None
sousaedu80135b92021-02-17 15:05:18 +01008197
kateac1e3792017-04-01 02:16:39 -07008198 try:
sousaedu80135b92021-02-17 15:05:18 +01008199 container = content.viewManager.CreateContainerView(
8200 content.rootFolder, [vim.dvs.DistributedVirtualPortgroup], True
8201 )
8202
kateac1e3792017-04-01 02:16:39 -07008203 for item in container.view:
8204 if item.key == dvPort_group_name:
8205 dvPort_group = item
8206 break
sousaedu80135b92021-02-17 15:05:18 +01008207
kateac1e3792017-04-01 02:16:39 -07008208 return dvPort_group
8209 except vmodl.MethodFault as exp:
sousaedu80135b92021-02-17 15:05:18 +01008210 self.logger.error(
8211 "Caught vmodl fault {} for disributed virtual port group {}".format(
8212 exp, dvPort_group_name
8213 )
8214 )
8215
kateac1e3792017-04-01 02:16:39 -07008216 return None
8217
8218 def get_vlanID_from_dvs_portgr(self, dvPort_group_name):
8219 """
sousaedu80135b92021-02-17 15:05:18 +01008220 Method to get disributed virtual portgroup vlanID
kateac1e3792017-04-01 02:16:39 -07008221
sousaedu80135b92021-02-17 15:05:18 +01008222 Args:
8223 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008224
sousaedu80135b92021-02-17 15:05:18 +01008225 Returns:
8226 vlan ID
kateac1e3792017-04-01 02:16:39 -07008227 """
8228 vlanId = None
sousaedu80135b92021-02-17 15:05:18 +01008229
kateac1e3792017-04-01 02:16:39 -07008230 try:
8231 dvPort_group = self.get_dvport_group(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008232
kateac1e3792017-04-01 02:16:39 -07008233 if dvPort_group:
8234 vlanId = dvPort_group.config.defaultPortConfig.vlan.vlanId
8235 except vmodl.MethodFault as exp:
sousaedu80135b92021-02-17 15:05:18 +01008236 self.logger.error(
8237 "Caught vmodl fault {} for disributed virtaul port group {}".format(
8238 exp, dvPort_group_name
8239 )
8240 )
8241
kateac1e3792017-04-01 02:16:39 -07008242 return vlanId
8243
kateac1e3792017-04-01 02:16:39 -07008244 def configure_vlanID(self, content, vcenter_conect, dvPort_group_name):
8245 """
sousaedu80135b92021-02-17 15:05:18 +01008246 Method to configure vlanID in disributed virtual portgroup vlanID
kateac1e3792017-04-01 02:16:39 -07008247
sousaedu80135b92021-02-17 15:05:18 +01008248 Args:
8249 network_name - name of network/portgroup
kateac1e3792017-04-01 02:16:39 -07008250
sousaedu80135b92021-02-17 15:05:18 +01008251 Returns:
8252 None
kateac1e3792017-04-01 02:16:39 -07008253 """
8254 vlanID = self.get_vlanID_from_dvs_portgr(dvPort_group_name)
sousaedu80135b92021-02-17 15:05:18 +01008255
kateac1e3792017-04-01 02:16:39 -07008256 if vlanID == 0:
beierlb22ce2d2019-12-12 12:09:51 -05008257 # configure vlanID
kateac1e3792017-04-01 02:16:39 -07008258 vlanID = self.genrate_vlanID(dvPort_group_name)
beierlb22ce2d2019-12-12 12:09:51 -05008259 config = {"vlanID": vlanID}
sousaedu80135b92021-02-17 15:05:18 +01008260 task = self.reconfig_portgroup(
8261 content, dvPort_group_name, config_info=config
8262 )
8263
kateac1e3792017-04-01 02:16:39 -07008264 if task:
beierlb22ce2d2019-12-12 12:09:51 -05008265 status = self.wait_for_vcenter_task(task, vcenter_conect)
sousaedu80135b92021-02-17 15:05:18 +01008266
kateac1e3792017-04-01 02:16:39 -07008267 if status:
sousaedu80135b92021-02-17 15:05:18 +01008268 self.logger.info(
8269 "Reconfigured Port group {} for vlan ID {}".format(
8270 dvPort_group_name, vlanID
8271 )
8272 )
kateac1e3792017-04-01 02:16:39 -07008273 else:
sousaedu80135b92021-02-17 15:05:18 +01008274 self.logger.error(
8275 "Fail reconfigure portgroup {} for vlanID{}".format(
8276 dvPort_group_name, vlanID
8277 )
8278 )
kateac1e3792017-04-01 02:16:39 -07008279
8280 def genrate_vlanID(self, network_name):
8281 """
sousaedu80135b92021-02-17 15:05:18 +01008282 Method to get unused vlanID
8283 Args:
8284 network_name - name of network/portgroup
8285 Returns:
8286 vlanID
kateac1e3792017-04-01 02:16:39 -07008287 """
8288 vlan_id = None
8289 used_ids = []
sousaedu80135b92021-02-17 15:05:18 +01008290
8291 if self.config.get("vlanID_range") is None:
8292 raise vimconn.VimConnConflictException(
8293 "You must provide a 'vlanID_range' "
8294 "at config value before creating sriov network with vlan tag"
8295 )
8296
kateac1e3792017-04-01 02:16:39 -07008297 if "used_vlanIDs" not in self.persistent_info:
sousaedu80135b92021-02-17 15:05:18 +01008298 self.persistent_info["used_vlanIDs"] = {}
kateac1e3792017-04-01 02:16:39 -07008299 else:
tierno7d782ef2019-10-04 12:56:31 +00008300 used_ids = list(self.persistent_info["used_vlanIDs"].values())
kateac1e3792017-04-01 02:16:39 -07008301
sousaedu80135b92021-02-17 15:05:18 +01008302 for vlanID_range in self.config.get("vlanID_range"):
tierno1b856002019-11-07 16:28:54 +00008303 start_vlanid, end_vlanid = vlanID_range.split("-")
sousaedu80135b92021-02-17 15:05:18 +01008304
kateac1e3792017-04-01 02:16:39 -07008305 if start_vlanid > end_vlanid:
sousaedu80135b92021-02-17 15:05:18 +01008306 raise vimconn.VimConnConflictException(
8307 "Invalid vlan ID range {}".format(vlanID_range)
8308 )
kateac1e3792017-04-01 02:16:39 -07008309
beierlb22ce2d2019-12-12 12:09:51 -05008310 for vid in range(int(start_vlanid), int(end_vlanid) + 1):
8311 if vid not in used_ids:
8312 vlan_id = vid
kateac1e3792017-04-01 02:16:39 -07008313 self.persistent_info["used_vlanIDs"][network_name] = vlan_id
8314 return vlan_id
sousaedu80135b92021-02-17 15:05:18 +01008315
kateac1e3792017-04-01 02:16:39 -07008316 if vlan_id is None:
tierno72774862020-05-04 11:44:15 +00008317 raise vimconn.VimConnConflictException("All Vlan IDs are in use")
kateac1e3792017-04-01 02:16:39 -07008318
kateac1e3792017-04-01 02:16:39 -07008319 def get_obj(self, content, vimtype, name):
8320 """
sousaedu80135b92021-02-17 15:05:18 +01008321 Get the vsphere object associated with a given text name
kateac1e3792017-04-01 02:16:39 -07008322 """
8323 obj = None
sousaedu80135b92021-02-17 15:05:18 +01008324 container = content.viewManager.CreateContainerView(
8325 content.rootFolder, vimtype, True
8326 )
8327
kateac1e3792017-04-01 02:16:39 -07008328 for item in container.view:
8329 if item.name == name:
8330 obj = item
8331 break
sousaedu80135b92021-02-17 15:05:18 +01008332
kateac1e3792017-04-01 02:16:39 -07008333 return obj
8334
kasar0c007d62017-05-19 03:13:57 -07008335 def insert_media_to_vm(self, vapp, image_id):
8336 """
8337 Method to insert media CD-ROM (ISO image) from catalog to vm.
8338 vapp - vapp object to get vm id
8339 Image_id - image id for cdrom to be inerted to vm
8340 """
8341 # create connection object
8342 vca = self.connect()
8343 try:
8344 # fetching catalog details
kasarc5bf2932018-03-09 04:15:22 -08008345 rest_url = "{}/api/catalog/{}".format(self.url, image_id)
sousaedu80135b92021-02-17 15:05:18 +01008346
kasarc5bf2932018-03-09 04:15:22 -08008347 if vca._session:
sousaedu80135b92021-02-17 15:05:18 +01008348 headers = {
8349 "Accept": "application/*+xml;version=" + API_VERSION,
8350 "x-vcloud-authorization": vca._session.headers[
8351 "x-vcloud-authorization"
8352 ],
8353 }
8354 response = self.perform_request(
8355 req_type="GET", url=rest_url, headers=headers
8356 )
kasar0c007d62017-05-19 03:13:57 -07008357
8358 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01008359 self.logger.error(
8360 "REST call {} failed reason : {}"
8361 "status code : {}".format(
8362 rest_url, response.text, response.status_code
8363 )
8364 )
8365
8366 raise vimconn.VimConnException(
8367 "insert_media_to_vm(): Failed to get " "catalog details"
8368 )
8369
kasar0c007d62017-05-19 03:13:57 -07008370 # searching iso name and id
beierl26fec002019-12-06 17:06:40 -05008371 iso_name, media_id = self.get_media_details(vca, response.text)
kasar0c007d62017-05-19 03:13:57 -07008372
8373 if iso_name and media_id:
beierlb22ce2d2019-12-12 12:09:51 -05008374 data = """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
kasar0c007d62017-05-19 03:13:57 -07008375 <ns6:MediaInsertOrEjectParams
beierl26fec002019-12-06 17:06:40 -05008376 xmlns="http://www.vmware.com/vcloud/versions" xmlns:ns2="http://schemas.dmtf.org/ovf/envelope/1"
8377 xmlns:ns3="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData"
8378 xmlns:ns4="http://schemas.dmtf.org/wbem/wscim/1/common"
8379 xmlns:ns5="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData"
8380 xmlns:ns6="http://www.vmware.com/vcloud/v1.5"
8381 xmlns:ns7="http://www.vmware.com/schema/ovf"
8382 xmlns:ns8="http://schemas.dmtf.org/ovf/environment/1"
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008383 xmlns:ns9="http://www.vmware.com/vcloud/extension/v1.5">
kasar0c007d62017-05-19 03:13:57 -07008384 <ns6:Media
8385 type="application/vnd.vmware.vcloud.media+xml"
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008386 name="{}"
kasar0c007d62017-05-19 03:13:57 -07008387 id="urn:vcloud:media:{}"
8388 href="https://{}/api/media/{}"/>
sousaedu80135b92021-02-17 15:05:18 +01008389 </ns6:MediaInsertOrEjectParams>""".format(
8390 iso_name, media_id, self.url, media_id
8391 )
kasar0c007d62017-05-19 03:13:57 -07008392
kasarc5bf2932018-03-09 04:15:22 -08008393 for vms in vapp.get_all_vms():
sousaedu80135b92021-02-17 15:05:18 +01008394 vm_id = vms.get("id").split(":")[-1]
kasar0c007d62017-05-19 03:13:57 -07008395
sousaedu80135b92021-02-17 15:05:18 +01008396 headers[
8397 "Content-Type"
8398 ] = "application/vnd.vmware.vcloud.mediaInsertOrEjectParams+xml"
8399 rest_url = "{}/api/vApp/vm-{}/media/action/insertMedia".format(
8400 self.url, vm_id
8401 )
kasar0c007d62017-05-19 03:13:57 -07008402
sousaedu80135b92021-02-17 15:05:18 +01008403 response = self.perform_request(
8404 req_type="POST", url=rest_url, data=data, headers=headers
8405 )
kasar0c007d62017-05-19 03:13:57 -07008406
8407 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01008408 error_msg = (
8409 "insert_media_to_vm() : Failed to insert CD-ROM to vm. Reason {}. "
8410 "Status code {}".format(response.text, response.status_code)
8411 )
Ananda Baitharu319c26f2019-03-05 17:34:31 +00008412 self.logger.error(error_msg)
sousaedu80135b92021-02-17 15:05:18 +01008413
tierno72774862020-05-04 11:44:15 +00008414 raise vimconn.VimConnException(error_msg)
kasar0c007d62017-05-19 03:13:57 -07008415 else:
beierl26fec002019-12-06 17:06:40 -05008416 task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01008417 result = self.client.get_task_monitor().wait_for_success(
8418 task=task
8419 )
kasarc5bf2932018-03-09 04:15:22 -08008420
sousaedu80135b92021-02-17 15:05:18 +01008421 if result.get("status") == "success":
8422 self.logger.info(
8423 "insert_media_to_vm(): Sucessfully inserted media ISO"
8424 " image to vm {}".format(vm_id)
8425 )
kasar0c007d62017-05-19 03:13:57 -07008426 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008427 self.logger.error(
8428 "insert_media_to_vm() : exception occurred "
8429 "while inserting media CD-ROM"
8430 )
8431
tierno72774862020-05-04 11:44:15 +00008432 raise vimconn.VimConnException(message=exp)
kasar0c007d62017-05-19 03:13:57 -07008433
kasar0c007d62017-05-19 03:13:57 -07008434 def get_media_details(self, vca, content):
8435 """
8436 Method to get catalog item details
8437 vca - connection object
8438 content - Catalog details
8439 Return - Media name, media id
8440 """
8441 cataloghref_list = []
8442 try:
8443 if content:
8444 vm_list_xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01008445
kasar0c007d62017-05-19 03:13:57 -07008446 for child in vm_list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01008447 if "CatalogItem" in child.tag:
8448 cataloghref_list.append(child.attrib.get("href"))
8449
kasar0c007d62017-05-19 03:13:57 -07008450 if cataloghref_list is not None:
8451 for href in cataloghref_list:
8452 if href:
sousaedu80135b92021-02-17 15:05:18 +01008453 headers = {
8454 "Accept": "application/*+xml;version=" + API_VERSION,
8455 "x-vcloud-authorization": vca._session.headers[
8456 "x-vcloud-authorization"
8457 ],
8458 }
8459 response = self.perform_request(
8460 req_type="GET", url=href, headers=headers
8461 )
8462
kasar0c007d62017-05-19 03:13:57 -07008463 if response.status_code != 200:
sousaedu80135b92021-02-17 15:05:18 +01008464 self.logger.error(
8465 "REST call {} failed reason : {}"
8466 "status code : {}".format(
8467 href, response.text, response.status_code
8468 )
8469 )
8470
8471 raise vimconn.VimConnException(
8472 "get_media_details : Failed to get "
8473 "catalogitem details"
8474 )
8475
beierl26fec002019-12-06 17:06:40 -05008476 list_xmlroot = XmlElementTree.fromstring(response.text)
sousaedu80135b92021-02-17 15:05:18 +01008477
kasar0c007d62017-05-19 03:13:57 -07008478 for child in list_xmlroot.iter():
sousaedu80135b92021-02-17 15:05:18 +01008479 if "Entity" in child.tag:
8480 if "media" in child.attrib.get("href"):
8481 name = child.attrib.get("name")
8482 media_id = (
8483 child.attrib.get("href").split("/").pop()
8484 )
8485
beierlb22ce2d2019-12-12 12:09:51 -05008486 return name, media_id
kasar0c007d62017-05-19 03:13:57 -07008487 else:
8488 self.logger.debug("Media name and id not found")
sousaedu80135b92021-02-17 15:05:18 +01008489
beierlb22ce2d2019-12-12 12:09:51 -05008490 return False, False
kasar0c007d62017-05-19 03:13:57 -07008491 except Exception as exp:
sousaedu80135b92021-02-17 15:05:18 +01008492 self.logger.error(
8493 "get_media_details : exception occurred " "getting media details"
8494 )
8495
tierno72774862020-05-04 11:44:15 +00008496 raise vimconn.VimConnException(message=exp)
kasar0c007d62017-05-19 03:13:57 -07008497
kated47ad5f2017-08-03 02:16:13 -07008498 def retry_rest(self, method, url, add_headers=None, data=None):
sousaedu80135b92021-02-17 15:05:18 +01008499 """Method to get Token & retry respective REST request
8500 Args:
8501 api - REST API - Can be one of 'GET' or 'PUT' or 'POST'
8502 url - request url to be used
8503 add_headers - Additional headers (optional)
8504 data - Request payload data to be passed in request
8505 Returns:
8506 response - Response of request
bhangare1a0b97c2017-06-21 02:20:15 -07008507 """
8508 response = None
8509
beierlb22ce2d2019-12-12 12:09:51 -05008510 # Get token
bhangare1a0b97c2017-06-21 02:20:15 -07008511 self.get_token()
8512
kasarc5bf2932018-03-09 04:15:22 -08008513 if self.client._session:
sousaedu80135b92021-02-17 15:05:18 +01008514 headers = {
8515 "Accept": "application/*+xml;version=" + API_VERSION,
8516 "x-vcloud-authorization": self.client._session.headers[
8517 "x-vcloud-authorization"
8518 ],
8519 }
bhangare1a0b97c2017-06-21 02:20:15 -07008520
8521 if add_headers:
8522 headers.update(add_headers)
8523
sousaedu80135b92021-02-17 15:05:18 +01008524 if method == "GET":
8525 response = self.perform_request(req_type="GET", url=url, headers=headers)
8526 elif method == "PUT":
8527 response = self.perform_request(
8528 req_type="PUT", url=url, headers=headers, data=data
8529 )
8530 elif method == "POST":
8531 response = self.perform_request(
8532 req_type="POST", url=url, headers=headers, data=data
8533 )
8534 elif method == "DELETE":
8535 response = self.perform_request(req_type="DELETE", url=url, headers=headers)
8536
kated47ad5f2017-08-03 02:16:13 -07008537 return response
8538
bhangare1a0b97c2017-06-21 02:20:15 -07008539 def get_token(self):
sousaedu80135b92021-02-17 15:05:18 +01008540 """Generate a new token if expired
bhangare1a0b97c2017-06-21 02:20:15 -07008541
sousaedu80135b92021-02-17 15:05:18 +01008542 Returns:
8543 The return client object that letter can be used to connect to vCloud director as admin for VDC
bhangare1a0b97c2017-06-21 02:20:15 -07008544 """
beierl26fec002019-12-06 17:06:40 -05008545 self.client = self.connect()
bhangare1a0b97c2017-06-21 02:20:15 -07008546
8547 def get_vdc_details(self):
sousaedu80135b92021-02-17 15:05:18 +01008548 """Get VDC details using pyVcloud Lib
bhangare1a0b97c2017-06-21 02:20:15 -07008549
sousaedu80135b92021-02-17 15:05:18 +01008550 Returns org and vdc object
bhangare1a0b97c2017-06-21 02:20:15 -07008551 """
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008552 vdc = None
sousaedu80135b92021-02-17 15:05:18 +01008553
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008554 try:
8555 org = Org(self.client, resource=self.client.get_org())
8556 vdc = org.get_vdc(self.tenant_name)
8557 except Exception as e:
8558 # pyvcloud not giving a specific exception, Refresh nevertheless
8559 self.logger.debug("Received exception {}, refreshing token ".format(str(e)))
bhangare1a0b97c2017-06-21 02:20:15 -07008560
beierlb22ce2d2019-12-12 12:09:51 -05008561 # Retry once, if failed by refreshing token
bhangare1a0b97c2017-06-21 02:20:15 -07008562 if vdc is None:
8563 self.get_token()
Ravi Chamartyb7ff3552018-10-30 19:51:23 +00008564 org = Org(self.client, resource=self.client.get_org())
kasarc5bf2932018-03-09 04:15:22 -08008565 vdc = org.get_vdc(self.tenant_name)
bhangare1a0b97c2017-06-21 02:20:15 -07008566
kasarc5bf2932018-03-09 04:15:22 -08008567 return org, vdc
8568
kasarc5bf2932018-03-09 04:15:22 -08008569 def perform_request(self, req_type, url, headers=None, data=None):
8570 """Perform the POST/PUT/GET/DELETE request."""
beierlb22ce2d2019-12-12 12:09:51 -05008571 # Log REST request details
kasarc5bf2932018-03-09 04:15:22 -08008572 self.log_request(req_type, url=url, headers=headers, data=data)
8573 # perform request and return its result
sousaedu80135b92021-02-17 15:05:18 +01008574
8575 if req_type == "GET":
8576 response = requests.get(url=url, headers=headers, verify=False)
8577 elif req_type == "PUT":
8578 response = requests.put(url=url, headers=headers, data=data, verify=False)
8579 elif req_type == "POST":
8580 response = requests.post(url=url, headers=headers, data=data, verify=False)
8581 elif req_type == "DELETE":
8582 response = requests.delete(url=url, headers=headers, verify=False)
8583
beierlb22ce2d2019-12-12 12:09:51 -05008584 # Log the REST response
kasarc5bf2932018-03-09 04:15:22 -08008585 self.log_response(response)
8586
8587 return response
8588
kasarc5bf2932018-03-09 04:15:22 -08008589 def log_request(self, req_type, url=None, headers=None, data=None):
8590 """Logs REST request details"""
8591
8592 if req_type is not None:
8593 self.logger.debug("Request type: {}".format(req_type))
8594
8595 if url is not None:
8596 self.logger.debug("Request url: {}".format(url))
8597
8598 if headers is not None:
8599 for header in headers:
sousaedu80135b92021-02-17 15:05:18 +01008600 self.logger.debug(
8601 "Request header: {}: {}".format(header, headers[header])
8602 )
kasarc5bf2932018-03-09 04:15:22 -08008603
8604 if data is not None:
8605 self.logger.debug("Request data: {}".format(data))
8606
kasarc5bf2932018-03-09 04:15:22 -08008607 def log_response(self, response):
8608 """Logs REST response details"""
8609
8610 self.logger.debug("Response status code: {} ".format(response.status_code))
8611
kasarc5bf2932018-03-09 04:15:22 -08008612 def get_task_from_response(self, content):
8613 """
beierl26fec002019-12-06 17:06:40 -05008614 content - API response.text(response.text)
sbhangarea8e5b782018-06-21 02:10:03 -07008615 return task object
kasarc5bf2932018-03-09 04:15:22 -08008616 """
8617 xmlroot = XmlElementTree.fromstring(content)
sousaedu80135b92021-02-17 15:05:18 +01008618
8619 if xmlroot.tag.split("}")[1] == "Task":
kasarc5bf2932018-03-09 04:15:22 -08008620 return xmlroot
sbhangarea8e5b782018-06-21 02:10:03 -07008621 else:
kasarc5bf2932018-03-09 04:15:22 -08008622 for ele in xmlroot:
8623 if ele.tag.split("}")[1] == "Tasks":
8624 task = ele[0]
sbhangarea8e5b782018-06-21 02:10:03 -07008625 break
sousaedu80135b92021-02-17 15:05:18 +01008626
kasarc5bf2932018-03-09 04:15:22 -08008627 return task
8628
beierlb22ce2d2019-12-12 12:09:51 -05008629 def power_on_vapp(self, vapp_id, vapp_name):
kasarc5bf2932018-03-09 04:15:22 -08008630 """
8631 vapp_id - vApp uuid
8632 vapp_name - vAapp name
sbhangarea8e5b782018-06-21 02:10:03 -07008633 return - Task object
kasarc5bf2932018-03-09 04:15:22 -08008634 """
sousaedu80135b92021-02-17 15:05:18 +01008635 headers = {
8636 "Accept": "application/*+xml;version=" + API_VERSION,
8637 "x-vcloud-authorization": self.client._session.headers[
8638 "x-vcloud-authorization"
8639 ],
8640 }
sbhangarea8e5b782018-06-21 02:10:03 -07008641
sousaedu80135b92021-02-17 15:05:18 +01008642 poweron_href = "{}/api/vApp/vapp-{}/power/action/powerOn".format(
8643 self.url, vapp_id
8644 )
8645 response = self.perform_request(
8646 req_type="POST", url=poweron_href, headers=headers
8647 )
kasarc5bf2932018-03-09 04:15:22 -08008648
8649 if response.status_code != 202:
sousaedu80135b92021-02-17 15:05:18 +01008650 self.logger.error(
8651 "REST call {} failed reason : {}"
8652 "status code : {} ".format(
8653 poweron_href, response.text, response.status_code
8654 )
8655 )
8656
8657 raise vimconn.VimConnException(
8658 "power_on_vapp() : Failed to power on " "vApp {}".format(vapp_name)
8659 )
kasarc5bf2932018-03-09 04:15:22 -08008660 else:
beierl26fec002019-12-06 17:06:40 -05008661 poweron_task = self.get_task_from_response(response.text)
sousaedu80135b92021-02-17 15:05:18 +01008662
kasarc5bf2932018-03-09 04:15:22 -08008663 return poweron_task